245 lines
9.7 KiB
Python
245 lines
9.7 KiB
Python
from flask import request, jsonify, current_app
|
|
from . import api_bp
|
|
from .license import require_admin
|
|
import os
|
|
|
|
# 系统设置配置项映射
|
|
CONFIG_MAPPING = {
|
|
# 基本设置
|
|
'site_name': 'SITE_NAME',
|
|
'admin_email': 'ADMIN_EMAIL',
|
|
'frontend_domain': 'FRONTEND_DOMAIN',
|
|
'max_failed_attempts': 'MAX_FAILED_ATTEMPTS',
|
|
'lockout_minutes': 'LOCKOUT_MINUTES',
|
|
'max_unbind_times': 'MAX_UNBIND_TIMES',
|
|
'auth_secret_key': 'AUTH_SECRET_KEY',
|
|
|
|
# 安全设置
|
|
'secret_key': 'SECRET_KEY',
|
|
'session_cookie_secure': 'SESSION_COOKIE_SECURE',
|
|
'session_cookie_httponly': 'SESSION_COOKIE_HTTPONLY',
|
|
'session_cookie_samesite': 'SESSION_COOKIE_SAMESITE',
|
|
|
|
# 卡密设置
|
|
'license_key_length': 'LICENSE_KEY_LENGTH',
|
|
'license_key_prefix': 'LICENSE_KEY_PREFIX',
|
|
'trial_prefix': 'TRIAL_PREFIX',
|
|
'offline_cache_days': 'OFFLINE_CACHE_DAYS',
|
|
|
|
# API设置
|
|
'api_version': 'API_VERSION',
|
|
'items_per_page': 'ITEMS_PER_PAGE',
|
|
|
|
# 文件上传设置
|
|
'max_content_length': 'MAX_CONTENT_LENGTH',
|
|
'upload_folder': 'UPLOAD_FOLDER',
|
|
|
|
# 会话设置
|
|
'session_lifetime_hours': 'SESSION_LIFETIME_HOURS',
|
|
|
|
# 记住我设置
|
|
'remember_cookie_duration': 'REMEMBER_COOKIE_DURATION_DAYS', # 特殊处理
|
|
'remember_cookie_secure': 'REMEMBER_COOKIE_SECURE',
|
|
'remember_cookie_httponly': 'REMEMBER_COOKIE_HTTPONLY',
|
|
'remember_cookie_samesite': 'REMEMBER_COOKIE_SAMESITE',
|
|
|
|
# 日志设置
|
|
'log_level': 'LOG_LEVEL',
|
|
|
|
# 支付设置
|
|
'alipay_app_id': 'ALIPAY_APP_ID',
|
|
'alipay_private_key': 'ALIPAY_PRIVATE_KEY',
|
|
'alipay_public_key': 'ALIPAY_PUBLIC_KEY',
|
|
'alipay_alipay_public_key': 'ALIPAY_ALIPAY_PUBLIC_KEY',
|
|
'alipay_gateway': 'ALIPAY_GATEWAY',
|
|
'alipay_sign_type': 'ALIPAY_SIGN_TYPE',
|
|
'alipay_charset': 'ALIPAY_CHARSET',
|
|
'alipay_version': 'ALIPAY_VERSION',
|
|
'alipay_notify_url': 'ALIPAY_NOTIFY_URL',
|
|
'alipay_return_url': 'ALIPAY_RETURN_URL',
|
|
'alipay_timeout_express': 'ALIPAY_TIMEOUT_EXPRESS',
|
|
'payment_enabled': 'PAYMENT_ENABLED'
|
|
}
|
|
|
|
@require_admin
|
|
@api_bp.route('/settings/test-payment', methods=['POST'])
|
|
def test_payment():
|
|
"""测试支付功能"""
|
|
try:
|
|
# 获取当前配置
|
|
config = current_app.config
|
|
|
|
# 检查支付功能是否启用
|
|
if not config.get('PAYMENT_ENABLED'):
|
|
return jsonify({'success': False, 'message': '支付功能未启用'}), 400
|
|
|
|
# 检查支付宝配置
|
|
required_configs = ['ALIPAY_APP_ID', 'ALIPAY_PRIVATE_KEY', 'ALIPAY_PUBLIC_KEY', 'ALIPAY_ALIPAY_PUBLIC_KEY']
|
|
missing_configs = [cfg for cfg in required_configs if not config.get(cfg)]
|
|
if missing_configs:
|
|
return jsonify({'success': False, 'message': f'缺少支付宝配置: {", ".join(missing_configs)}'}), 400
|
|
|
|
# 创建测试订单
|
|
try:
|
|
from app.utils.alipay import AlipayHelper
|
|
from app.models import Order
|
|
import time
|
|
import random
|
|
|
|
# 初始化支付宝助手
|
|
alipay_helper = AlipayHelper(current_app)
|
|
|
|
# 生成测试订单号
|
|
test_order_number = f"TEST{int(time.time())}{random.randint(100, 999)}"
|
|
|
|
# 创建支付链接
|
|
notify_url = config.get('ALIPAY_NOTIFY_URL') or f"{request.url_root.strip('/')}/api/v1/pay/alipay/notify"
|
|
return_url = config.get('ALIPAY_RETURN_URL') or f"{request.url_root.strip('/')}/payment/result"
|
|
|
|
payment_url = alipay_helper.create_payment_url(
|
|
order_number=test_order_number,
|
|
amount=0.01, # 测试金额
|
|
subject='支付功能测试',
|
|
notify_url=notify_url,
|
|
return_url=return_url
|
|
)
|
|
|
|
current_app.logger.info(f"支付功能测试成功,订单号: {test_order_number}")
|
|
|
|
return jsonify({
|
|
'success': True,
|
|
'message': '支付功能测试成功!',
|
|
'payment_url': payment_url,
|
|
'order_number': test_order_number
|
|
})
|
|
|
|
except Exception as e:
|
|
current_app.logger.error(f"创建支付链接失败: {str(e)}")
|
|
return jsonify({'success': False, 'message': f'创建支付链接失败: {str(e)}'}), 400
|
|
|
|
except Exception as e:
|
|
current_app.logger.error(f"测试支付功能失败: {str(e)}")
|
|
return jsonify({'success': False, 'message': '服务器内部错误'}), 500
|
|
|
|
|
|
@require_admin
|
|
@api_bp.route('/settings/test-alipay', methods=['POST'])
|
|
def test_alipay_config():
|
|
"""测试支付宝配置"""
|
|
try:
|
|
data = request.get_json()
|
|
if not data:
|
|
return jsonify({'success': False, 'message': '请求数据为空'}), 400
|
|
|
|
# 获取配置参数
|
|
alipay_app_id = data.get('alipay_app_id')
|
|
alipay_private_key = data.get('alipay_private_key')
|
|
alipay_public_key = data.get('alipay_public_key')
|
|
alipay_alipay_public_key = data.get('alipay_alipay_public_key')
|
|
alipay_gateway = data.get('alipay_gateway', 'https://openapi.alipay.com/gateway.do')
|
|
|
|
# 验证必填项
|
|
if not all([alipay_app_id, alipay_private_key, alipay_public_key, alipay_alipay_public_key]):
|
|
return jsonify({'success': False, 'message': '请填写完整的支付宝配置信息'}), 400
|
|
|
|
# 验证基本参数
|
|
if not alipay_app_id or len(alipay_app_id) < 10:
|
|
return jsonify({'success': False, 'message': '无效的APP_ID'}), 400
|
|
|
|
# 验证密钥格式
|
|
if 'BEGIN' not in alipay_private_key or 'END' not in alipay_private_key:
|
|
return jsonify({'success': False, 'message': '私钥格式不正确'}), 400
|
|
|
|
if 'BEGIN' not in alipay_public_key or 'END' not in alipay_public_key:
|
|
return jsonify({'success': False, 'message': '公钥格式不正确'}), 400
|
|
|
|
if 'BEGIN' not in alipay_alipay_public_key or 'END' not in alipay_alipay_public_key:
|
|
return jsonify({'success': False, 'message': '支付宝公钥格式不正确'}), 400
|
|
|
|
# 如果所有验证通过,返回成功
|
|
return jsonify({
|
|
'success': True,
|
|
'message': '支付宝配置测试成功!',
|
|
'details': {
|
|
'app_id': alipay_app_id,
|
|
'gateway': alipay_gateway,
|
|
'sign_type': 'RSA2'
|
|
}
|
|
})
|
|
|
|
except Exception as e:
|
|
current_app.logger.error(f"测试支付宝配置失败: {str(e)}")
|
|
return jsonify({'success': False, 'message': '服务器内部错误'}), 500
|
|
|
|
|
|
@require_admin
|
|
@api_bp.route('/settings', methods=['POST'])
|
|
def save_settings():
|
|
"""保存系统设置"""
|
|
try:
|
|
data = request.get_json()
|
|
if not data:
|
|
return jsonify({'success': False, 'message': '请求数据为空'}), 400
|
|
|
|
# 获取当前应用配置
|
|
app_config = current_app.config
|
|
|
|
# 更新配置项
|
|
updated_configs = {}
|
|
for key, value in data.items():
|
|
if key in CONFIG_MAPPING:
|
|
config_key = CONFIG_MAPPING[key]
|
|
# 类型转换
|
|
if key in ['max_failed_attempts', 'lockout_minutes', 'max_unbind_times',
|
|
'license_key_length', 'offline_cache_days', 'items_per_page',
|
|
'session_lifetime_hours', 'remember_cookie_duration']:
|
|
value = int(value)
|
|
elif key in ['session_cookie_secure', 'session_cookie_httponly',
|
|
'remember_cookie_secure', 'remember_cookie_httponly']:
|
|
# 转换布尔值
|
|
value = value is True or value == 'True' or value == 'true'
|
|
elif key == 'max_content_length':
|
|
# 转换为字节
|
|
value = int(value) * 1024 * 1024
|
|
elif key == 'session_lifetime_hours':
|
|
# 转换为秒
|
|
value = int(value) * 3600
|
|
elif key in ['alipay_timeout_express']:
|
|
# 支付超时时间,转换为分钟
|
|
value = int(value)
|
|
elif key in ['payment_enabled']:
|
|
# 支付开关
|
|
value = value is True or value == 'True' or value == 'true'
|
|
elif key in ['alipay_sign_type', 'alipay_charset', 'alipay_version']:
|
|
# 支付相关字符串配置
|
|
pass # 保持原值
|
|
# 注意:密钥类配置(私钥、公钥等)不进行类型转换,直接保存
|
|
|
|
# 更新配置
|
|
app_config[config_key] = value
|
|
updated_configs[config_key] = value
|
|
|
|
# 特殊处理会话生命周期
|
|
if 'SESSION_LIFETIME_HOURS' in updated_configs:
|
|
from datetime import timedelta
|
|
app_config['PERMANENT_SESSION_LIFETIME'] = timedelta(seconds=updated_configs['SESSION_LIFETIME_HOURS'])
|
|
|
|
# 特殊处理记住我持续时间
|
|
if 'REMEMBER_COOKIE_DURATION_DAYS' in updated_configs:
|
|
from datetime import timedelta
|
|
app_config['REMEMBER_COOKIE_DURATION'] = timedelta(days=updated_configs['REMEMBER_COOKIE_DURATION_DAYS'])
|
|
|
|
# 特殊处理SECRET_KEY
|
|
if 'SECRET_KEY' in updated_configs:
|
|
# 更新应用的SECRET_KEY
|
|
app_config['SECRET_KEY'] = updated_configs['SECRET_KEY']
|
|
|
|
return jsonify({
|
|
'success': True,
|
|
'message': '设置保存成功',
|
|
'updated_configs': updated_configs
|
|
})
|
|
|
|
except Exception as e:
|
|
current_app.logger.error(f"保存设置失败: {str(e)}")
|
|
return jsonify({'success': False, 'message': '服务器内部错误'}), 500 |