1
This commit is contained in:
@@ -159,4 +159,4 @@ def extract_error_message(exc: Exception, service_type: str = "video") -> str:
|
||||
return f"{service_type}生成失败: {code}"
|
||||
except (json.JSONDecodeError, TypeError, ValueError):
|
||||
pass
|
||||
return raw[:200] if len(raw) > 200 else raw
|
||||
return raw[:5000] if len(raw) > 5000 else raw
|
||||
@@ -30,7 +30,7 @@ def _log_image_request(engine: ProviderImageEngineLike, record_id: str, request_
|
||||
today = datetime.now().strftime(LOG_DATE_FORMAT)
|
||||
log_file = os.path.join(LOG_DIR, f"{today}.log")
|
||||
request_str = json.dumps(request_data, ensure_ascii=False)
|
||||
request_encrypted = encrypt_data(request_data)
|
||||
request_encrypted = encrypt_data(request_data, True)
|
||||
entry = {
|
||||
"timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
|
||||
"type": "image_gen_request",
|
||||
@@ -54,7 +54,7 @@ def _log_image_response(record_id: str, response_data: dict, error: str | None =
|
||||
os.makedirs(LOG_DIR, exist_ok=True)
|
||||
today = datetime.now().strftime(LOG_DATE_FORMAT)
|
||||
log_file = os.path.join(LOG_DIR, f"{today}.log")
|
||||
response_encrypted = encrypt_data(response_data) if response_data else ""
|
||||
response_encrypted = encrypt_data(response_data, True) if response_data else ""
|
||||
entry = {
|
||||
"timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
|
||||
"type": "image_gen_response",
|
||||
|
||||
@@ -37,8 +37,8 @@ def _log_ai_request_response(config, request_data: dict, response_data: dict | N
|
||||
os.makedirs(LOG_DIR, exist_ok=True)
|
||||
today = datetime.now().strftime(LOG_DATE_FORMAT)
|
||||
log_file = os.path.join(LOG_DIR, f"{today}.log")
|
||||
request_encrypted = encrypt_data(_sanitize_for_log(request_data))
|
||||
response_encrypted = encrypt_data(_sanitize_for_log(response_data)) if response_data else ""
|
||||
request_encrypted = encrypt_data(_sanitize_for_log(request_data), True)
|
||||
response_encrypted = encrypt_data(_sanitize_for_log(response_data), True) if response_data else ""
|
||||
entry = {
|
||||
"timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
|
||||
"model_name": config.name,
|
||||
|
||||
@@ -18,10 +18,13 @@ ENCRYPTION_KEY = b'videogen@202605!'
|
||||
|
||||
|
||||
|
||||
def encrypt_data(data: dict) -> str:
|
||||
def encrypt_data(data: dict, is_encrypt: bool = False) -> str:
|
||||
data_str = json.dumps(data, ensure_ascii=False, sort_keys=True)
|
||||
if is_encrypt:
|
||||
return data_str
|
||||
|
||||
data_bytes = data_str.encode("utf-8")
|
||||
|
||||
|
||||
padder = padding.PKCS7(128).padder()
|
||||
padded_data = padder.update(data_bytes) + padder.finalize()
|
||||
|
||||
|
||||
@@ -0,0 +1,379 @@
|
||||
from typing import Optional, List, Tuple
|
||||
from datetime import datetime
|
||||
|
||||
from sqlalchemy import select, func
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from app.models.user import User
|
||||
from app.models.user_oauth import UserOAuth
|
||||
from app.models.user_oauth_account import UserOAuthAccount
|
||||
from app.models.resources_material import ResourcesMaterial
|
||||
from app.models.pre_test_template import PreTestTemplate
|
||||
from app.models.upload_task import UploadTask
|
||||
from app.utils.datetime_util import BEIJING_TZ, datetime_to_db_tz_str, db_tz_str_to_datetime, parse_date_range
|
||||
|
||||
|
||||
async def get_oauth_list(
|
||||
id: Optional[str] = None,
|
||||
db: AsyncSession = None,
|
||||
phone: Optional[str] = None,
|
||||
account_id: Optional[str] = None,
|
||||
account_userid: Optional[str] = None,
|
||||
created_at: Optional[datetime] = None,
|
||||
appid: Optional[str] = None,
|
||||
open_type: Optional[int] = None,
|
||||
page: int = 1,
|
||||
page_size: int = 10,
|
||||
) -> Tuple[List[UserOAuth], int]:
|
||||
offset = (page - 1) * page_size
|
||||
|
||||
query = select(UserOAuth).where(UserOAuth.deleted_at.is_(None))
|
||||
if id:
|
||||
query = query.where(UserOAuth.id == id)
|
||||
if phone:
|
||||
query = query.join(User, User.id == UserOAuth.user_id).where(User.phone == phone)
|
||||
if account_id:
|
||||
query = query.where(UserOAuth.account_id == account_id)
|
||||
if account_userid:
|
||||
query = query.where(UserOAuth.account_userid == account_userid)
|
||||
# 【改动3】适配入参 created_at=["2025-01-01","2026-01-01"] 字符串日期场景
|
||||
if created_at and len(created_at) == 2:
|
||||
try:
|
||||
start_dt, end_dt = parse_date_range(created_at, is_timezone=True)
|
||||
# 直接用datetime范围匹配,不走func.date,保留时分秒精度,命中索引
|
||||
query = query.where(
|
||||
UserOAuth.created_at >= start_dt,
|
||||
UserOAuth.created_at <= end_dt
|
||||
)
|
||||
except ValueError:
|
||||
# 捕获日期格式错误,非法时间直接不附加该查询条件
|
||||
pass
|
||||
if appid:
|
||||
query = query.where(UserOAuth.appid == appid)
|
||||
if open_type:
|
||||
query = query.where(UserOAuth.open_type == open_type)
|
||||
|
||||
count_query = select(func.count(UserOAuth.id)).where(UserOAuth.deleted_at.is_(None))
|
||||
|
||||
if phone:
|
||||
count_query = count_query.join(User, User.id == UserOAuth.user_id).where(User.phone == phone)
|
||||
if account_id:
|
||||
count_query = count_query.where(UserOAuth.account_id == account_id)
|
||||
if account_userid:
|
||||
count_query = count_query.where(UserOAuth.account_userid == account_userid)
|
||||
if created_at:
|
||||
try:
|
||||
start_dt, end_dt = parse_date_range(created_at, is_timezone=True)
|
||||
# 直接用datetime范围匹配,不走func.date,保留时分秒精度,命中索引
|
||||
count_query = count_query.where(
|
||||
UserOAuth.created_at >= start_dt,
|
||||
UserOAuth.created_at <= end_dt
|
||||
)
|
||||
except ValueError:
|
||||
# 捕获日期格式错误,非法时间直接不附加该查询条件
|
||||
pass
|
||||
if appid:
|
||||
count_query = count_query.where(UserOAuth.appid == appid)
|
||||
if open_type:
|
||||
count_query = count_query.where(UserOAuth.open_type == open_type)
|
||||
|
||||
total_result = await db.execute(count_query)
|
||||
total = total_result.scalar_one()
|
||||
|
||||
query = query.order_by(UserOAuth.id.desc()).offset(offset).limit(page_size)
|
||||
result = await db.execute(query)
|
||||
list = [];
|
||||
for oauth in result.scalars().all():
|
||||
user_query = select(User).where(User.id == oauth.user_id)
|
||||
user_result = await db.execute(user_query)
|
||||
user = user_result.scalar_one()
|
||||
if user:
|
||||
phone = user.phone
|
||||
else:
|
||||
phone = None
|
||||
item = {
|
||||
"id": oauth.id,
|
||||
"account_id": oauth.account_id,
|
||||
"account_name": oauth.account_name,
|
||||
"account_role": oauth.account_role,
|
||||
"account_username": oauth.account_username,
|
||||
"account_userid": oauth.account_userid,
|
||||
"user_id": oauth.user_id,
|
||||
"user_phone": phone,
|
||||
"open_type": oauth.open_type,
|
||||
"port_type": oauth.port_type,
|
||||
"appid": oauth.appid,
|
||||
"access_token": oauth.access_token,
|
||||
"refresh_token": oauth.refresh_token,
|
||||
"access_token_expired": oauth.access_token_expired,
|
||||
"refresh_token_expired": oauth.refresh_token_expired,
|
||||
"created_at": oauth.created_at,
|
||||
"updated_at": oauth.updated_at,
|
||||
}
|
||||
list.append(item)
|
||||
return list, total
|
||||
|
||||
|
||||
async def get_material_list(
|
||||
db: AsyncSession,
|
||||
phone: Optional[str] = None,
|
||||
id: Optional[str] = None,
|
||||
resource_type: Optional[str] = None,
|
||||
advertiser_id: Optional[str] = None,
|
||||
material_id: Optional[str] = None,
|
||||
upload_id: Optional[str] = None,
|
||||
created_at: Optional[datetime] = None,
|
||||
status: Optional[str] = None,
|
||||
page: int = 1,
|
||||
page_size: int = 20,
|
||||
) -> Tuple[List[ResourcesMaterial], int]:
|
||||
offset = (page - 1) * page_size
|
||||
|
||||
query = select(ResourcesMaterial).where(ResourcesMaterial.deleted_at.is_(None))
|
||||
|
||||
if phone:
|
||||
query = query.join(UserOAuth, UserOAuth.id == ResourcesMaterial.oauth_id).join(User, User.id == UserOAuth.user_id).where(User.phone == phone)
|
||||
if id:
|
||||
query = query.where(ResourcesMaterial.id == id)
|
||||
if resource_type:
|
||||
query = query.where(ResourcesMaterial.resource_type == resource_type)
|
||||
if advertiser_id:
|
||||
query = query.where(ResourcesMaterial.advertiser_id == advertiser_id)
|
||||
if material_id:
|
||||
query = query.where(ResourcesMaterial.material_id == material_id)
|
||||
if upload_id:
|
||||
query = query.where(ResourcesMaterial.upload_id == upload_id)
|
||||
if created_at:
|
||||
start_dt, end_dt = parse_date_range(created_at, is_timezone=True)
|
||||
# 直接用datetime范围匹配,不走func.date,保留时分秒精度,命中索引
|
||||
query = query.where(
|
||||
ResourcesMaterial.created_at >= start_dt,
|
||||
ResourcesMaterial.created_at <= end_dt
|
||||
)
|
||||
if status:
|
||||
query = query.where(ResourcesMaterial.status == status)
|
||||
|
||||
count_query = select(func.count(ResourcesMaterial.id)).where(ResourcesMaterial.deleted_at.is_(None))
|
||||
|
||||
if phone:
|
||||
count_query = count_query.join(UserOAuth, UserOAuth.id == ResourcesMaterial.oauth_id).join(User, User.id == UserOAuth.user_id).where(User.phone == phone)
|
||||
if id:
|
||||
count_query = count_query.where(ResourcesMaterial.id == id)
|
||||
if resource_type:
|
||||
count_query = count_query.where(ResourcesMaterial.resource_type == resource_type)
|
||||
if advertiser_id:
|
||||
count_query = count_query.where(ResourcesMaterial.advertiser_id == advertiser_id)
|
||||
if material_id:
|
||||
count_query = count_query.where(ResourcesMaterial.material_id == material_id)
|
||||
if upload_id:
|
||||
count_query = count_query.where(ResourcesMaterial.upload_id == upload_id)
|
||||
if created_at:
|
||||
start_dt, end_dt = parse_date_range(created_at, is_timezone=True)
|
||||
# 直接用datetime范围匹配,不走func.date,保留时分秒精度,命中索引
|
||||
count_query = count_query.where(
|
||||
ResourcesMaterial.created_at >= start_dt,
|
||||
ResourcesMaterial.created_at <= end_dt
|
||||
)
|
||||
if status:
|
||||
count_query = count_query.where(ResourcesMaterial.status == status)
|
||||
|
||||
total_result = await db.execute(count_query)
|
||||
total = total_result.scalar_one()
|
||||
|
||||
query = query.order_by(ResourcesMaterial.id.desc()).offset(offset).limit(page_size)
|
||||
result = await db.execute(query)
|
||||
list = []
|
||||
for item in result.scalars().all():
|
||||
user_query = select(User).where(User.id == item.user_id)
|
||||
user_result = await db.execute(user_query)
|
||||
user = user_result.scalar_one()
|
||||
if user:
|
||||
phone = user.phone
|
||||
else:
|
||||
phone = None
|
||||
item = {
|
||||
"id": item.id,
|
||||
"oauth_id": item.oauth_id,
|
||||
"user_phone": phone,
|
||||
"advertiser_id": item.advertiser_id,
|
||||
"target_table": item.target_table,
|
||||
"target_id": item.target_id,
|
||||
"material_id": item.material_id,
|
||||
"upload_id": item.upload_id,
|
||||
"resource_type": item.resource_type,
|
||||
"user_id": item.user_id,
|
||||
"created_at": item.created_at,
|
||||
"updated_at": item.updated_at,
|
||||
"task_id": item.task_id,
|
||||
"note": item.note,
|
||||
"status": item.status,
|
||||
"pre_result": item.pre_result,
|
||||
"pre_test_template_id": item.pre_test_template_id,
|
||||
}
|
||||
list.append(item)
|
||||
|
||||
return list, total
|
||||
|
||||
|
||||
async def get_pre_test_template_list(
|
||||
db: AsyncSession,
|
||||
phone: Optional[str] = None,
|
||||
id: Optional[str] = None,
|
||||
created_at: Optional[datetime] = None,
|
||||
page: int = 1,
|
||||
page_size: int = 10,
|
||||
) -> Tuple[List[PreTestTemplate], int]:
|
||||
offset = (page - 1) * page_size
|
||||
|
||||
query = select(PreTestTemplate).where(PreTestTemplate.deleted_at.is_(None))
|
||||
|
||||
if phone:
|
||||
query = query.join(User, User.id == PreTestTemplate.user_id).where(User.phone == phone)
|
||||
if id:
|
||||
query = query.where(PreTestTemplate.id == id)
|
||||
if created_at:
|
||||
start_dt, end_dt = parse_date_range(created_at, is_timezone=True)
|
||||
# 直接用datetime范围匹配,不走func.date,保留时分秒精度,命中索引
|
||||
query = query.where(
|
||||
PreTestTemplate.created_at >= start_dt,
|
||||
PreTestTemplate.created_at <= end_dt
|
||||
)
|
||||
|
||||
count_query = select(func.count(PreTestTemplate.id)).where(PreTestTemplate.deleted_at.is_(None))
|
||||
|
||||
if phone:
|
||||
count_query = count_query.join(User, User.id == PreTestTemplate.user_id).where(User.phone == phone)
|
||||
if id:
|
||||
count_query = count_query.where(PreTestTemplate.id == id)
|
||||
if created_at:
|
||||
# 直接用datetime范围匹配,不走func.date,保留时分秒精度,命中索引
|
||||
start_dt, end_dt = parse_date_range(created_at, is_timezone=True)
|
||||
count_query = count_query.where(
|
||||
PreTestTemplate.created_at >= start_dt,
|
||||
PreTestTemplate.created_at <= end_dt
|
||||
)
|
||||
|
||||
total_result = await db.execute(count_query)
|
||||
total = total_result.scalar_one()
|
||||
|
||||
query = query.order_by(PreTestTemplate.id.desc()).offset(offset).limit(page_size)
|
||||
result = await db.execute(query)
|
||||
list = []
|
||||
for item in result.scalars().all():
|
||||
user_query = select(User).where(User.id == item.user_id)
|
||||
user_result = await db.execute(user_query)
|
||||
user = user_result.scalar_one()
|
||||
if user:
|
||||
phone = user.phone
|
||||
else:
|
||||
phone = None
|
||||
item = {
|
||||
"id": item.id,
|
||||
"name": item.name,
|
||||
"user_phone": phone,
|
||||
"user_id": item.user_id,
|
||||
"platform": item.platform,
|
||||
"external_action": item.external_action,
|
||||
"cpa_bid": item.cpa_bid,
|
||||
"audience_gender": item.audience_gender,
|
||||
"audience_age": item.audience_age,
|
||||
"audience_region": item.audience_region,
|
||||
"audience_network": item.audience_network,
|
||||
"cus_name": item.cus_name,
|
||||
"pricing_type": item.pricing_type,
|
||||
"cost_cap": item.cost_cap,
|
||||
"target_cost": item.target_cost,
|
||||
"nobid": item.nobid,
|
||||
"cpc_bid": item.cpc_bid,
|
||||
"budget": item.budget,
|
||||
"is_default": item.is_default,
|
||||
"created_at": item.created_at,
|
||||
"updated_at": item.updated_at,
|
||||
"note": item.note,
|
||||
}
|
||||
list.append(item)
|
||||
return list, total
|
||||
|
||||
|
||||
async def get_upload_task_list(
|
||||
db: AsyncSession,
|
||||
phone: Optional[str] = None,
|
||||
id: Optional[str] = None,
|
||||
created_at: Optional[List[str]] = None,
|
||||
advertiser_id: Optional[str] = None,
|
||||
status: Optional[int] = None,
|
||||
resource_id: Optional[str] = None,
|
||||
page: int = 1,
|
||||
page_size: int = 10,
|
||||
) -> Tuple[List[UploadTask], int]:
|
||||
offset = (page - 1) * page_size
|
||||
|
||||
query = select(UploadTask).where(UploadTask.deleted_at.is_(None))
|
||||
|
||||
if phone:
|
||||
query = query.join(User, User.id == UploadTask.user_id).where(User.phone == phone)
|
||||
if id:
|
||||
query = query.where(UploadTask.id == id)
|
||||
if created_at and len(created_at) >= 2:
|
||||
# 直接用datetime范围匹配,不走func.date,保留时分秒精度,命中索引
|
||||
start_dt, end_dt = parse_date_range(created_at, is_timezone=True)
|
||||
query = query.where(
|
||||
UploadTask.created_at >= start_dt,
|
||||
UploadTask.created_at <= end_dt
|
||||
)
|
||||
if advertiser_id:
|
||||
query = query.where(UploadTask.advertiser_id == advertiser_id)
|
||||
if status:
|
||||
query = query.where(UploadTask.status == status)
|
||||
if resource_id:
|
||||
query = query.where(UploadTask.resource_id == resource_id)
|
||||
|
||||
count_query = select(func.count(UploadTask.id)).where(UploadTask.deleted_at.is_(None))
|
||||
|
||||
if phone:
|
||||
count_query = count_query.join(User, User.id == UploadTask.user_id).where(User.phone == phone)
|
||||
if id:
|
||||
count_query = count_query.where(UploadTask.id == id)
|
||||
if created_at and len(created_at) >= 2:
|
||||
# 直接用datetime范围匹配,不走func.date,保留时分秒精度,命中索引
|
||||
start_dt, end_dt = parse_date_range(created_at, is_timezone=True)
|
||||
count_query = count_query.where(
|
||||
UploadTask.created_at >= start_dt,
|
||||
UploadTask.created_at <= end_dt
|
||||
)
|
||||
if advertiser_id:
|
||||
count_query = count_query.where(UploadTask.advertiser_id == advertiser_id)
|
||||
if status:
|
||||
count_query = count_query.where(UploadTask.status == status)
|
||||
if resource_id:
|
||||
count_query = count_query.where(UploadTask.resource_id == resource_id)
|
||||
|
||||
total_result = await db.execute(count_query)
|
||||
total = total_result.scalar_one()
|
||||
|
||||
query = query.order_by(UploadTask.id.desc()).offset(offset).limit(page_size)
|
||||
result = await db.execute(query)
|
||||
list = []
|
||||
for item in result.scalars().all():
|
||||
user_query = select(User).where(User.id == item.user_id)
|
||||
user_result = await db.execute(user_query)
|
||||
user = user_result.scalar_one()
|
||||
if user:
|
||||
phone = user.phone
|
||||
else:
|
||||
phone = None
|
||||
item = {
|
||||
"id": item.id,
|
||||
"user_phone": phone,
|
||||
"user_id": item.user_id,
|
||||
"advertiser_id": item.advertiser_id,
|
||||
"resource_id": item.resource_id,
|
||||
"status": item.status,
|
||||
"note": item.note,
|
||||
"oauth_id": item.oauth_id,
|
||||
"created_at": item.created_at,
|
||||
"updated_at": item.updated_at,
|
||||
"other_info": item.other_info,
|
||||
}
|
||||
list.append(item)
|
||||
return list, total
|
||||
@@ -1,20 +1,22 @@
|
||||
import random
|
||||
from datetime import datetime, timedelta, timezone
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
import httpx
|
||||
from sqlalchemy import select, func
|
||||
from sqlalchemy import select, func, update
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from app.config import settings
|
||||
# 引入项目统一北京时间时区
|
||||
from app.utils.datetime_util import BEIJING_TZ
|
||||
from app.models.user_oauth import UserOAuth
|
||||
from app.models.user_oauth_app import UserOAuthApp
|
||||
from app.utils.id_gen import generate_id
|
||||
from app.tasks.token_refresh_task import _update_redis_token
|
||||
from app.tasks.token_refresh_task import _update_redis_token, _delete_redis_token
|
||||
|
||||
#随机获取一个可用的应用配置
|
||||
# 随机获取一个可用的应用配置
|
||||
async def get_available_app(open_type: int, db: AsyncSession) -> dict:
|
||||
# 从 user_oauth_app 表查询可用应用
|
||||
# 过滤条件:open_type 匹配、status=1(正常)、deleted_at is None
|
||||
if not isinstance(open_type, int):
|
||||
raise ValueError("open_type必须为整数类型")
|
||||
|
||||
result = await db.execute(
|
||||
select(UserOAuthApp).where(
|
||||
UserOAuthApp.open_type == open_type,
|
||||
@@ -30,8 +32,6 @@ async def get_available_app(open_type: int, db: AsyncSession) -> dict:
|
||||
available_apps = []
|
||||
for app in apps:
|
||||
app_id = app.app_id
|
||||
|
||||
# 查询该应用当前授权数量
|
||||
count_result = await db.execute(
|
||||
select(func.count(UserOAuth.id)).where(
|
||||
UserOAuth.appid == app_id,
|
||||
@@ -39,8 +39,6 @@ async def get_available_app(open_type: int, db: AsyncSession) -> dict:
|
||||
)
|
||||
)
|
||||
count = count_result.scalar() or 0
|
||||
|
||||
# 检查是否达到最大授权数
|
||||
max_users = app.max_count
|
||||
if count < max_users:
|
||||
available_apps.append({
|
||||
@@ -59,24 +57,21 @@ async def get_available_app(open_type: int, db: AsyncSession) -> dict:
|
||||
|
||||
async def build_oauth_url(open_type: int, user_id: str, db: AsyncSession) -> str:
|
||||
if open_type == 1:
|
||||
#千川
|
||||
return await _build_jl_oauth_url(open_type, user_id, db)
|
||||
elif open_type in [2, 3]:
|
||||
#广告,本地推
|
||||
return await _build_jl_oauth_url(2, user_id, db)
|
||||
elif open_type == 5:
|
||||
#快手代理商
|
||||
return "无配置"
|
||||
elif open_type == 9:
|
||||
#腾讯营销K2
|
||||
return "无配置"
|
||||
elif open_type == 10:
|
||||
#腾讯营销K3
|
||||
return "无配置"
|
||||
else:
|
||||
raise ValueError(f"不支持的应用类型: {app_type}")
|
||||
# 修复BUG:变量名错误 app_type -> open_type
|
||||
raise ValueError(f"不支持的应用类型: {open_type}")
|
||||
|
||||
#千川授权链接构建
|
||||
|
||||
# 千川授权链接构建
|
||||
async def _build_jl_oauth_url(open_type: int, user_id: str, db: AsyncSession) -> str:
|
||||
app = await get_available_app(open_type, db)
|
||||
app_id = app.get("app_id")
|
||||
@@ -92,221 +87,232 @@ async def _build_jl_oauth_url(open_type: int, user_id: str, db: AsyncSession) ->
|
||||
|
||||
|
||||
async def get_token(code: str, user_id: str, app_id: str, db: AsyncSession) -> dict:
|
||||
#1.根据app_id查询应用配置
|
||||
if not all([code, user_id, app_id]):
|
||||
raise ValueError("code、user_id、app_id不能为空")
|
||||
|
||||
result = await db.execute(
|
||||
select(UserOAuthApp).where(UserOAuthApp.app_id == app_id)
|
||||
select(UserOAuthApp).where(
|
||||
UserOAuthApp.app_id == app_id,
|
||||
UserOAuthApp.deleted_at.is_(None),
|
||||
UserOAuthApp.status == 1
|
||||
)
|
||||
)
|
||||
app = result.scalar_one_or_none()
|
||||
if not app:
|
||||
raise ValueError("应用配置不存在")
|
||||
|
||||
raise ValueError("应用配置不存在或已禁用")
|
||||
|
||||
open_type = app.open_type
|
||||
secret = app.secret
|
||||
|
||||
if open_type == 1 or open_type == 2:
|
||||
#千川或广告
|
||||
if open_type in (1, 2):
|
||||
return await get_juliang_token(app_id, secret, code, open_type, user_id, db)
|
||||
elif open_type == 5:
|
||||
#快手代理商
|
||||
return await get_kuaishou_token(app_id, secret, code, open_type, user_id, db)
|
||||
elif open_type == 9 or open_type == 10:
|
||||
#腾讯营销K2或腾讯营销K3
|
||||
elif open_type in (9, 10):
|
||||
return await get_tencent_token(app_id, secret, code, open_type, user_id, db)
|
||||
else:
|
||||
raise ValueError(f"不支持的应用类型: {open_type}")
|
||||
|
||||
|
||||
async def get_juliang_token(app_id: str, secret: str, code: str, open_type: int, user_id: str, db: AsyncSession) -> dict:
|
||||
|
||||
async with httpx.AsyncClient() as client:
|
||||
#1.请求token
|
||||
url = "https://api.oceanengine.com/open_api/oauth2/access_token/"
|
||||
response = await client.post(
|
||||
url,
|
||||
json={
|
||||
"app_id": app_id,
|
||||
"secret": secret,
|
||||
"auth_code": code,
|
||||
},
|
||||
)
|
||||
response.raise_for_status()
|
||||
data = response.json()
|
||||
if data.get("code") != 0:
|
||||
raise ValueError(data.get("message", "获取token失败")+f",错误信息:{data.get('message', '')}")
|
||||
data = data.get("data", {})
|
||||
access_token = data.get("access_token", "")
|
||||
refresh_token = data.get("refresh_token", "")
|
||||
expires_in = datetime.now(timezone.utc) + timedelta(seconds=data.get("expires_in", 0))
|
||||
refresh_token_expires_in = datetime.now(timezone.utc) + timedelta(seconds=data.get("refresh_token_expires_in", 0))
|
||||
#2.获取已授权角色账户,一个授权可能有多个角色账户
|
||||
url = "https://api.oceanengine.com/open_api/oauth2/advertiser/get/"
|
||||
response = await client.get(
|
||||
url,
|
||||
headers={"Access-Token": access_token},
|
||||
)
|
||||
response.raise_for_status()
|
||||
data = response.json()
|
||||
if data.get("code") != 0:
|
||||
raise ValueError(data.get("message", "获取已授权账户失败")+f",错误信息:{data.get('message', '')}")
|
||||
data = data.get("data", {})
|
||||
account_list = data.get("list", [])
|
||||
#3.获取已授权登录信息
|
||||
url = "https://api.oceanengine.com/open_api/2/user/info/"
|
||||
response = await client.get(
|
||||
url,
|
||||
headers={"Access-Token": access_token},
|
||||
)
|
||||
response.raise_for_status()
|
||||
data = response.json()
|
||||
if data.get("code") != 0:
|
||||
raise ValueError(data.get("message", "获取已授权登录信息失败")+f",错误信息:{data.get('message', '')}")
|
||||
data = data.get("data", {})
|
||||
account_username = data.get("email", "")
|
||||
account_userid = str(data.get("id", ""))
|
||||
material_auth_status = data.get("material_auth_status", False)
|
||||
#4.根据登录信息判断是否新增token或更新token,不同的登录信息对应不同的token,然后更新数据库
|
||||
#查询email,appid,user_id是否存在已授权记录
|
||||
oauth = await db.execute(
|
||||
select(UserOAuth)
|
||||
.where(UserOAuth.account_username == account_username, UserOAuth.account_userid == account_userid, UserOAuth.appid == app_id, UserOAuth.user_id == user_id)
|
||||
.limit(1)
|
||||
)
|
||||
oauth = oauth.scalar_one_or_none()
|
||||
if not oauth:
|
||||
new_oauth_ids = []
|
||||
for account in account_list:
|
||||
oauth_id = generate_id()
|
||||
new_oauth_ids.append(oauth_id)
|
||||
#新增授权记录
|
||||
db.add(UserOAuth(
|
||||
id=oauth_id,
|
||||
account_id = str(account.get("account_id", "")),
|
||||
account_name = account.get("account_name", ""),
|
||||
account_role = account.get("account_role", ""),
|
||||
account_username = account_username,
|
||||
account_userid = account_userid,
|
||||
user_id = user_id,
|
||||
appid = app_id,
|
||||
open_type = open_type,
|
||||
port_type = 1,
|
||||
access_token = access_token,
|
||||
access_token_expired = expires_in,
|
||||
refresh_token = refresh_token,
|
||||
refresh_token_expired = refresh_token_expires_in,
|
||||
material_auth_status = material_auth_status,
|
||||
))
|
||||
await db.commit()
|
||||
|
||||
|
||||
for oauth_id in new_oauth_ids:
|
||||
await _update_redis_token(oauth_id, access_token, expires_in)
|
||||
else:
|
||||
# 查询现有授权记录(未删除的)
|
||||
existing_accounts = await db.execute(
|
||||
select(UserOAuth).where(
|
||||
timeout = httpx.Timeout(30.0)
|
||||
try:
|
||||
async with httpx.AsyncClient(timeout=timeout) as client:
|
||||
# 1. 获取token
|
||||
url = "https://api.oceanengine.com/open_api/oauth2/access_token/"
|
||||
resp = await client.post(
|
||||
url,
|
||||
json={
|
||||
"app_id": app_id,
|
||||
"secret": secret,
|
||||
"auth_code": code,
|
||||
},
|
||||
)
|
||||
resp.raise_for_status()
|
||||
data = resp.json()
|
||||
if data.get("code") != 0:
|
||||
msg = data.get("message", "获取token失败")
|
||||
raise ValueError(f"获取token失败:{msg}")
|
||||
|
||||
resp_data = data.get("data", {})
|
||||
access_token = resp_data.get("access_token", "")
|
||||
refresh_token = resp_data.get("refresh_token", "")
|
||||
expires_sec = resp_data.get("expires_in", 7200)
|
||||
refresh_expires_sec = resp_data.get("refresh_token_expires_in", 30 * 24 * 3600)
|
||||
|
||||
# 【修复:统一使用北京时间计算过期时间】
|
||||
now_beijing = datetime.now(tz=BEIJING_TZ)
|
||||
access_expired = now_beijing + timedelta(seconds=expires_sec)
|
||||
refresh_expired = now_beijing + timedelta(seconds=refresh_expires_sec)
|
||||
|
||||
# 2. 获取授权广告账户列表
|
||||
resp = await client.get(
|
||||
"https://api.oceanengine.com/open_api/oauth2/advertiser/get/",
|
||||
headers={"Access-Token": access_token},
|
||||
)
|
||||
resp.raise_for_status()
|
||||
data = resp.json()
|
||||
if data.get("code") != 0:
|
||||
raise ValueError(f"获取已授权账户失败:{data.get('message')}")
|
||||
account_list = data.get("data", {}).get("list", [])
|
||||
|
||||
# 3. 获取登录用户信息
|
||||
resp = await client.get(
|
||||
"https://api.oceanengine.com/open_api/2/user/info/",
|
||||
headers={"Access-Token": access_token},
|
||||
)
|
||||
resp.raise_for_status()
|
||||
data = resp.json()
|
||||
if data.get("code") != 0:
|
||||
raise ValueError(f"获取登录信息失败:{data.get('message')}")
|
||||
|
||||
user_info = data.get("data", {})
|
||||
account_username = user_info.get("email", "")
|
||||
account_userid = str(user_info.get("id", ""))
|
||||
material_auth_status = user_info.get("material_auth_status", False)
|
||||
|
||||
# 4. 查询当前用户+应用+登录账号下的授权记录
|
||||
oauth_query = select(UserOAuth).where(
|
||||
UserOAuth.account_username == account_username,
|
||||
UserOAuth.account_userid == account_userid,
|
||||
UserOAuth.appid == app_id,
|
||||
UserOAuth.user_id == user_id,
|
||||
UserOAuth.deleted_at.is_(None)
|
||||
)
|
||||
oauth_exist = await db.execute(oauth_query.limit(1))
|
||||
oauth_exist = oauth_exist.scalar_one_or_none()
|
||||
|
||||
if not oauth_exist:
|
||||
# 新增授权
|
||||
new_oauth_ids = []
|
||||
for account in account_list:
|
||||
oauth_id = generate_id()
|
||||
new_oauth_ids.append(oauth_id)
|
||||
db.add(UserOAuth(
|
||||
id=oauth_id,
|
||||
account_id=str(account.get("account_id", "")),
|
||||
account_name=account.get("account_name", ""),
|
||||
account_role=account.get("account_role", ""),
|
||||
account_username=account_username,
|
||||
account_userid=account_userid,
|
||||
user_id=user_id,
|
||||
appid=app_id,
|
||||
open_type=open_type,
|
||||
port_type=1,
|
||||
access_token=access_token,
|
||||
access_token_expired=access_expired,
|
||||
refresh_token=refresh_token,
|
||||
refresh_token_expired=refresh_expired,
|
||||
material_auth_status=material_auth_status,
|
||||
))
|
||||
await db.commit()
|
||||
# 批量写入Redis
|
||||
for oauth_id in new_oauth_ids:
|
||||
await _update_redis_token(oauth_id, access_token, access_expired)
|
||||
else:
|
||||
# 查询当前所有有效授权账户
|
||||
exist_query = select(UserOAuth).where(
|
||||
UserOAuth.account_username == account_username,
|
||||
UserOAuth.account_userid == account_userid,
|
||||
UserOAuth.appid == app_id,
|
||||
UserOAuth.user_id == user_id,
|
||||
UserOAuth.deleted_at.is_(None),
|
||||
)
|
||||
)
|
||||
existing_accounts = {acc.account_id: acc for acc in existing_accounts.scalars().all()}
|
||||
exist_res = await db.execute(exist_query)
|
||||
exist_map = {item.account_id: item for item in exist_res.scalars().all()}
|
||||
|
||||
# 新的账户列表
|
||||
new_account_ids = {str(account.get("account_id")) for account in account_list}
|
||||
old_account_ids = set(existing_accounts.keys())
|
||||
new_account_ids = {str(acc.get("account_id")) for acc in account_list}
|
||||
old_account_ids = set(exist_map.keys())
|
||||
update_redis_ids = []
|
||||
|
||||
# 需要更新Redis的oauth_id列表
|
||||
update_redis_ids = []
|
||||
# 下线的账户:软删除 + 清理Redis脏缓存
|
||||
for del_account_id in old_account_ids - new_account_ids:
|
||||
del_oauth = exist_map[del_account_id]
|
||||
del_oauth.deleted_at = now_beijing
|
||||
await _delete_redis_token(del_oauth.id)
|
||||
|
||||
# 1. 软删除已消失的账户
|
||||
for account_id in old_account_ids - new_account_ids:
|
||||
existing_accounts[account_id].deleted_at = datetime.now(timezone.utc)
|
||||
|
||||
# 2. 更新或新增账户
|
||||
for account in account_list:
|
||||
account_id = str(account.get("account_id", ""))
|
||||
if account_id in existing_accounts:
|
||||
# 更新现有记录
|
||||
existing_oauth = existing_accounts[account_id]
|
||||
existing_oauth.account_name = account.get("account_name", "")
|
||||
existing_oauth.account_role = account.get("account_role", "")
|
||||
existing_oauth.access_token = access_token
|
||||
existing_oauth.access_token_expired = expires_in
|
||||
existing_oauth.refresh_token = refresh_token
|
||||
existing_oauth.refresh_token_expired = refresh_token_expires_in
|
||||
existing_oauth.material_auth_status = material_auth_status
|
||||
update_redis_ids.append(existing_oauth.id)
|
||||
else:
|
||||
# 新增记录
|
||||
oauth_id = generate_id()
|
||||
update_redis_ids.append(oauth_id)
|
||||
db.add(UserOAuth(
|
||||
# 更新/新增当前授权账户
|
||||
for account in account_list:
|
||||
aid = str(account.get("account_id", ""))
|
||||
if aid in exist_map:
|
||||
item = exist_map[aid]
|
||||
item.account_name = account.get("account_name", "")
|
||||
item.account_role = account.get("account_role", "")
|
||||
item.access_token = access_token
|
||||
item.access_token_expired = access_expired
|
||||
item.refresh_token = refresh_token
|
||||
item.refresh_token_expired = refresh_expired
|
||||
item.material_auth_status = material_auth_status
|
||||
update_redis_ids.append(item.id)
|
||||
else:
|
||||
oauth_id = generate_id()
|
||||
update_redis_ids.append(oauth_id)
|
||||
db.add(UserOAuth(
|
||||
id=oauth_id,
|
||||
account_id=str(account_id),
|
||||
account_id=aid,
|
||||
account_name=account.get("account_name", ""),
|
||||
account_role=account.get("account_role", ""),
|
||||
account_username=account_username,
|
||||
account_userid = account_userid,
|
||||
account_userid=account_userid,
|
||||
user_id=user_id,
|
||||
appid=app_id,
|
||||
open_type=open_type,
|
||||
port_type=1,
|
||||
access_token = access_token,
|
||||
access_token_expired=expires_in,
|
||||
access_token=access_token,
|
||||
access_token_expired=access_expired,
|
||||
refresh_token=refresh_token,
|
||||
refresh_token_expired=refresh_token_expires_in,
|
||||
refresh_token_expired=refresh_expired,
|
||||
material_auth_status=material_auth_status,
|
||||
))
|
||||
await db.commit()
|
||||
|
||||
for oauth_id in update_redis_ids:
|
||||
await _update_redis_token(oauth_id, access_token, expires_in)
|
||||
await db.commit()
|
||||
# 更新有效账号缓存
|
||||
for oid in update_redis_ids:
|
||||
await _update_redis_token(oid, access_token, access_expired)
|
||||
|
||||
#5.本次更新成功以后,判断是否有其他同一个appid,同一个授权登录账号的授权记录,如果有,则更新token信息
|
||||
from sqlalchemy import update
|
||||
|
||||
related_oauths = await db.execute(
|
||||
select(UserOAuth).where(
|
||||
# 5. 同登录账号、同应用、其他用户下的授权批量同步最新token
|
||||
related_query = select(UserOAuth).where(
|
||||
UserOAuth.account_username == account_username,
|
||||
UserOAuth.account_userid == account_userid,
|
||||
UserOAuth.appid == app_id,
|
||||
UserOAuth.user_id != user_id,
|
||||
UserOAuth.deleted_at.is_(None),
|
||||
)
|
||||
)
|
||||
related_oauths = related_oauths.scalars().all()
|
||||
|
||||
if related_oauths:
|
||||
await db.execute(
|
||||
update(UserOAuth).where(
|
||||
UserOAuth.account_username == account_username,
|
||||
UserOAuth.account_userid == account_userid,
|
||||
UserOAuth.appid == app_id,
|
||||
UserOAuth.user_id != user_id,
|
||||
UserOAuth.deleted_at.is_(None),
|
||||
).values(
|
||||
access_token=access_token,
|
||||
access_token_expired=expires_in,
|
||||
refresh_token=refresh_token,
|
||||
refresh_token_expired=refresh_token_expires_in,
|
||||
material_auth_status=material_auth_status,
|
||||
related_res = await db.execute(related_query)
|
||||
related_list = related_res.scalars().all()
|
||||
if related_list:
|
||||
await db.execute(
|
||||
update(UserOAuth).where(
|
||||
UserOAuth.account_username == account_username,
|
||||
UserOAuth.account_userid == account_userid,
|
||||
UserOAuth.appid == app_id,
|
||||
UserOAuth.user_id != user_id,
|
||||
UserOAuth.deleted_at.is_(None),
|
||||
).values(
|
||||
access_token=access_token,
|
||||
access_token_expired=access_expired,
|
||||
refresh_token=refresh_token,
|
||||
refresh_token_expired=refresh_expired,
|
||||
material_auth_status=material_auth_status,
|
||||
)
|
||||
)
|
||||
)
|
||||
await db.commit()
|
||||
|
||||
for related_oauth in related_oauths:
|
||||
await _update_redis_token(related_oauth.id, access_token, expires_in)
|
||||
await db.commit()
|
||||
for item in related_list:
|
||||
await _update_redis_token(item.id, access_token, access_expired)
|
||||
|
||||
return {"message": "授权成功"}
|
||||
|
||||
except httpx.HTTPError as e:
|
||||
raise ValueError(f"第三方接口请求异常:{str(e)}")
|
||||
except Exception as e:
|
||||
raise ValueError(f"授权处理异常:{str(e)}")
|
||||
|
||||
return {"message": "授权成功"}
|
||||
|
||||
async def get_kuaishou_token(app_id: str, secret: str, code: str, oauth_type: int, user_id: str, db: AsyncSession) -> dict:
|
||||
return "未配置"
|
||||
return {"message": "快手渠道暂未实现授权逻辑"}
|
||||
|
||||
|
||||
async def get_tencent_token(app_id: str, secret: str, code: str, oauth_type: int, user_id: str, db: AsyncSession) -> str:
|
||||
return "未配置"
|
||||
return "腾讯营销渠道暂未实现授权逻辑"
|
||||
|
||||
|
||||
async def get_oauth_list(
|
||||
@@ -318,36 +324,35 @@ async def get_oauth_list(
|
||||
page: int = 1,
|
||||
page_size: int = 10,
|
||||
) -> dict:
|
||||
if page < 1:
|
||||
page = 1
|
||||
if page_size < 1:
|
||||
page_size = 10
|
||||
# 分页参数容错
|
||||
page = max(page, 1)
|
||||
page_size = max(min(page_size, 100), 1)
|
||||
|
||||
query = select(UserOAuth).where(
|
||||
base_where = [
|
||||
UserOAuth.user_id == user_id,
|
||||
UserOAuth.deleted_at.is_(None),
|
||||
)
|
||||
|
||||
]
|
||||
if account_userid:
|
||||
query = query.where(UserOAuth.account_userid == account_userid)
|
||||
base_where.append(UserOAuth.account_userid == account_userid)
|
||||
if open_type:
|
||||
query = query.where(UserOAuth.open_type == open_type)
|
||||
base_where.append(UserOAuth.open_type == open_type)
|
||||
if account_id:
|
||||
query = query.where(UserOAuth.account_id == account_id)
|
||||
base_where.append(UserOAuth.account_id == account_id)
|
||||
|
||||
query = query.order_by(UserOAuth.created_at.desc())
|
||||
# 统计总条数(优化:使用count,避免全量查询)
|
||||
count_stmt = select(func.count(UserOAuth.id)).where(*base_where)
|
||||
total = await db.scalar(count_stmt) or 0
|
||||
|
||||
total_result = await db.execute(query.with_only_columns(UserOAuth.id))
|
||||
total = len(total_result.scalars().all())
|
||||
|
||||
offset = (page - 1) * page_size
|
||||
query = query.offset(offset).limit(page_size)
|
||||
|
||||
result = await db.execute(query)
|
||||
oauth_list = result.scalars().all()
|
||||
# 分页查询数据
|
||||
data_stmt = select(UserOAuth).where(*base_where)\
|
||||
.order_by(UserOAuth.created_at.desc())\
|
||||
.offset((page - 1) * page_size)\
|
||||
.limit(page_size)
|
||||
result = await db.execute(data_stmt)
|
||||
data_list = result.scalars().all()
|
||||
|
||||
return {
|
||||
"data": oauth_list,
|
||||
"data": data_list,
|
||||
"total": total,
|
||||
"page": page,
|
||||
"page_size": page_size,
|
||||
|
||||
@@ -30,7 +30,7 @@ def _log_video_request(engine: ProviderVideoEngineLike, record_id: str, request_
|
||||
today = datetime.now().strftime(LOG_DATE_FORMAT)
|
||||
log_file = os.path.join(LOG_DIR, f"{today}.log")
|
||||
request_str = json.dumps(request_data, ensure_ascii=False)
|
||||
request_encrypted = encrypt_data(request_data)
|
||||
request_encrypted = encrypt_data(request_data, True)
|
||||
entry = {
|
||||
"timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
|
||||
"type": "video_gen_request",
|
||||
@@ -54,7 +54,7 @@ def _log_video_response(record_id: str, response_data: dict, error: str | None =
|
||||
os.makedirs(LOG_DIR, exist_ok=True)
|
||||
today = datetime.now().strftime(LOG_DATE_FORMAT)
|
||||
log_file = os.path.join(LOG_DIR, f"{today}.log")
|
||||
response_encrypted = encrypt_data(response_data) if response_data else ""
|
||||
response_encrypted = encrypt_data(response_data, True) if response_data else ""
|
||||
|
||||
entry = {
|
||||
"timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
|
||||
|
||||
Reference in New Issue
Block a user