diff --git a/src/config/__init__.py b/src/config/__init__.py index 5fa20c2..994ab9c 100644 --- a/src/config/__init__.py +++ b/src/config/__init__.py @@ -13,6 +13,7 @@ from .constants import ( DEFAULT_PASSWORD_LENGTH, PASSWORD_CHARSET, DEFAULT_USER_INFO, + generate_random_user_info, OPENAI_API_ENDPOINTS, ) @@ -30,5 +31,6 @@ __all__ = [ 'DEFAULT_PASSWORD_LENGTH', 'PASSWORD_CHARSET', 'DEFAULT_USER_INFO', + 'generate_random_user_info', 'OPENAI_API_ENDPOINTS', ] diff --git a/src/config/constants.py b/src/config/constants.py index 7001a06..109b433 100644 --- a/src/config/constants.py +++ b/src/config/constants.py @@ -2,6 +2,8 @@ 常量定义 """ +import random +from datetime import datetime from enum import Enum from typing import Dict, List, Tuple @@ -120,7 +122,48 @@ OTP_MAX_ATTEMPTS = 40 # 最大轮询次数 PASSWORD_CHARSET = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" 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 = { "name": "Neo", "birthdate": "2000-02-20", diff --git a/src/core/register.py b/src/core/register.py index 15bcd6f..a78a12a 100644 --- a/src/core/register.py +++ b/src/core/register.py @@ -22,7 +22,7 @@ from ..database import crud from ..database.session import get_db from ..config.constants import ( OPENAI_API_ENDPOINTS, - DEFAULT_USER_INFO, + generate_random_user_info, OTP_CODE_PATTERN, DEFAULT_PASSWORD_LENGTH, PASSWORD_CHARSET, @@ -372,7 +372,9 @@ class RegistrationEngine: def _create_user_account(self) -> bool: """创建用户账户""" 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( OPENAI_API_ENDPOINTS["create_account"], diff --git a/src/services/outlook.py b/src/services/outlook.py index e8a9906..72e593d 100644 --- a/src/services/outlook.py +++ b/src/services/outlook.py @@ -370,13 +370,26 @@ class OutlookService(BaseEmailService): self._current_account_index = 0 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(): self.accounts.append(account) self._account_locks[account.email] = threading.Lock() 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: logger.warning("未配置有效的 Outlook 账户") diff --git a/src/web/routes/accounts.py b/src/web/routes/accounts.py index a666819..b65830c 100644 --- a/src/web/routes/accounts.py +++ b/src/web/routes/accounts.py @@ -15,6 +15,7 @@ from ...database import crud from ...database.session import get_db from ...database.models import Account from ...config.constants import AccountStatus +from ...config.settings import get_settings logger = logging.getLogger(__name__) router = APIRouter() @@ -417,7 +418,8 @@ async def refresh_account_token(account_id: int, request: TokenRefreshRequest = """刷新单个账号的 Token""" 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) if result.success: @@ -438,6 +440,9 @@ async def batch_refresh_tokens(request: BatchRefreshRequest, background_tasks: B """批量刷新账号 Token""" from ...core.token_refresh import refresh_account_token as do_refresh + # 使用传入的代理或全局代理配置 + proxy = request.proxy if request.proxy else get_settings().proxy_url + results = { "success_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: try: - result = do_refresh(account_id, request.proxy) + result = do_refresh(account_id, proxy) if result.success: results["success_count"] += 1 else: @@ -464,7 +469,8 @@ async def validate_account_token(account_id: int, request: TokenValidateRequest """验证单个账号的 Token 有效性""" 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) return { @@ -479,6 +485,9 @@ async def batch_validate_tokens(request: BatchValidateRequest): """批量验证账号 Token 有效性""" from ...core.token_refresh import validate_account_token as do_validate + # 使用传入的代理或全局代理配置 + proxy = request.proxy if request.proxy else get_settings().proxy_url + results = { "valid_count": 0, "invalid_count": 0, @@ -487,7 +496,7 @@ async def batch_validate_tokens(request: BatchValidateRequest): for account_id in request.ids: try: - is_valid, error = do_validate(account_id, request.proxy) + is_valid, error = do_validate(account_id, proxy) results["details"].append({ "id": account_id, "valid": is_valid, diff --git a/src/web/routes/email_services.py b/src/web/routes/email_services.py index e49a70f..a2282d4 100644 --- a/src/web/routes/email_services.py +++ b/src/web/routes/email_services.py @@ -228,6 +228,27 @@ async def get_email_service(service_id: int): 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) 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: update_data["name"] = request.name 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: update_data["enabled"] = request.enabled if request.priority is not None: diff --git a/static/js/email_services.js b/static/js/email_services.js index 271b745..b48e6eb 100644 --- a/static/js/email_services.js +++ b/static/js/email_services.js @@ -42,11 +42,23 @@ const elements = { tempmailEnabled: document.getElementById('tempmail-enabled'), testTempmailBtn: document.getElementById('test-tempmail-btn'), - // 模态框 + // 添加自定义域名模态框 addCustomModal: document.getElementById('add-custom-modal'), addCustomForm: document.getElementById('add-custom-form'), 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.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) => { const checkboxes = elements.customTable.querySelectorAll('input[type="checkbox"][data-id]'); @@ -181,6 +215,9 @@ async function loadOutlookServices() {