mirror of
https://github.com/cnlimiter/codex-register.git
synced 2026-05-11 10:00:11 +08:00
feat(config): 添加随机用户信息生成函数并改进代理配置
This commit is contained in:
@@ -13,6 +13,7 @@ from .constants import (
|
|||||||
DEFAULT_PASSWORD_LENGTH,
|
DEFAULT_PASSWORD_LENGTH,
|
||||||
PASSWORD_CHARSET,
|
PASSWORD_CHARSET,
|
||||||
DEFAULT_USER_INFO,
|
DEFAULT_USER_INFO,
|
||||||
|
generate_random_user_info,
|
||||||
OPENAI_API_ENDPOINTS,
|
OPENAI_API_ENDPOINTS,
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -30,5 +31,6 @@ __all__ = [
|
|||||||
'DEFAULT_PASSWORD_LENGTH',
|
'DEFAULT_PASSWORD_LENGTH',
|
||||||
'PASSWORD_CHARSET',
|
'PASSWORD_CHARSET',
|
||||||
'DEFAULT_USER_INFO',
|
'DEFAULT_USER_INFO',
|
||||||
|
'generate_random_user_info',
|
||||||
'OPENAI_API_ENDPOINTS',
|
'OPENAI_API_ENDPOINTS',
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -2,6 +2,8 @@
|
|||||||
常量定义
|
常量定义
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import random
|
||||||
|
from datetime import datetime
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
from typing import Dict, List, Tuple
|
from typing import Dict, List, Tuple
|
||||||
|
|
||||||
@@ -120,7 +122,48 @@ OTP_MAX_ATTEMPTS = 40 # 最大轮询次数
|
|||||||
PASSWORD_CHARSET = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
|
PASSWORD_CHARSET = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
|
||||||
DEFAULT_PASSWORD_LENGTH = 12
|
DEFAULT_PASSWORD_LENGTH = 12
|
||||||
|
|
||||||
# 用户信息(用于注册)
|
# 用户信息生成(用于注册)
|
||||||
|
|
||||||
|
# 常用英文名
|
||||||
|
FIRST_NAMES = [
|
||||||
|
"James", "John", "Robert", "Michael", "William", "David", "Richard", "Joseph", "Thomas", "Charles",
|
||||||
|
"Emma", "Olivia", "Ava", "Isabella", "Sophia", "Mia", "Charlotte", "Amelia", "Harper", "Evelyn",
|
||||||
|
"Alex", "Jordan", "Taylor", "Morgan", "Casey", "Riley", "Jamie", "Avery", "Quinn", "Skyler",
|
||||||
|
"Liam", "Noah", "Ethan", "Lucas", "Mason", "Oliver", "Elijah", "Aiden", "Henry", "Sebastian",
|
||||||
|
"Grace", "Lily", "Chloe", "Zoey", "Nora", "Aria", "Hazel", "Aurora", "Stella", "Ivy"
|
||||||
|
]
|
||||||
|
|
||||||
|
def generate_random_user_info() -> dict:
|
||||||
|
"""
|
||||||
|
生成随机用户信息
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
包含 name 和 birthdate 的字典
|
||||||
|
"""
|
||||||
|
# 随机选择名字
|
||||||
|
name = random.choice(FIRST_NAMES)
|
||||||
|
|
||||||
|
# 生成随机生日(18-45岁)
|
||||||
|
current_year = datetime.now().year
|
||||||
|
birth_year = random.randint(current_year - 45, current_year - 18)
|
||||||
|
birth_month = random.randint(1, 12)
|
||||||
|
# 根据月份确定天数
|
||||||
|
if birth_month in [1, 3, 5, 7, 8, 10, 12]:
|
||||||
|
birth_day = random.randint(1, 31)
|
||||||
|
elif birth_month in [4, 6, 9, 11]:
|
||||||
|
birth_day = random.randint(1, 30)
|
||||||
|
else:
|
||||||
|
# 2月,简化处理
|
||||||
|
birth_day = random.randint(1, 28)
|
||||||
|
|
||||||
|
birthdate = f"{birth_year}-{birth_month:02d}-{birth_day:02d}"
|
||||||
|
|
||||||
|
return {
|
||||||
|
"name": name,
|
||||||
|
"birthdate": birthdate
|
||||||
|
}
|
||||||
|
|
||||||
|
# 保留默认值供兼容
|
||||||
DEFAULT_USER_INFO = {
|
DEFAULT_USER_INFO = {
|
||||||
"name": "Neo",
|
"name": "Neo",
|
||||||
"birthdate": "2000-02-20",
|
"birthdate": "2000-02-20",
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ from ..database import crud
|
|||||||
from ..database.session import get_db
|
from ..database.session import get_db
|
||||||
from ..config.constants import (
|
from ..config.constants import (
|
||||||
OPENAI_API_ENDPOINTS,
|
OPENAI_API_ENDPOINTS,
|
||||||
DEFAULT_USER_INFO,
|
generate_random_user_info,
|
||||||
OTP_CODE_PATTERN,
|
OTP_CODE_PATTERN,
|
||||||
DEFAULT_PASSWORD_LENGTH,
|
DEFAULT_PASSWORD_LENGTH,
|
||||||
PASSWORD_CHARSET,
|
PASSWORD_CHARSET,
|
||||||
@@ -372,7 +372,9 @@ class RegistrationEngine:
|
|||||||
def _create_user_account(self) -> bool:
|
def _create_user_account(self) -> bool:
|
||||||
"""创建用户账户"""
|
"""创建用户账户"""
|
||||||
try:
|
try:
|
||||||
create_account_body = json.dumps(DEFAULT_USER_INFO)
|
user_info = generate_random_user_info()
|
||||||
|
self._log(f"生成用户信息: {user_info['name']}, 生日: {user_info['birthdate']}")
|
||||||
|
create_account_body = json.dumps(user_info)
|
||||||
|
|
||||||
response = self.session.post(
|
response = self.session.post(
|
||||||
OPENAI_API_ENDPOINTS["create_account"],
|
OPENAI_API_ENDPOINTS["create_account"],
|
||||||
|
|||||||
@@ -370,13 +370,26 @@ class OutlookService(BaseEmailService):
|
|||||||
self._current_account_index = 0
|
self._current_account_index = 0
|
||||||
self._account_locks: Dict[str, threading.Lock] = {}
|
self._account_locks: Dict[str, threading.Lock] = {}
|
||||||
|
|
||||||
for account_config in self.config.get("accounts", []):
|
# 支持两种配置格式:
|
||||||
account = OutlookAccount.from_config(account_config)
|
# 1. 单个账户格式:{"email": "xxx", "password": "xxx"}
|
||||||
|
# 2. 多账户格式:{"accounts": [{"email": "xxx", "password": "xxx"}]}
|
||||||
|
if "email" in self.config and "password" in self.config:
|
||||||
|
# 单个账户格式
|
||||||
|
account = OutlookAccount.from_config(self.config)
|
||||||
if account.validate():
|
if account.validate():
|
||||||
self.accounts.append(account)
|
self.accounts.append(account)
|
||||||
self._account_locks[account.email] = threading.Lock()
|
self._account_locks[account.email] = threading.Lock()
|
||||||
else:
|
else:
|
||||||
logger.warning(f"无效的 Outlook 账户配置: {account_config}")
|
logger.warning(f"无效的 Outlook 账户配置: {self.config}")
|
||||||
|
else:
|
||||||
|
# 多账户格式
|
||||||
|
for account_config in self.config.get("accounts", []):
|
||||||
|
account = OutlookAccount.from_config(account_config)
|
||||||
|
if account.validate():
|
||||||
|
self.accounts.append(account)
|
||||||
|
self._account_locks[account.email] = threading.Lock()
|
||||||
|
else:
|
||||||
|
logger.warning(f"无效的 Outlook 账户配置: {account_config}")
|
||||||
|
|
||||||
if not self.accounts:
|
if not self.accounts:
|
||||||
logger.warning("未配置有效的 Outlook 账户")
|
logger.warning("未配置有效的 Outlook 账户")
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ from ...database import crud
|
|||||||
from ...database.session import get_db
|
from ...database.session import get_db
|
||||||
from ...database.models import Account
|
from ...database.models import Account
|
||||||
from ...config.constants import AccountStatus
|
from ...config.constants import AccountStatus
|
||||||
|
from ...config.settings import get_settings
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
router = APIRouter()
|
router = APIRouter()
|
||||||
@@ -417,7 +418,8 @@ async def refresh_account_token(account_id: int, request: TokenRefreshRequest =
|
|||||||
"""刷新单个账号的 Token"""
|
"""刷新单个账号的 Token"""
|
||||||
from ...core.token_refresh import refresh_account_token as do_refresh
|
from ...core.token_refresh import refresh_account_token as do_refresh
|
||||||
|
|
||||||
proxy = request.proxy if request else None
|
# 使用传入的代理或全局代理配置
|
||||||
|
proxy = request.proxy if request and request.proxy else get_settings().proxy_url
|
||||||
result = do_refresh(account_id, proxy)
|
result = do_refresh(account_id, proxy)
|
||||||
|
|
||||||
if result.success:
|
if result.success:
|
||||||
@@ -438,6 +440,9 @@ async def batch_refresh_tokens(request: BatchRefreshRequest, background_tasks: B
|
|||||||
"""批量刷新账号 Token"""
|
"""批量刷新账号 Token"""
|
||||||
from ...core.token_refresh import refresh_account_token as do_refresh
|
from ...core.token_refresh import refresh_account_token as do_refresh
|
||||||
|
|
||||||
|
# 使用传入的代理或全局代理配置
|
||||||
|
proxy = request.proxy if request.proxy else get_settings().proxy_url
|
||||||
|
|
||||||
results = {
|
results = {
|
||||||
"success_count": 0,
|
"success_count": 0,
|
||||||
"failed_count": 0,
|
"failed_count": 0,
|
||||||
@@ -446,7 +451,7 @@ async def batch_refresh_tokens(request: BatchRefreshRequest, background_tasks: B
|
|||||||
|
|
||||||
for account_id in request.ids:
|
for account_id in request.ids:
|
||||||
try:
|
try:
|
||||||
result = do_refresh(account_id, request.proxy)
|
result = do_refresh(account_id, proxy)
|
||||||
if result.success:
|
if result.success:
|
||||||
results["success_count"] += 1
|
results["success_count"] += 1
|
||||||
else:
|
else:
|
||||||
@@ -464,7 +469,8 @@ async def validate_account_token(account_id: int, request: TokenValidateRequest
|
|||||||
"""验证单个账号的 Token 有效性"""
|
"""验证单个账号的 Token 有效性"""
|
||||||
from ...core.token_refresh import validate_account_token as do_validate
|
from ...core.token_refresh import validate_account_token as do_validate
|
||||||
|
|
||||||
proxy = request.proxy if request else None
|
# 使用传入的代理或全局代理配置
|
||||||
|
proxy = request.proxy if request and request.proxy else get_settings().proxy_url
|
||||||
is_valid, error = do_validate(account_id, proxy)
|
is_valid, error = do_validate(account_id, proxy)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -479,6 +485,9 @@ async def batch_validate_tokens(request: BatchValidateRequest):
|
|||||||
"""批量验证账号 Token 有效性"""
|
"""批量验证账号 Token 有效性"""
|
||||||
from ...core.token_refresh import validate_account_token as do_validate
|
from ...core.token_refresh import validate_account_token as do_validate
|
||||||
|
|
||||||
|
# 使用传入的代理或全局代理配置
|
||||||
|
proxy = request.proxy if request.proxy else get_settings().proxy_url
|
||||||
|
|
||||||
results = {
|
results = {
|
||||||
"valid_count": 0,
|
"valid_count": 0,
|
||||||
"invalid_count": 0,
|
"invalid_count": 0,
|
||||||
@@ -487,7 +496,7 @@ async def batch_validate_tokens(request: BatchValidateRequest):
|
|||||||
|
|
||||||
for account_id in request.ids:
|
for account_id in request.ids:
|
||||||
try:
|
try:
|
||||||
is_valid, error = do_validate(account_id, request.proxy)
|
is_valid, error = do_validate(account_id, proxy)
|
||||||
results["details"].append({
|
results["details"].append({
|
||||||
"id": account_id,
|
"id": account_id,
|
||||||
"valid": is_valid,
|
"valid": is_valid,
|
||||||
|
|||||||
@@ -228,6 +228,27 @@ async def get_email_service(service_id: int):
|
|||||||
return service_to_response(service)
|
return service_to_response(service)
|
||||||
|
|
||||||
|
|
||||||
|
@router.get("/{service_id}/full")
|
||||||
|
async def get_email_service_full(service_id: int):
|
||||||
|
"""获取单个邮箱服务完整详情(包含敏感字段,用于编辑)"""
|
||||||
|
with get_db() as db:
|
||||||
|
service = db.query(EmailServiceModel).filter(EmailServiceModel.id == service_id).first()
|
||||||
|
if not service:
|
||||||
|
raise HTTPException(status_code=404, detail="服务不存在")
|
||||||
|
|
||||||
|
return {
|
||||||
|
"id": service.id,
|
||||||
|
"service_type": service.service_type,
|
||||||
|
"name": service.name,
|
||||||
|
"enabled": service.enabled,
|
||||||
|
"priority": service.priority,
|
||||||
|
"config": service.config or {}, # 返回完整配置
|
||||||
|
"last_used": service.last_used.isoformat() if service.last_used else None,
|
||||||
|
"created_at": service.created_at.isoformat() if service.created_at else None,
|
||||||
|
"updated_at": service.updated_at.isoformat() if service.updated_at else None,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@router.post("", response_model=EmailServiceResponse)
|
@router.post("", response_model=EmailServiceResponse)
|
||||||
async def create_email_service(request: EmailServiceCreate):
|
async def create_email_service(request: EmailServiceCreate):
|
||||||
"""创建邮箱服务配置"""
|
"""创建邮箱服务配置"""
|
||||||
@@ -269,7 +290,12 @@ async def update_email_service(service_id: int, request: EmailServiceUpdate):
|
|||||||
if request.name is not None:
|
if request.name is not None:
|
||||||
update_data["name"] = request.name
|
update_data["name"] = request.name
|
||||||
if request.config is not None:
|
if request.config is not None:
|
||||||
update_data["config"] = request.config
|
# 合并配置而不是替换
|
||||||
|
current_config = service.config or {}
|
||||||
|
merged_config = {**current_config, **request.config}
|
||||||
|
# 移除空值
|
||||||
|
merged_config = {k: v for k, v in merged_config.items() if v}
|
||||||
|
update_data["config"] = merged_config
|
||||||
if request.enabled is not None:
|
if request.enabled is not None:
|
||||||
update_data["enabled"] = request.enabled
|
update_data["enabled"] = request.enabled
|
||||||
if request.priority is not None:
|
if request.priority is not None:
|
||||||
|
|||||||
@@ -42,11 +42,23 @@ const elements = {
|
|||||||
tempmailEnabled: document.getElementById('tempmail-enabled'),
|
tempmailEnabled: document.getElementById('tempmail-enabled'),
|
||||||
testTempmailBtn: document.getElementById('test-tempmail-btn'),
|
testTempmailBtn: document.getElementById('test-tempmail-btn'),
|
||||||
|
|
||||||
// 模态框
|
// 添加自定义域名模态框
|
||||||
addCustomModal: document.getElementById('add-custom-modal'),
|
addCustomModal: document.getElementById('add-custom-modal'),
|
||||||
addCustomForm: document.getElementById('add-custom-form'),
|
addCustomForm: document.getElementById('add-custom-form'),
|
||||||
closeCustomModal: document.getElementById('close-custom-modal'),
|
closeCustomModal: document.getElementById('close-custom-modal'),
|
||||||
cancelAddCustom: document.getElementById('cancel-add-custom')
|
cancelAddCustom: document.getElementById('cancel-add-custom'),
|
||||||
|
|
||||||
|
// 编辑自定义域名模态框
|
||||||
|
editCustomModal: document.getElementById('edit-custom-modal'),
|
||||||
|
editCustomForm: document.getElementById('edit-custom-form'),
|
||||||
|
closeEditCustomModal: document.getElementById('close-edit-custom-modal'),
|
||||||
|
cancelEditCustom: document.getElementById('cancel-edit-custom'),
|
||||||
|
|
||||||
|
// 编辑 Outlook 模态框
|
||||||
|
editOutlookModal: document.getElementById('edit-outlook-modal'),
|
||||||
|
editOutlookForm: document.getElementById('edit-outlook-form'),
|
||||||
|
closeEditOutlookModal: document.getElementById('close-edit-outlook-modal'),
|
||||||
|
cancelEditOutlook: document.getElementById('cancel-edit-outlook')
|
||||||
};
|
};
|
||||||
|
|
||||||
// 初始化
|
// 初始化
|
||||||
@@ -107,6 +119,28 @@ function initEventListeners() {
|
|||||||
|
|
||||||
elements.addCustomForm.addEventListener('submit', handleAddCustom);
|
elements.addCustomForm.addEventListener('submit', handleAddCustom);
|
||||||
|
|
||||||
|
// 编辑自定义域名模态框
|
||||||
|
elements.closeEditCustomModal.addEventListener('click', () => {
|
||||||
|
elements.editCustomModal.classList.remove('active');
|
||||||
|
});
|
||||||
|
|
||||||
|
elements.cancelEditCustom.addEventListener('click', () => {
|
||||||
|
elements.editCustomModal.classList.remove('active');
|
||||||
|
});
|
||||||
|
|
||||||
|
elements.editCustomForm.addEventListener('submit', handleEditCustom);
|
||||||
|
|
||||||
|
// 编辑 Outlook 模态框
|
||||||
|
elements.closeEditOutlookModal.addEventListener('click', () => {
|
||||||
|
elements.editOutlookModal.classList.remove('active');
|
||||||
|
});
|
||||||
|
|
||||||
|
elements.cancelEditOutlook.addEventListener('click', () => {
|
||||||
|
elements.editOutlookModal.classList.remove('active');
|
||||||
|
});
|
||||||
|
|
||||||
|
elements.editOutlookForm.addEventListener('submit', handleEditOutlook);
|
||||||
|
|
||||||
// 自定义域名全选
|
// 自定义域名全选
|
||||||
elements.selectAllCustom.addEventListener('change', (e) => {
|
elements.selectAllCustom.addEventListener('change', (e) => {
|
||||||
const checkboxes = elements.customTable.querySelectorAll('input[type="checkbox"][data-id]');
|
const checkboxes = elements.customTable.querySelectorAll('input[type="checkbox"][data-id]');
|
||||||
@@ -181,6 +215,9 @@ async function loadOutlookServices() {
|
|||||||
<td>${format.date(service.last_used)}</td>
|
<td>${format.date(service.last_used)}</td>
|
||||||
<td>
|
<td>
|
||||||
<div class="action-buttons">
|
<div class="action-buttons">
|
||||||
|
<button class="btn btn-ghost btn-sm" onclick="editOutlookService(${service.id})" title="编辑">
|
||||||
|
✏️
|
||||||
|
</button>
|
||||||
<button class="btn btn-ghost btn-sm" onclick="toggleService(${service.id}, ${!service.enabled})" title="${service.enabled ? '禁用' : '启用'}">
|
<button class="btn btn-ghost btn-sm" onclick="toggleService(${service.id}, ${!service.enabled})" title="${service.enabled ? '禁用' : '启用'}">
|
||||||
${service.enabled ? '🔇' : '🔊'}
|
${service.enabled ? '🔇' : '🔊'}
|
||||||
</button>
|
</button>
|
||||||
@@ -261,6 +298,9 @@ async function loadCustomServices() {
|
|||||||
<td>${format.date(service.last_used)}</td>
|
<td>${format.date(service.last_used)}</td>
|
||||||
<td>
|
<td>
|
||||||
<div class="action-buttons">
|
<div class="action-buttons">
|
||||||
|
<button class="btn btn-ghost btn-sm" onclick="editCustomService(${service.id})" title="编辑">
|
||||||
|
✏️
|
||||||
|
</button>
|
||||||
<button class="btn btn-ghost btn-sm" onclick="toggleService(${service.id}, ${!service.enabled})" title="${service.enabled ? '禁用' : '启用'}">
|
<button class="btn btn-ghost btn-sm" onclick="toggleService(${service.id}, ${!service.enabled})" title="${service.enabled ? '禁用' : '启用'}">
|
||||||
${service.enabled ? '🔇' : '🔊'}
|
${service.enabled ? '🔇' : '🔊'}
|
||||||
</button>
|
</button>
|
||||||
@@ -501,3 +541,139 @@ function escapeHtml(text) {
|
|||||||
div.textContent = text;
|
div.textContent = text;
|
||||||
return div.innerHTML;
|
return div.innerHTML;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ============== 编辑功能 ==============
|
||||||
|
|
||||||
|
// 编辑自定义域名服务
|
||||||
|
async function editCustomService(id) {
|
||||||
|
try {
|
||||||
|
// 获取完整的服务详情
|
||||||
|
const service = await api.get(`/email-services/${id}/full`);
|
||||||
|
|
||||||
|
// 填充表单
|
||||||
|
document.getElementById('edit-custom-id').value = service.id;
|
||||||
|
document.getElementById('edit-custom-name').value = service.name || '';
|
||||||
|
document.getElementById('edit-custom-api-url').value = service.config?.api_url || '';
|
||||||
|
document.getElementById('edit-custom-api-key').value = service.config?.api_key || '';
|
||||||
|
document.getElementById('edit-custom-domain').value = service.config?.domain || '';
|
||||||
|
document.getElementById('edit-custom-priority').value = service.priority || 0;
|
||||||
|
document.getElementById('edit-custom-enabled').checked = service.enabled;
|
||||||
|
|
||||||
|
// 清空密码提示
|
||||||
|
document.getElementById('edit-custom-api-key').placeholder = service.config?.api_key ? '已设置,留空保持不变' : 'API Key';
|
||||||
|
|
||||||
|
// 显示模态框
|
||||||
|
elements.editCustomModal.classList.add('active');
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
toast.error('获取服务信息失败: ' + error.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 保存编辑自定义域名服务
|
||||||
|
async function handleEditCustom(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
const id = document.getElementById('edit-custom-id').value;
|
||||||
|
const formData = new FormData(e.target);
|
||||||
|
|
||||||
|
// 构建更新数据
|
||||||
|
const updateData = {
|
||||||
|
name: formData.get('name'),
|
||||||
|
priority: parseInt(formData.get('priority')) || 0,
|
||||||
|
enabled: formData.get('enabled') === 'on'
|
||||||
|
};
|
||||||
|
|
||||||
|
// 构建配置
|
||||||
|
const config = {
|
||||||
|
api_url: formData.get('api_url'),
|
||||||
|
domain: formData.get('domain')
|
||||||
|
};
|
||||||
|
|
||||||
|
// 只有在填写了 API Key 时才更新
|
||||||
|
const apiKey = formData.get('api_key');
|
||||||
|
if (apiKey && apiKey.trim()) {
|
||||||
|
config.api_key = apiKey.trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
updateData.config = config;
|
||||||
|
|
||||||
|
try {
|
||||||
|
await api.patch(`/email-services/${id}`, updateData);
|
||||||
|
toast.success('服务更新成功');
|
||||||
|
elements.editCustomModal.classList.remove('active');
|
||||||
|
loadCustomServices();
|
||||||
|
loadStats();
|
||||||
|
} catch (error) {
|
||||||
|
toast.error('更新失败: ' + error.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 编辑 Outlook 服务
|
||||||
|
async function editOutlookService(id) {
|
||||||
|
try {
|
||||||
|
// 获取完整的服务详情
|
||||||
|
const service = await api.get(`/email-services/${id}/full`);
|
||||||
|
|
||||||
|
// 填充表单
|
||||||
|
document.getElementById('edit-outlook-id').value = service.id;
|
||||||
|
document.getElementById('edit-outlook-email').value = service.config?.email || service.name || '';
|
||||||
|
document.getElementById('edit-outlook-password').value = '';
|
||||||
|
document.getElementById('edit-outlook-password').placeholder = service.config?.password ? '已设置,留空保持不变' : '请输入密码';
|
||||||
|
document.getElementById('edit-outlook-client-id').value = service.config?.client_id || '';
|
||||||
|
document.getElementById('edit-outlook-refresh-token').value = '';
|
||||||
|
document.getElementById('edit-outlook-refresh-token').placeholder = service.config?.refresh_token ? '已设置,留空保持不变' : 'OAuth Refresh Token';
|
||||||
|
document.getElementById('edit-outlook-priority').value = service.priority || 0;
|
||||||
|
document.getElementById('edit-outlook-enabled').checked = service.enabled;
|
||||||
|
|
||||||
|
// 显示模态框
|
||||||
|
elements.editOutlookModal.classList.add('active');
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
toast.error('获取服务信息失败: ' + error.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 保存编辑 Outlook 服务
|
||||||
|
async function handleEditOutlook(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
const id = document.getElementById('edit-outlook-id').value;
|
||||||
|
const formData = new FormData(e.target);
|
||||||
|
|
||||||
|
// 获取当前服务信息以保留未修改的敏感字段
|
||||||
|
let currentService;
|
||||||
|
try {
|
||||||
|
currentService = await api.get(`/email-services/${id}/full`);
|
||||||
|
} catch (error) {
|
||||||
|
toast.error('获取服务信息失败');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构建更新数据
|
||||||
|
const updateData = {
|
||||||
|
name: formData.get('email'), // 使用邮箱作为名称
|
||||||
|
priority: parseInt(formData.get('priority')) || 0,
|
||||||
|
enabled: formData.get('enabled') === 'on'
|
||||||
|
};
|
||||||
|
|
||||||
|
// 构建配置,保留未修改的敏感字段
|
||||||
|
const config = {
|
||||||
|
email: formData.get('email'),
|
||||||
|
password: formData.get('password')?.trim() || currentService.config?.password || '',
|
||||||
|
client_id: formData.get('client_id')?.trim() || currentService.config?.client_id || '',
|
||||||
|
refresh_token: formData.get('refresh_token')?.trim() || currentService.config?.refresh_token || ''
|
||||||
|
};
|
||||||
|
|
||||||
|
updateData.config = config;
|
||||||
|
|
||||||
|
try {
|
||||||
|
await api.patch(`/email-services/${id}`, updateData);
|
||||||
|
toast.success('账户更新成功');
|
||||||
|
elements.editOutlookModal.classList.remove('active');
|
||||||
|
loadOutlookServices();
|
||||||
|
loadStats();
|
||||||
|
} catch (error) {
|
||||||
|
toast.error('更新失败: ' + error.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -234,6 +234,103 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- 编辑自定义域名模态框 -->
|
||||||
|
<div class="modal" id="edit-custom-modal">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h3>✏️ 编辑自定义域名服务</h3>
|
||||||
|
<button class="modal-close" id="close-edit-custom-modal">×</button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<form id="edit-custom-form">
|
||||||
|
<input type="hidden" id="edit-custom-id" name="id">
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="edit-custom-name">服务名称</label>
|
||||||
|
<input type="text" id="edit-custom-name" name="name" required placeholder="例如:我的域名邮箱">
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="edit-custom-api-url">API 地址</label>
|
||||||
|
<input type="text" id="edit-custom-api-url" name="api_url" required placeholder="https://api.example.com">
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="edit-custom-api-key">API 密钥</label>
|
||||||
|
<input type="text" id="edit-custom-api-key" name="api_key" placeholder="API Key">
|
||||||
|
<small style="color: var(--text-muted);">留空则保持原值不变</small>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="edit-custom-domain">邮箱域名</label>
|
||||||
|
<input type="text" id="edit-custom-domain" name="domain" placeholder="example.com">
|
||||||
|
</div>
|
||||||
|
<div class="form-row">
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="edit-custom-priority">优先级</label>
|
||||||
|
<input type="number" id="edit-custom-priority" name="priority" value="0" min="0">
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label>
|
||||||
|
<input type="checkbox" id="edit-custom-enabled" name="enabled">
|
||||||
|
启用服务
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-actions">
|
||||||
|
<button type="submit" class="btn btn-primary">保存</button>
|
||||||
|
<button type="button" class="btn btn-secondary" id="cancel-edit-custom">取消</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 编辑 Outlook 账户模态框 -->
|
||||||
|
<div class="modal" id="edit-outlook-modal">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h3>✏️ 编辑 Outlook 账户</h3>
|
||||||
|
<button class="modal-close" id="close-edit-outlook-modal">×</button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<form id="edit-outlook-form">
|
||||||
|
<input type="hidden" id="edit-outlook-id" name="id">
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="edit-outlook-email">邮箱地址</label>
|
||||||
|
<input type="text" id="edit-outlook-email" name="email" required placeholder="example@outlook.com">
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="edit-outlook-password">密码</label>
|
||||||
|
<input type="password" id="edit-outlook-password" name="password" placeholder="留空则保持原值不变">
|
||||||
|
<small style="color: var(--text-muted);">留空则保持原值不变</small>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="edit-outlook-client-id">OAuth Client ID (可选)</label>
|
||||||
|
<input type="text" id="edit-outlook-client-id" name="client_id" placeholder="用于 XOAUTH2 认证">
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="edit-outlook-refresh-token">OAuth Refresh Token (可选)</label>
|
||||||
|
<input type="text" id="edit-outlook-refresh-token" name="refresh_token" placeholder="留空则保持原值不变">
|
||||||
|
<small style="color: var(--text-muted);">留空则保持原值不变</small>
|
||||||
|
</div>
|
||||||
|
<div class="form-row">
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="edit-outlook-priority">优先级</label>
|
||||||
|
<input type="number" id="edit-outlook-priority" name="priority" value="0" min="0">
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label>
|
||||||
|
<input type="checkbox" id="edit-outlook-enabled" name="enabled">
|
||||||
|
启用账户
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-actions">
|
||||||
|
<button type="submit" class="btn btn-primary">保存</button>
|
||||||
|
<button type="button" class="btn btn-secondary" id="cancel-edit-outlook">取消</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<script src="/static/js/utils.js"></script>
|
<script src="/static/js/utils.js"></script>
|
||||||
<script src="/static/js/email_services.js"></script>
|
<script src="/static/js/email_services.js"></script>
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
Reference in New Issue
Block a user