更新了项目文件
This commit is contained in:
@@ -44,7 +44,7 @@ def call_bailian_app(request):
|
||||
prompt = data.get("prompt")
|
||||
x = request.headers.get('X', '')
|
||||
t = request.headers.get('T', '')
|
||||
increment = -1
|
||||
increment = -0
|
||||
function_type = 'call_bailian_app'
|
||||
result = update_usage_count(openid, increment, function_type)
|
||||
if decrypt_param(x, t):
|
||||
|
||||
299
MyApi/app_login_pay.py
Executable file
299
MyApi/app_login_pay.py
Executable file
@@ -0,0 +1,299 @@
|
||||
import base64
|
||||
import json
|
||||
import string
|
||||
from datetime import datetime
|
||||
from decimal import Decimal
|
||||
import requests
|
||||
import time
|
||||
import random
|
||||
from xml.etree import ElementTree as ET
|
||||
from Crypto.Hash import SHA256
|
||||
from Crypto.PublicKey import RSA
|
||||
from Crypto.Signature import pkcs1_15
|
||||
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
|
||||
from django.http import JsonResponse, HttpResponse, HttpResponseRedirect
|
||||
from django.views.decorators.csrf import csrf_exempt
|
||||
from django.conf import settings
|
||||
from .models import TransactionLog, MembershipType, User
|
||||
from .API_Log import get_logger
|
||||
|
||||
log_file = '支付日志demo.log'
|
||||
logger = get_logger('支付日志demo', log_file, when='midnight', backup_count=7)
|
||||
|
||||
def get_sign(sign_str, key_path):
|
||||
rsa_key = RSA.importKey(open(key_path).read())
|
||||
signer = pkcs1_15.new(rsa_key)
|
||||
digest = SHA256.new(sign_str.encode('utf8'))
|
||||
sign = base64.b64encode(signer.sign(digest)).decode('utf-8')
|
||||
return sign
|
||||
|
||||
def decrypt(nonce, ciphertext, associated_data, api_key):
|
||||
key_bytes = str.encode(api_key)
|
||||
nonce_bytes = str.encode(nonce)
|
||||
ad_bytes = str.encode(associated_data)
|
||||
data = base64.b64decode(ciphertext)
|
||||
aesgcm = AESGCM(key_bytes)
|
||||
return aesgcm.decrypt(nonce_bytes, data, ad_bytes)
|
||||
|
||||
def update_user_membership_or_quota(openid, membership_type):
|
||||
current_time = int(time.time())
|
||||
try:
|
||||
user = User.objects.get(openid=openid)
|
||||
if membership_type.is_quota:
|
||||
user.coins += membership_type.coins
|
||||
logger.info(f'用户 {user.id} (openid: {openid}) 充值额度卡,增加金币 {membership_type.coins}')
|
||||
else:
|
||||
user.is_member = True
|
||||
if user.member_start_time is None:
|
||||
user.member_start_time = current_time
|
||||
elif user.member_end_time is None or user.member_end_time < current_time:
|
||||
user.member_start_time = current_time
|
||||
if user.member_end_time is None or user.member_end_time < current_time:
|
||||
user.member_end_time = current_time + membership_type.duration_days * 24 * 3600
|
||||
else:
|
||||
user.member_end_time += membership_type.duration_days * 24 * 3600
|
||||
user.coins += membership_type.coins
|
||||
user.save()
|
||||
return True
|
||||
except User.DoesNotExist:
|
||||
logger.error(f'用户 {openid} 不存在')
|
||||
return False
|
||||
except Exception as e:
|
||||
logger.error(f'更新会员或额度充值时出错: {str(e)}')
|
||||
return False
|
||||
|
||||
@csrf_exempt
|
||||
def wx_pay(request):
|
||||
request_data = json.loads(request.body)
|
||||
logger.info(f"生成订单{request_data}")
|
||||
type = request_data.get('type', 'default')
|
||||
wx_price = request_data['total_fee']
|
||||
openid = request_data['openid']
|
||||
uuid = request_data.get('uuid')
|
||||
transaction_type = request_data['transaction_type']
|
||||
up_time = datetime.now()
|
||||
|
||||
membership_types = MembershipType.objects.all()
|
||||
body_map = {membership_type.type: membership_type.title for membership_type in membership_types}
|
||||
body_description = body_map.get(type)
|
||||
|
||||
transactionNo = str(up_time).replace('.', '').replace('-', '').replace(':', '').replace(' ', '')
|
||||
|
||||
membership_type = MembershipType.objects.get(type=type)
|
||||
price = membership_type.price
|
||||
newTransaction = TransactionLog.objects.create(
|
||||
transaction_no=transactionNo,
|
||||
transaction_status='pending',
|
||||
user_openid=openid,
|
||||
transaction_type=transaction_type,
|
||||
transaction_amount=price,
|
||||
remark=type,
|
||||
created_at=up_time
|
||||
)
|
||||
|
||||
logger.info("生成订单:")
|
||||
logger.info(f"商户订单号:{transactionNo}")
|
||||
logger.info(f"用户OpenID:{openid}")
|
||||
logger.info(f"用户UUID{uuid}")
|
||||
logger.info(f"type:{type}")
|
||||
logger.info(f"transaction_type:{transaction_type}")
|
||||
logger.info(f"成功时间:{up_time}")
|
||||
logger.info(f"金额(前端):{wx_price}")
|
||||
logger.info(f"金额(后端):{price}")
|
||||
|
||||
url = 'https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi'
|
||||
body = {
|
||||
"appid": settings.LOGIN_APP_ID,
|
||||
"mchid": settings.LOGIN_WX_MCH_ID,
|
||||
"description": body_description,
|
||||
"out_trade_no": transactionNo,
|
||||
"notify_url": settings.LOGIN_WX_NOTIFY_URL,
|
||||
"amount": {"total": int(float(price) * 100), "currency": "CNY"},
|
||||
"payer": {"openid": openid},
|
||||
"attach": json.dumps({"type": type, "transaction_type": transaction_type,"uuid":uuid})
|
||||
}
|
||||
data = json.dumps(body)
|
||||
logger.info(f'生成支付请求体: {body}')
|
||||
random_str = ''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(32))
|
||||
time_stamps = str(int(time.time()))
|
||||
sign_str = f"POST\n/v3/pay/transactions/jsapi\n{time_stamps}\n{random_str}\n{data}\n"
|
||||
sign = get_sign(sign_str, settings.LOGIN_WX_KEY_PATH)
|
||||
|
||||
headers = {
|
||||
'Content-Type': 'application/json',
|
||||
'Accept': 'application/json',
|
||||
'User-Agent': '*/*',
|
||||
'Authorization': 'WECHATPAY2-SHA256-RSA2048 ' + f'mchid="{settings.LOGIN_WX_MCH_ID}",nonce_str="{random_str}",signature="{sign}",timestamp="{time_stamps}",serial_no="{settings.LOGIN_WX_SERIAL_NO}"',
|
||||
'Wechatpay-Serial': '66DB35F836EFD4CBEC66F3815D283A2892310324'
|
||||
}
|
||||
logger.info(f'生成请求头: {headers}')
|
||||
response = requests.post(url, data=data, headers=headers)
|
||||
response_dict = response.json()
|
||||
logger.info(f'响应头: {response.headers}')
|
||||
logger.info(f'响应体: {response_dict}')
|
||||
if response.status_code == 200:
|
||||
res = {
|
||||
'appid': settings.LOGIN_APP_ID,
|
||||
'partnerid': settings.LOGIN_WX_MCH_ID,
|
||||
'prepayid': response_dict['prepay_id'],
|
||||
'package': f'prepay_id={response_dict["prepay_id"]}',
|
||||
'nonceStr': random_str,
|
||||
'timeStamp': time_stamps,
|
||||
'paySign': get_sign(
|
||||
f"{settings.LOGIN_APP_ID}\n{time_stamps}\n{random_str}\n{'prepay_id=' + response_dict['prepay_id']}\n",
|
||||
settings.LOGIN_WX_KEY_PATH
|
||||
),
|
||||
'signType': 'MD5'
|
||||
}
|
||||
logger.info(f'签名有效: {res}')
|
||||
return HttpResponse(json.dumps(res), content_type='application/json')
|
||||
else:
|
||||
logger.error(f"支付请求失败:{response_dict}")
|
||||
return HttpResponse(json.dumps({'msg': "支付失败"}), content_type='application/json', status=400)
|
||||
|
||||
@csrf_exempt
|
||||
def wx_pay_notify(request):
|
||||
try:
|
||||
# 确保请求体被正确解码
|
||||
request_body = request.body.decode('utf-8')
|
||||
webData = json.loads(request_body)
|
||||
logger.info(f'回调返回信息:{webData}')
|
||||
|
||||
# 提取加密数据
|
||||
resource = webData.get('resource', {})
|
||||
ciphertext = resource.get('ciphertext', '')
|
||||
nonce = resource.get('nonce', '')
|
||||
associated_data = resource.get('associated_data', '')
|
||||
|
||||
if not ciphertext or not nonce or not associated_data:
|
||||
logger.error('回调数据不完整')
|
||||
return HttpResponse(json.dumps({"code": "FAIL", "message": "回调数据不完整"}), content_type='application/json')
|
||||
|
||||
# 解密回调数据
|
||||
callback_data = decrypt(nonce, ciphertext, associated_data, settings.LOGIN_V3_KEY)
|
||||
callback_data_str = callback_data.decode('utf-8') # 将字节对象解码为字符串
|
||||
callback_data = json.loads(callback_data_str) # 将字符串解析为字典对象
|
||||
logger.info(f'解密后的回调数据:{callback_data}')
|
||||
|
||||
# 提取必要信息
|
||||
mchid = callback_data.get('mchid', '')
|
||||
appid = callback_data.get('appid', '')
|
||||
out_trade_no = callback_data.get('out_trade_no', '')
|
||||
transaction_id = callback_data.get('transaction_id', '')
|
||||
trade_state = callback_data.get('trade_state', '')
|
||||
payer = callback_data.get('payer', {})
|
||||
openid = payer.get('openid', '')
|
||||
attach = callback_data.get('attach', '').replace("'", "\"")
|
||||
attach = json.loads(attach) if attach else {}
|
||||
type = attach.get('type', '')
|
||||
transaction_type = attach.get('transaction_type', '')
|
||||
uuid = attach.get('uuid', '')
|
||||
success_time_str = callback_data.get('success_time', '')
|
||||
amount = callback_data.get('amount', {})
|
||||
amount_total = amount.get('total', 0)
|
||||
success_time = datetime.strptime(success_time_str, "%Y-%m-%dT%H:%M:%S%z") if success_time_str else None
|
||||
|
||||
logger.info("交易结果:")
|
||||
logger.info(f"商户号:{mchid}")
|
||||
logger.info(f"AppID:{appid}")
|
||||
logger.info(f"商户订单号:{out_trade_no}")
|
||||
logger.info(f"微信订单号:{transaction_id}")
|
||||
logger.info(f"交易状态:{trade_state}")
|
||||
logger.info(f"用户OpenID:{openid}")
|
||||
logger.info(f"type:{type}")
|
||||
logger.info(f"transaction_type:{transaction_type}")
|
||||
logger.info(f"成功时间:{success_time}")
|
||||
logger.info(f"金额(分):{amount_total}")
|
||||
|
||||
# 获取交易记录、会员类型和用户
|
||||
try:
|
||||
transaction_log = TransactionLog.objects.get(transaction_no=out_trade_no)
|
||||
except TransactionLog.DoesNotExist:
|
||||
logger.error('交易记录不存在')
|
||||
return HttpResponse(json.dumps({"code": "FAIL", "message": "交易记录不存在"}), content_type='application/json')
|
||||
|
||||
try:
|
||||
membership_type = MembershipType.objects.get(type=type)
|
||||
except MembershipType.DoesNotExist:
|
||||
logger.error('会员类型不存在')
|
||||
return HttpResponse(json.dumps({"code": "FAIL", "message": "会员类型不存在"}), content_type='application/json')
|
||||
|
||||
try:
|
||||
user = User.objects.get(nickname=uuid)
|
||||
except User.DoesNotExist:
|
||||
logger.error('用户不存在')
|
||||
return HttpResponse(json.dumps({"code": "FAIL", "message": "用户不存在"}), content_type='application/json')
|
||||
|
||||
# 验证交易信息
|
||||
if (transaction_log.user_openid == openid) and (transaction_log.transaction_amount * 100 == amount_total) and (
|
||||
membership_type.price * 100 == amount_total):
|
||||
transaction_log.transaction_status = 'completed'
|
||||
transaction_log.save()
|
||||
logger.info(f'交易记录更新成功:{transaction_log}')
|
||||
|
||||
# 更新用户会员或配额
|
||||
success = update_user_membership_or_quota(user.openid, membership_type)
|
||||
|
||||
# 如果用户有邀请人,则处理返利
|
||||
if user.inviter_nickname:
|
||||
inviter = User.objects.filter(nickname=user.inviter_nickname).first()
|
||||
if inviter:
|
||||
rebate_amount = round(Decimal(amount_total) * Decimal(0.35) / Decimal(100), 2)
|
||||
inviter.balance += rebate_amount
|
||||
inviter.save()
|
||||
logger.info(f'邀请人{inviter.nickname}返利{rebate_amount}元成功')
|
||||
|
||||
return HttpResponse(json.dumps({"code": "SUCCESS", "message": "成功"}))
|
||||
else:
|
||||
logger.warning('回调数据与订单记录不一致')
|
||||
return HttpResponse(json.dumps({"code": "FAIL", "message": "回调数据与订单记录不一致"}))
|
||||
except Exception as e:
|
||||
logger.error(f'处理回调时出错:{str(e)}')
|
||||
return HttpResponse(json.dumps({"code": "FAIL", "message": "处理回调时出错"}))
|
||||
|
||||
|
||||
def wx_resource(nonce, ciphertext, associated_data):
|
||||
key_bytes = str.encode(settings.LOGIN_V3_KEY)
|
||||
nonce_bytes = str.encode(nonce)
|
||||
ad_bytes = str.encode(associated_data)
|
||||
data = base64.b64decode(ciphertext)
|
||||
aesgcm = AESGCM(key_bytes)
|
||||
plaintext = aesgcm.decrypt(nonce_bytes, data, ad_bytes)
|
||||
plaintext_str = bytes.decode(plaintext)
|
||||
return eval(plaintext_str)
|
||||
|
||||
|
||||
def wechat_login(request):
|
||||
redirect_uri = settings.LOGIN_REDIRECT_URI
|
||||
appid = settings.LOGIN_APP_ID
|
||||
state = 'random_string' # 可以随机生成字符串,保持安全性
|
||||
wechat_auth_url = (
|
||||
f"https://open.weixin.qq.com/connect/oauth2/authorize?"
|
||||
f"appid={appid}&redirect_uri={redirect_uri}&response_type=code&scope=snsapi_base&state={state}#wechat_redirect"
|
||||
)
|
||||
return HttpResponseRedirect(wechat_auth_url)
|
||||
|
||||
def wechat_callback(request):
|
||||
code = request.GET.get('code')
|
||||
if not code:
|
||||
return JsonResponse({'error': '缺少code参数'}, status=400)
|
||||
|
||||
appid = settings.LOGIN_APP_ID
|
||||
secret = settings.LOGIN_APP_SECRET
|
||||
|
||||
token_url = (
|
||||
f"https://api.weixin.qq.com/sns/oauth2/access_token?"
|
||||
f"appid={appid}&secret={secret}&code={code}&grant_type=authorization_code"
|
||||
)
|
||||
response = requests.get(token_url)
|
||||
token_info = response.json()
|
||||
|
||||
if 'errcode' in token_info:
|
||||
logger.error(f"获取access_token失败: {token_info}")
|
||||
return JsonResponse({'error': '获取access_token失败'}, status=400)
|
||||
|
||||
access_token = token_info['access_token']
|
||||
openid = token_info['openid']
|
||||
frontend_url = settings.LOGIN_WEB_URI # 替换为您的前端地址
|
||||
redirect_url = f"{frontend_url}?openid={openid}"
|
||||
return HttpResponseRedirect(redirect_url)
|
||||
@@ -28,7 +28,7 @@ class MembershipType(models.Model):
|
||||
type = models.CharField(max_length=50, unique=True, verbose_name="卡类型") # 卡类型,如天卡、周卡等 coins 额度卡
|
||||
title = models.CharField(max_length=100, verbose_name="标题") # 卡的标题
|
||||
description = models.TextField(verbose_name="描述") # 卡的描述
|
||||
price = models.DecimalField(max_digits=10, decimal_places=2, verbose_name="价格") # 卡的价格
|
||||
price = models.DecimalField(max_digits=5, decimal_places=2, verbose_name="价格") # 卡的价格
|
||||
duration_days = models.IntegerField(verbose_name="有效天数") # 卡的有效期,以天为单位
|
||||
coins = models.IntegerField(default=0, verbose_name="赠送金币数量") # 赠送金币的数量
|
||||
is_quota = models.BooleanField(default=False, verbose_name="是否为额度充值") # 是否为额度充值
|
||||
@@ -59,7 +59,7 @@ class User(models.Model):
|
||||
member_end_time = models.BigIntegerField(blank=True, null=True) # 存储会员到期时间的时间戳
|
||||
is_active = models.BooleanField(default=True) # 状态,启用/禁用,默认启用
|
||||
usage_count = models.IntegerField(default=0, blank=True, null=True) # 用户使用次数
|
||||
coins = models.IntegerField(default=30, verbose_name='金币数量') # 用户金币数量
|
||||
coins = models.IntegerField(default=10, verbose_name='金币数量') # 用户金币数量
|
||||
balance = models.DecimalField(max_digits=10, decimal_places=2, default=0.00, verbose_name='用户余额') # 用户余额
|
||||
inviter_nickname = models.CharField(max_length=150, blank=True, null=True, verbose_name='邀请人昵称') # 用户邀请人昵称
|
||||
invitees_count = models.IntegerField(default=0, verbose_name='邀请人数量') # 邀请人数量
|
||||
|
||||
@@ -4,6 +4,7 @@ from . import views
|
||||
from . import video_text
|
||||
from . import wxpay
|
||||
from . import AiMssage
|
||||
from . import app_login_pay
|
||||
urlpatterns = [
|
||||
path('login/', views.miniapp_login, name='miniapp_login'),
|
||||
path('video/', views.video_extraction, name='video_extraction'),
|
||||
@@ -26,8 +27,8 @@ urlpatterns = [
|
||||
path('task_status/<str:task_id>/', views.TaskStatusView.as_view(), name='task_status'),
|
||||
path('extend_video/', views.ExtendVideoView.as_view(), name='extend_video'),
|
||||
path('generate_image_video/', views.GenerateImageVideoView.as_view(), name='generate_image_video'),
|
||||
path('user/<int:user_id>/video_tasks/', views.UserVideoTaskListView.as_view(), name='user_video_tasks'),
|
||||
path('user/<int:user_id>/delete_task/<str:task_id>/', views.DeleteVideoTaskView.as_view(), name='delete_task'),
|
||||
path('user/<user_id>/video_tasks/', views.UserVideoTaskListView.as_view(), name='user_video_tasks'),
|
||||
path('user/<user_id>/delete_task/<str:task_id>/', views.DeleteVideoTaskView.as_view(), name='delete_task'),
|
||||
path('call_bailian_app/', AiMssage.call_bailian_app, name='call_bailian_app'),
|
||||
path('get_recent_chat_records/', AiMssage.get_recent_chat_records, name='get_recent_chat_records'),
|
||||
path('asset_library/', views.AssetLibraryView.as_view(), name='asset_library'),
|
||||
@@ -35,6 +36,9 @@ urlpatterns = [
|
||||
path('increment-download-count/', views.increment_download_count, name='increment_download_count'),
|
||||
path('reset-daily-quota/', views.DailyCoinsBonusView.as_view(), name='reset_daily_quota'),
|
||||
path('video-generation-callback/', views.VideoGenerationCallbackView.as_view(), name='VideoGenerationCallbackView'),
|
||||
|
||||
path('app_login/', app_login_pay.wechat_login, name='wechat_login'),
|
||||
path('app_callback/', app_login_pay.wechat_callback, name='wechat_callback'),
|
||||
path('app_wx_pay/', app_login_pay.wx_pay, name='wx_pay'),
|
||||
path('wpp_pay_notify/', app_login_pay.wx_pay_notify, name='wx_pay_notify'),
|
||||
]
|
||||
|
||||
|
||||
@@ -97,7 +97,7 @@ def transcribe_audio(request):
|
||||
else:
|
||||
return JsonResponse({'task_id': existing_task.task_id})
|
||||
else:
|
||||
increment = -1 # 假设每次生成视频需要消耗一次使用次数
|
||||
increment = -2 # 假设每次生成视频需要消耗一次使用次数
|
||||
function_type = 'transcribe_audio'
|
||||
result = update_usage_count(openid, increment, function_type)
|
||||
if not result['success']:
|
||||
|
||||
352
MyApi/views.py
352
MyApi/views.py
@@ -189,16 +189,16 @@ def log_api_call(source, openid, nickname, wxid, wechat_alias, api_name, is_succ
|
||||
remarks=remarks
|
||||
)
|
||||
|
||||
# log_api_call(
|
||||
# source='weixin',
|
||||
# openid='用户的openid',
|
||||
# nickname='用户昵称',
|
||||
# wxid='用户微信ID',
|
||||
# wechat_alias='用户微信号',
|
||||
# api_name='调用的API名称',
|
||||
# is_successful=True,
|
||||
# remarks='备注信息'
|
||||
# )
|
||||
# log_api_call(
|
||||
# source='weixin',
|
||||
# openid='用户的openid',
|
||||
# nickname='用户昵称',
|
||||
# wxid='用户微信ID',
|
||||
# wechat_alias='用户微信号',
|
||||
# api_name='调用的API名称',
|
||||
# is_successful=True,
|
||||
# remarks='备注信息'
|
||||
# )
|
||||
|
||||
def generate_short_id():
|
||||
# 使用IDCounter模型获取下一个ID
|
||||
@@ -265,31 +265,34 @@ def userinfo(request):
|
||||
|
||||
if contains_sql_or_xss(openid):
|
||||
logger.error(f'{openid} 用户触发威胁字符检测: {data}')
|
||||
return JsonResponse({'status': 'error', 'message': '你的国际行为已被记录,我们将保留追责权利'})
|
||||
return JsonResponse({'status': 'error', 'message': '你的行为已被记录,我们将保留追责权利'})
|
||||
|
||||
if not openid:
|
||||
return JsonResponse({"status": "error", 'body': '缺少openid参数'})
|
||||
membership_types = MembershipType.objects.all().values('type', 'title', 'description', 'price', 'coins', 'is_quota')
|
||||
membership_type_list = list(membership_types)
|
||||
return JsonResponse({"status": "success",'membershipTypeList': membership_type_list})
|
||||
else:
|
||||
|
||||
try:
|
||||
user = User.objects.get(openid=openid)
|
||||
except User.DoesNotExist:
|
||||
return JsonResponse({"status": "error", 'userInfo': None})
|
||||
try:
|
||||
user = User.objects.get(openid=openid)
|
||||
except User.DoesNotExist:
|
||||
return JsonResponse({"status": "error", 'userInfo': None})
|
||||
|
||||
increment = -0
|
||||
function_type = 'luserinfo'
|
||||
result = update_usage_count(openid, increment, function_type)
|
||||
membership_types = MembershipType.objects.all().values('type', 'title', 'description', 'price', 'coins', 'is_quota')
|
||||
increment = -0
|
||||
function_type = 'luserinfo'
|
||||
result = update_usage_count(openid, increment, function_type)
|
||||
membership_types = MembershipType.objects.all().values('type', 'title', 'description', 'price', 'coins', 'is_quota')
|
||||
|
||||
user_info = model_to_dict(user)
|
||||
try:
|
||||
user_info['member_start_time'] = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(user.member_start_time))
|
||||
user_info['member_end_time'] = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(user.member_end_time))
|
||||
except:
|
||||
user_info['member_start_time'] = user.member_start_time
|
||||
user_info['member_end_time'] = user.member_end_time
|
||||
user_info = model_to_dict(user)
|
||||
try:
|
||||
user_info['member_start_time'] = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(user.member_start_time))
|
||||
user_info['member_end_time'] = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(user.member_end_time))
|
||||
except:
|
||||
user_info['member_start_time'] = user.member_start_time
|
||||
user_info['member_end_time'] = user.member_end_time
|
||||
|
||||
membership_type_list = list(membership_types)
|
||||
return JsonResponse({"status": "success", 'userInfo': user_info, 'membershipTypeList': membership_type_list})
|
||||
membership_type_list = list(membership_types)
|
||||
return JsonResponse({"status": "success", 'userInfo': user_info, 'membershipTypeList': membership_type_list})
|
||||
|
||||
def generate_token_for_user(openid):
|
||||
# 定义密钥,你应该将其保存在配置文件或环境变量中
|
||||
@@ -316,46 +319,46 @@ SECRET_KEY = "7801ffd6cceaff579812214a93b948b4"
|
||||
#提取视频
|
||||
def video_extraction(request):
|
||||
# 解析POST请求体
|
||||
data = json.loads(request.body)
|
||||
x = request.headers.get('X', '')
|
||||
t = request.headers.get('T', '')
|
||||
if decrypt_param(x, t):
|
||||
data = json.loads(request.body)
|
||||
x = request.headers.get('X', '')
|
||||
t = request.headers.get('T', '')
|
||||
if decrypt_param(x, t):
|
||||
|
||||
try:
|
||||
logger.info(f'视频提取data: {data} ')
|
||||
video_url = data.get('url')
|
||||
uuid = data.get('uuid')
|
||||
openid = data.get('openid')
|
||||
increment = - 1
|
||||
function_type = 'video_extraction'
|
||||
result = update_usage_count(openid, increment, function_type)
|
||||
if result['success']:
|
||||
encoded_video_url = quote(video_url, safe='')
|
||||
# 这里简化了token验证逻辑,实际应用中应根据项目需求进行相应的安全校验
|
||||
if not uuid or not video_url:
|
||||
logger.error(f'{encoded_video_url}视频提取失败--未登录-uuid:{uuid}--openid:{openid}')
|
||||
return JsonResponse({'error': '未登录'})
|
||||
# 调用视频提取API
|
||||
response = requests.post(API_URL, data={
|
||||
'url': video_url,
|
||||
'userId': USER_ID,
|
||||
'secretKey': SECRET_KEY
|
||||
})
|
||||
try:
|
||||
logger.info(f'视频提取data: {data} ')
|
||||
video_url = data.get('url')
|
||||
uuid = data.get('uuid')
|
||||
openid = data.get('openid')
|
||||
increment = -1
|
||||
function_type = 'video_extraction'
|
||||
result = update_usage_count(openid, increment, function_type)
|
||||
if result['success']:
|
||||
encoded_video_url = quote(video_url, safe='')
|
||||
# 这里简化了token验证逻辑,实际应用中应根据项目需求进行相应的安全校验
|
||||
if not uuid or not video_url:
|
||||
logger.error(f'{encoded_video_url}视频提取失败--未登录-uuid:{uuid}--openid:{openid}')
|
||||
return JsonResponse({'error': '未登录'})
|
||||
# 调用视频提取API
|
||||
response = requests.post(API_URL, data={
|
||||
'url': video_url,
|
||||
'userId': USER_ID,
|
||||
'secretKey': SECRET_KEY
|
||||
})
|
||||
|
||||
if response.status_code == 200:
|
||||
logger.info(f'{encoded_video_url}视频提取成功--uuid:{uuid}--openid:{openid}')
|
||||
return JsonResponse(response.json())
|
||||
else:
|
||||
logger.error(f'提取链接无效{response.text}')
|
||||
return JsonResponse({'error': '视频提取失败'}, status=response.status_code)
|
||||
if response.status_code == 200:
|
||||
logger.info(f'{encoded_video_url}视频提取成功--uuid:{uuid}--openid:{openid}')
|
||||
return JsonResponse(response.json())
|
||||
else:
|
||||
print(f'使用次数更新失败: {result}')
|
||||
return JsonResponse(result)
|
||||
except json.JSONDecodeError:
|
||||
logger.error(f'视频提取出错')
|
||||
return JsonResponse({'error': '无效的请求'})
|
||||
else:
|
||||
return JsonResponse({'error': '非法参数'}, status=400)
|
||||
logger.error(f'提取链接无效{response.text}')
|
||||
return JsonResponse({'error': '视频提取失败'}, status=response.status_code)
|
||||
else:
|
||||
print(f'使用次数更新失败: {result}')
|
||||
return JsonResponse(result)
|
||||
except json.JSONDecodeError:
|
||||
logger.error(f'视频提取出错')
|
||||
return JsonResponse({'error': '无效的请求'})
|
||||
else:
|
||||
return JsonResponse({'error': '非法参数'}, status=400)
|
||||
|
||||
|
||||
|
||||
@@ -365,19 +368,19 @@ def video_extraction(request):
|
||||
#储存好友请求数据
|
||||
def add_friend_request(request):
|
||||
if request.method == 'POST':
|
||||
data = json.loads(request.body)
|
||||
# 解析申请时间字符串为datetime对象
|
||||
fromusername = data.get('fromusername')
|
||||
friend_request = FriendRequest.objects.filter(fromusername=fromusername).first()
|
||||
if friend_request:
|
||||
print('已存在')
|
||||
return JsonResponse({"status": "success", "message": "已存在数据"}, status=200)
|
||||
else:
|
||||
data['time'] = datetime.strptime(data['time'], '%Y-%m-%d %H:%M:%S')
|
||||
friend_request = FriendRequest.objects.create(**data)
|
||||
friend_request.save()
|
||||
print('入库成功')
|
||||
return JsonResponse({"status": "success", "message": "添加好友请求已保存"}, status=200)
|
||||
data = json.loads(request.body)
|
||||
# 解析申请时间字符串为datetime对象
|
||||
fromusername = data.get('fromusername')
|
||||
friend_request = FriendRequest.objects.filter(fromusername=fromusername).first()
|
||||
if friend_request:
|
||||
print('已存在')
|
||||
return JsonResponse({"status": "success", "message": "已存在数据"}, status=200)
|
||||
else:
|
||||
data['time'] = datetime.strptime(data['time'], '%Y-%m-%d %H:%M:%S')
|
||||
friend_request = FriendRequest.objects.create(**data)
|
||||
friend_request.save()
|
||||
print('入库成功')
|
||||
return JsonResponse({"status": "success", "message": "添加好友请求已保存"}, status=200)
|
||||
else:
|
||||
return JsonResponse({"status": "error", "message": "只支持POST请求"}, status=405)
|
||||
|
||||
@@ -556,7 +559,7 @@ def redeem_card(request):
|
||||
return JsonResponse({'error': '卡密激活失败,请联系管理员'})
|
||||
elif card.card_type == 'quota':
|
||||
# 如果是额度卡,调用更新使用次数函数
|
||||
|
||||
|
||||
success = update_usage_count(openid, increment=+card.validity_period,function_type='redeem_card')
|
||||
if success.get('success'):
|
||||
card.used_by_openid = openid
|
||||
@@ -595,39 +598,28 @@ def reward_invitation(request):
|
||||
uuid = data.get('uuid', '')
|
||||
|
||||
if openid and uuid:
|
||||
# 查找uuid对应的用户,确保是新用户
|
||||
try:
|
||||
invited_user = User.objects.get(nickname=uuid)
|
||||
logger.info(f'用户 {uuid} 已经存在,不能重复邀请')
|
||||
return JsonResponse({'success': False, 'message': '用户已存在,不能重复邀请'})
|
||||
except User.DoesNotExist:
|
||||
# 被邀请用户不存在,说明是新用户,可以发放奖励
|
||||
try:
|
||||
inviter_user = User.objects.get(openid=openid)
|
||||
except User.DoesNotExist:
|
||||
logger.error(f'邀请人用户 {openid} 不存在')
|
||||
return JsonResponse({'success': False, 'error': '邀请人用户不存在'})
|
||||
invited_user = User.objects.get(nickname=uuid)
|
||||
|
||||
# 更新邀请人信息
|
||||
inviter_user.invitees_count += 1
|
||||
inviter_user.coins += 10
|
||||
inviter_user.save()
|
||||
|
||||
# 创建被邀请用户并设置邀请人信息
|
||||
new_user = User(nickname=uuid, inviter_nickname=inviter_user.nickname)
|
||||
new_user.save()
|
||||
inviter_user = User.objects.get(openid=openid)
|
||||
if inviter_user.inviter_nickname:
|
||||
|
||||
logger.info(f'用户 {openid} 邀请新用户 {uuid} 成功,奖励已发放')
|
||||
return JsonResponse({'success': True, 'message': '奖励发放成功'})
|
||||
|
||||
else:
|
||||
logger.error(f'用户邀请奖励接口 缺少必要参数')
|
||||
logger.error(f'已经被邀请过')
|
||||
return JsonResponse({'success': False, 'error': '缺少必要参数'})
|
||||
else:
|
||||
invited_user.invitees_count += 1
|
||||
invited_user.coins += 1
|
||||
invited_user.save()
|
||||
|
||||
# 创建被邀请用户并设置邀请人信息
|
||||
inviter_user.inviter_nickname = uuid
|
||||
inviter_user.save()
|
||||
|
||||
logger.info(f'用户 {uuid} 邀请新用户 {inviter_user.nickname} 成功,奖励已发放')
|
||||
return JsonResponse({'success': True, 'message': '奖励发放成功'})
|
||||
|
||||
else:
|
||||
return JsonResponse({'success': False, 'error': '非法参数'})
|
||||
except User.DoesNotExist:
|
||||
logger.error(f'用户不存在')
|
||||
return JsonResponse({'success': False, 'error': '用户不存在'})
|
||||
except Exception as e:
|
||||
logger.error(f'发放奖励时出错: {str(e)}')
|
||||
return JsonResponse({'success': False, 'error': '服务器内部错误'})
|
||||
@@ -1085,50 +1077,20 @@ class GenerateImageVideoView(View):
|
||||
|
||||
|
||||
class TaskStatusView(View):
|
||||
|
||||
def get(self, request, task_id):
|
||||
if not task_id:
|
||||
return JsonResponse({"message": "缺少任务ID"}, status=400)
|
||||
|
||||
try:
|
||||
# 从数据库中获取任务
|
||||
task = VideoTask.objects.get(task_id=task_id)
|
||||
except VideoTask.DoesNotExist:
|
||||
task = self.get_task(task_id)
|
||||
if not task:
|
||||
return JsonResponse({"message": "任务不存在"}, status=404)
|
||||
url = f"https://api.aivideoapi.com/status?uuid={task_id}"
|
||||
try:
|
||||
response = requests.get(url, headers=headers)
|
||||
response.raise_for_status()
|
||||
response_data = response.json()
|
||||
print(response_data)
|
||||
except requests.exceptions.RequestException as e:
|
||||
logger.error(f"查询任务状态时出错: {e}")
|
||||
return JsonResponse({"message": "查询任务状态失败", "error": str(e)}, status=500)
|
||||
progress = float(response_data.get('progress', 0)) if response_data.get('progress') is not None else 0.0
|
||||
task.progress = progress
|
||||
if task.progress >= 1.0:
|
||||
if response_data.get('status', task.status) == 'success':
|
||||
task.status = 'success'
|
||||
task.result_url = response_data.get('url', task.result_url)
|
||||
task.gif_url = response_data.get('gif_url', task.gif_url)
|
||||
AssetLibrary.objects.create(
|
||||
original_url=task.result_url,
|
||||
duration=task.seconds,
|
||||
category=task.style,
|
||||
description=task.text_prompt,
|
||||
description_zh=task.description_zh,
|
||||
generated_by=task.nickname,
|
||||
gif_url=task.gif_url,
|
||||
is_approved=True # 假设任务成功的素材自动审核通过
|
||||
)
|
||||
elif response_data.get('status', task.status) == 'failed':
|
||||
task.status = 'failed'
|
||||
elif progress==0.0:
|
||||
task.status = 'pending'
|
||||
else:
|
||||
task.status = 'running'
|
||||
|
||||
# 保存更新后的任务
|
||||
task.save()
|
||||
response_data = self.query_task_status(task_id)
|
||||
if not response_data:
|
||||
return JsonResponse({"message": "查询任务状态失败"}, status=500)
|
||||
|
||||
self.update_task_status(task, response_data)
|
||||
|
||||
return JsonResponse({
|
||||
"task_id": task.task_id,
|
||||
@@ -1138,6 +1100,79 @@ class TaskStatusView(View):
|
||||
"gif_url": task.gif_url
|
||||
}, status=200)
|
||||
|
||||
def get_task(self, task_id):
|
||||
try:
|
||||
return VideoTask.objects.get(task_id=task_id)
|
||||
except VideoTask.DoesNotExist:
|
||||
return None
|
||||
|
||||
def query_task_status(self, task_id):
|
||||
url = f"https://api.aivideoapi.com/status?uuid={task_id}"
|
||||
try:
|
||||
response = requests.get(url, headers=headers)
|
||||
response.raise_for_status()
|
||||
return response.json()
|
||||
except requests.exceptions.RequestException as e:
|
||||
logger.error(f"查询任务状态时出错: {e}")
|
||||
return None
|
||||
|
||||
def update_task_status(self, task, response_data):
|
||||
progress = float(response_data.get('progress', 0)) if response_data.get('progress') is not None else 0.0
|
||||
task.progress = progress
|
||||
|
||||
if task.progress >= 1.0:
|
||||
if response_data.get('status', task.status) == 'success':
|
||||
print(response_data)
|
||||
logger.info(response_data)
|
||||
result_url = self.handle_file_upload(response_data.get('result_url') or response_data.get('url', ''))
|
||||
gif_url = self.handle_file_upload(response_data.get('gif_url', ''))
|
||||
task.status = 'success'
|
||||
task.result_url = result_url
|
||||
task.gif_url = gif_url
|
||||
task.save()
|
||||
self.create_asset_library_entry(task)
|
||||
elif response_data.get('status', task.status) == 'failed':
|
||||
task.status = 'failed'
|
||||
elif progress == 0.0:
|
||||
task.status = 'pending'
|
||||
task.save()
|
||||
else:
|
||||
task.status = 'running'
|
||||
task.save()
|
||||
|
||||
def handle_file_upload(self, file_url):
|
||||
if not file_url:
|
||||
logger.error("文件URL为空,无法下载")
|
||||
return ""
|
||||
|
||||
local_file_path = f"/tmp/{os.path.basename(file_url)}"
|
||||
try:
|
||||
r = requests.get(file_url, stream=True)
|
||||
r.raise_for_status()
|
||||
with open(local_file_path, 'wb') as f:
|
||||
for chunk in r.iter_content(chunk_size=8192):
|
||||
f.write(chunk)
|
||||
qiniu_url = upload_to_qiniu(local_file_path, os.path.basename(local_file_path))
|
||||
except requests.exceptions.RequestException as e:
|
||||
logger.error(f"下载文件时出错: {e}")
|
||||
return ""
|
||||
finally:
|
||||
if os.path.exists(local_file_path) and os.path.isfile(local_file_path):
|
||||
os.remove(local_file_path)
|
||||
return qiniu_url
|
||||
|
||||
def create_asset_library_entry(self, task):
|
||||
AssetLibrary.objects.create(
|
||||
original_url=task.result_url,
|
||||
duration=task.seconds,
|
||||
category=task.style,
|
||||
description=task.description_zh,
|
||||
description_zh=task.description_zh,
|
||||
generated_by=task.nickname,
|
||||
gif_url=task.gif_url,
|
||||
is_approved=False # 假设任务成功的素材自动审核通过
|
||||
)
|
||||
|
||||
|
||||
class UpdatePendingTasksView(View):
|
||||
def get(self, request):
|
||||
@@ -1250,4 +1285,29 @@ class VideoGenerationCallbackView(View):
|
||||
return JsonResponse({'success': False, 'message': '服务器内部错误'}, status=500)
|
||||
|
||||
def post(self, request):
|
||||
return JsonResponse({'success': False, 'message': '请求方法不支持'}, status=405)
|
||||
return JsonResponse({'success': False, 'message': '请求方法不支持'}, status=405)
|
||||
|
||||
|
||||
def wechat_config(request):
|
||||
if request.method == 'GET':
|
||||
url = request.GET.get('url')
|
||||
if not url:
|
||||
return JsonResponse({'error': 'URL is required'}, status=400)
|
||||
|
||||
# 生成签名的逻辑
|
||||
timestamp = int(time.time())
|
||||
nonceStr = ''.join(random.choices('abcdefghijklmnopqrstuvwxyz0123456789', k=16))
|
||||
jsapi_ticket = 'your_jsapi_ticket' # 需要从微信服务器获取
|
||||
string1 = f'jsapi_ticket={jsapi_ticket}&noncestr={nonceStr}×tamp={timestamp}&url={url}'
|
||||
signature = hashlib.sha1(string1.encode('utf-8')).hexdigest()
|
||||
|
||||
config = {
|
||||
'appId': 'your_app_id',
|
||||
'timestamp': timestamp,
|
||||
'nonceStr': nonceStr,
|
||||
'signature': signature,
|
||||
}
|
||||
|
||||
return JsonResponse(config)
|
||||
else:
|
||||
return JsonResponse({'error': 'Invalid request method'}, status=405)
|
||||
Reference in New Issue
Block a user