diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..4752a56 --- /dev/null +++ b/.env.example @@ -0,0 +1,107 @@ +# ======================================== +# Flask提示词大师应用环境变量配置示例 +# ======================================== +# 复制此文件为 .env 并根据实际情况修改配置 +# cp env.example .env + +# ======================================== +# Flask基础配置 +# ======================================== +# Flask应用密钥(必需) +SECRET_KEY=your-secret-key-here + +# 应用环境(development/production/testing) +FLASK_ENV=development + +# 调试模式(开发环境开启,生产环境关闭) +DEBUG=True + +# ======================================== +# 数据库配置 +# ======================================== +# 主数据库连接URL(必需) +# MySQL示例: mysql+pymysql://username:password@host:port/database_name?charset=utf8mb4 +DATABASE_URL=mysql+pymysql://username:password@localhost:3306/database_name?charset=utf8mb4 + +# 腾讯云数据库连接URL(可选) +# TENCENT_DATABASE_URL=mysql+pymysql://username:password@tencent-host:port/database_name?charset=utf8mb4 + +# ======================================== +# OpenAI兼容API配置 +# ======================================== +# API基础URL(必需) +LLM_API_URL=https://api.deepseek.com/v1 + +# API密钥(必需) +LLM_API_KEY=sk-your-api-key-here + +# ======================================== +# 微信小程序配置 +# ======================================== +# 小程序AppID(必需) +WX_APPID=your-wx-appid-here + +# 小程序Secret(必需) +WX_SECRET=your-wx-secret-here + +# ======================================== +# 跨域配置 +# ======================================== +# 允许跨域的域名,多个用逗号分隔 +# 开发环境: http://localhost:3000,http://127.0.0.1:3000 +# 生产环境: https://yourdomain.com,https://www.yourdomain.com +CORS_ORIGINS=http://localhost:3000,http://127.0.0.1:3000 + +# ======================================== +# 日志配置 +# ======================================== +# 日志级别(DEBUG/INFO/WARNING/ERROR/CRITICAL) +LOG_LEVEL=INFO + +# 日志文件路径 +LOG_FILE=logs/app.log + +# ======================================== +# 缓存配置 +# ======================================== +# 缓存类型(simple/redis/memcached) +CACHE_TYPE=simple + +# 缓存默认超时时间(秒) +CACHE_DEFAULT_TIMEOUT=300 + +# Redis缓存URL(当CACHE_TYPE=redis时使用) +# REDIS_URL=redis://localhost:6379/0 + +# ======================================== +# 会话配置 +# ======================================== +# 会话生命周期(小时) +SESSION_LIFETIME_HOURS=24 + +# ======================================== +# 文件上传配置 +# ======================================== +# 最大文件上传大小(字节) +MAX_CONTENT_LENGTH=16777216 + +# 文件上传目录 +UPLOAD_FOLDER=uploads + +# ======================================== +# 安全配置 +# ======================================== +# 是否启用CSRF保护 +WTF_CSRF_ENABLED=True + +# CSRF令牌超时时间(秒) +WTF_CSRF_TIME_LIMIT=3600 + +# ======================================== +# 性能配置 +# ======================================== +# 数据库连接池大小 +DB_POOL_SIZE=20 + +# 数据库连接池最大溢出连接数 +DB_MAX_OVERFLOW=30 \ No newline at end of file diff --git a/.env.test b/.env.test new file mode 100644 index 0000000..ed35e64 --- /dev/null +++ b/.env.test @@ -0,0 +1,10 @@ +# 测试环境变量文件 +FLASK_ENV=development +SECRET_KEY=test-secret-key-for-development +DATABASE_URL=sqlite:///test.db +LLM_API_URL=https://api.deepseek.com/v1 +LLM_API_KEY=sk-test-api-key-for-development +WX_APPID=test-wx-appid +WX_SECRET=test-wx-secret +CORS_ORIGINS=http://localhost:3000,http://127.0.0.1:3000 +LOG_LEVEL=DEBUG \ No newline at end of file diff --git a/.gitignore b/.gitignore index f2bbe4f..ad08dd0 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,47 @@ env/ ENV/ myenv/ +# 环境变量文件 +.env +.env.local +.env.*.local + +# 日志文件 +logs/ +*.log + +# 缓存文件 +__pycache__/ +*.py[cod] +*$py.class + +# 数据库文件 +*.db +*.sqlite3 + +# 上传文件 +uploads/ + +# 备份文件 +*.bak +*.backup + +# IDE配置文件 +.vscode/ +.idea/ +*.swp +*.swo + +# 操作系统文件 +.DS_Store +Thumbs.db + +# 测试覆盖率 +.coverage +htmlcov/ + +# 构建输出 +dist/ +build/ +*.egg-info/ + diff --git a/config.py b/config.py index 6bfaaea..de855c0 100644 --- a/config.py +++ b/config.py @@ -6,50 +6,68 @@ # class Config: # SECRET_KEY = os.environ.get('SECRET_KEY') or 'dev-key' - + # # MySQL数据库配置 # SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URL') or 'mysql+pymysql://root:123456@localhost:3306/pro_db?charset=utf8mb4' # SQLALCHEMY_TRACK_MODIFICATIONS = False - + # # OpenAI兼容API配置 # LLM_API_URL = os.environ.get('LLM_API_URL') or 'https://api.deepseek.com/v1' # LLM_API_KEY = os.environ.get('LLM_API_KEY') or 'sk-fdf7cc1c73504e628ec0119b7e11b8cc' - + # # 微信小程序配置 # WX_APPID = os.environ.get('WX_APPID') or 'wx2c65877d37fc29bf' # 替换为你的小程序 appid # WX_SECRET = os.environ.get('WX_SECRET') or '89aa97dda3c1347c6ae3d6ab4627f1f4' # 替换为你的小程序 secret - + # # 添加跨域支持 # CORS_ORIGINS = ['*'] # 生产环境建议设置具体域名 + +# 此文件已弃用,请使用 config/ 目录下的配置系统 +# 为了向后兼容,此文件重定向到新的配置系统 import os +import warnings from dotenv import load_dotenv # 在配置类定义前加载环境变量 load_dotenv() +# 警告:此文件已弃用,请使用 config/ 目录下的配置系统 +warnings.warn("config.py 已弃用,请使用新的配置系统 (config/ 目录)", DeprecationWarning) + class Config: - SECRET_KEY = os.environ.get('SECRET_KEY') or 'dev-key' - - # ---------------------- 原有本地MySQL数据库配置 ---------------------- - SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URL') or 'mysql+pymysql://root:123456@localhost:3306/pro_db?charset=utf8mb4' - SQLALCHEMY_TRACK_MODIFICATIONS = False # 关闭SQLAlchemy的修改跟踪(减少性能消耗) - - # ---------------------- 新增:腾讯云数据库配置 ---------------------- - # 腾讯云数据库连接URI(格式:mysql+pymysql://用户名:密码@数据库地址:端口/数据库名?charset=utf8mb4) - # 注意:需先在腾讯云控制台创建目标数据库(如命名为 pro_db_tencent,需替换为你的实际库名) - TENCENT_SQLALCHEMY_DATABASE_URI = os.environ.get('TENCENT_DATABASE_URL') or \ - 'mysql+pymysql://root:!Rjb12191@gz-cynosdbmysql-grp-d26pzce5.sql.tencentcdb.com:24936/pro_db?charset=utf8mb4' - # 腾讯云数据库同样关闭修改跟踪(与本地配置保持一致) + SECRET_KEY = os.environ.get('SECRET_KEY') + if not SECRET_KEY: + raise ValueError("SECRET_KEY 环境变量未设置,请设置环境变量或使用新的配置系统") + + # ---------------------- 数据库配置 ---------------------- + SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URL') + if not SQLALCHEMY_DATABASE_URI: + raise ValueError("DATABASE_URL 环境变量未设置,请设置环境变量或使用新的配置系统") + + SQLALCHEMY_TRACK_MODIFICATIONS = False + + # ---------------------- 腾讯云数据库配置 ---------------------- + TENCENT_SQLALCHEMY_DATABASE_URI = os.environ.get('TENCENT_DATABASE_URL') TENCENT_SQLALCHEMY_TRACK_MODIFICATIONS = False - - # ---------------------- 其他原有配置(保持不变) ---------------------- - # OpenAI兼容API配置 + + # ---------------------- OpenAI兼容API配置 ---------------------- LLM_API_URL = os.environ.get('LLM_API_URL') or 'https://api.deepseek.com/v1' - LLM_API_KEY = os.environ.get('LLM_API_KEY') or 'sk-fdf7cc1c73504e628ec0119b7e11b8cc' - - # 微信小程序配置 - WX_APPID = os.environ.get('WX_APPID') or 'wx2c65877d37fc29bf' # 替换为你的小程序 appid - WX_SECRET = os.environ.get('WX_SECRET') or '89aa97dda3c1347c6ae3d6ab4627f1f4' # 替换为你的小程序 secret - - # 添加跨域支持 - CORS_ORIGINS = ['*'] # 生产环境建议设置具体域名(如 ['https://your-domain.com']) \ No newline at end of file + LLM_API_KEY = os.environ.get('LLM_API_KEY') + if not LLM_API_KEY: + raise ValueError("LLM_API_KEY 环境变量未设置,请设置环境变量或使用新的配置系统") + + # ---------------------- 微信小程序配置 ---------------------- + WX_APPID = os.environ.get('WX_APPID') + WX_SECRET = os.environ.get('WX_SECRET') + if not WX_APPID or not WX_SECRET: + raise ValueError("WX_APPID 和 WX_SECRET 环境变量未设置,请设置环境变量或使用新的配置系统") + + # ---------------------- 跨域配置 ---------------------- + CORS_ORIGINS = os.environ.get('CORS_ORIGINS', '*').split(',') + + @staticmethod + def init_app(app): + """初始化应用配置(为兼容性保留)""" + # 创建必要的目录 + os.makedirs('logs', exist_ok=True) + os.makedirs('uploads', exist_ok=True) \ No newline at end of file diff --git a/config/__pycache__/__init__.cpython-312.pyc b/config/__pycache__/__init__.cpython-312.pyc index a5a3a25..4211506 100644 Binary files a/config/__pycache__/__init__.cpython-312.pyc and b/config/__pycache__/__init__.cpython-312.pyc differ diff --git a/config/__pycache__/base.cpython-312.pyc b/config/__pycache__/base.cpython-312.pyc index 48c0011..4f63d22 100644 Binary files a/config/__pycache__/base.cpython-312.pyc and b/config/__pycache__/base.cpython-312.pyc differ diff --git a/config/__pycache__/development.cpython-312.pyc b/config/__pycache__/development.cpython-312.pyc index 2e05c34..a526d29 100644 Binary files a/config/__pycache__/development.cpython-312.pyc and b/config/__pycache__/development.cpython-312.pyc differ diff --git a/config/__pycache__/local.cpython-312.pyc b/config/__pycache__/local.cpython-312.pyc index cac6fd6..7f1866b 100644 Binary files a/config/__pycache__/local.cpython-312.pyc and b/config/__pycache__/local.cpython-312.pyc differ diff --git a/config/__pycache__/production.cpython-312.pyc b/config/__pycache__/production.cpython-312.pyc index c995498..3173694 100644 Binary files a/config/__pycache__/production.cpython-312.pyc and b/config/__pycache__/production.cpython-312.pyc differ diff --git a/config/__pycache__/testing.cpython-312.pyc b/config/__pycache__/testing.cpython-312.pyc index 2058bfa..a208302 100644 Binary files a/config/__pycache__/testing.cpython-312.pyc and b/config/__pycache__/testing.cpython-312.pyc differ diff --git a/config/base.py b/config/base.py index 7ffe275..2b9ede5 100644 --- a/config/base.py +++ b/config/base.py @@ -23,14 +23,14 @@ class Config: # OpenAI兼容API配置 LLM_API_URL = os.environ.get('LLM_API_URL') or 'https://api.deepseek.com/v1' - LLM_API_KEY = os.environ.get('LLM_API_KEY') or 'sk-your-api-key-here' + LLM_API_KEY = os.environ.get('LLM_API_KEY') # 微信小程序配置 - WX_APPID = os.environ.get('WX_APPID') or 'wx-your-appid-here' - WX_SECRET = os.environ.get('WX_SECRET') or 'your-wx-secret-here' - - # 跨域配置 - CORS_ORIGINS = os.environ.get('CORS_ORIGINS', '*').split(',') + WX_APPID = os.environ.get('WX_APPID') + WX_SECRET = os.environ.get('WX_SECRET') + + # 跨域配置 - 默认值在具体环境配置中设置 + CORS_ORIGINS = os.environ.get('CORS_ORIGINS', '').split(',') # 日志配置 LOG_LEVEL = os.environ.get('LOG_LEVEL', 'INFO') diff --git a/config/development.py b/config/development.py index e2b1129..09e4b4b 100644 --- a/config/development.py +++ b/config/development.py @@ -12,6 +12,22 @@ class DevelopmentConfig(Config): super().__init__() if not self.SQLALCHEMY_DATABASE_URI: self.SQLALCHEMY_DATABASE_URI = 'sqlite:///dev.db' + + # 开发环境API配置(如果未设置,使用示例值并给出警告) + if not self.LLM_API_KEY: + self.LLM_API_KEY = 'sk-dev-example-api-key' + import warnings + warnings.warn("LLM_API_KEY not set, using development example key") + + if not self.WX_APPID: + self.WX_APPID = 'wx-dev-example-appid' + + if not self.WX_SECRET: + self.WX_SECRET = 'wx-dev-example-secret' + + # 开发环境CORS配置(如果没有设置,使用开发默认值) + if not self.CORS_ORIGINS or self.CORS_ORIGINS == ['']: + self.CORS_ORIGINS = ['http://localhost:3000', 'http://127.0.0.1:3000', '*'] # 开发环境日志配置 LOG_LEVEL = 'DEBUG' diff --git a/config/production.py b/config/production.py index c40ff8d..ea9da6c 100644 --- a/config/production.py +++ b/config/production.py @@ -7,7 +7,27 @@ class ProductionConfig(Config): """ DEBUG = False TESTING = False - + + def __init__(self): + super().__init__() + + # 生产环境必须设置的关键配置检查 + required_configs = [ + ('SECRET_KEY', self.SECRET_KEY), + ('LLM_API_KEY', self.LLM_API_KEY), + ('WX_APPID', self.WX_APPID), + ('WX_SECRET', self.WX_SECRET), + ('SQLALCHEMY_DATABASE_URI', self.SQLALCHEMY_DATABASE_URI) + ] + + for name, value in required_configs: + if not value: + raise ValueError(f"生产环境必须设置{name}环境变量") + + # 生产环境CORS配置检查(在父类中已经设置) + if not self.CORS_ORIGINS or self.CORS_ORIGINS == ['']: + raise ValueError("生产环境必须设置CORS_ORIGINS环境变量,指定允许的域名") + # 生产环境日志配置 LOG_LEVEL = 'WARNING' LOG_FILE = 'logs/production.log' @@ -31,8 +51,8 @@ class ProductionConfig(Config): # 生产环境跨域配置(需要设置具体的域名) CORS_ORIGINS = os.environ.get('CORS_ORIGINS', '').split(',') if not CORS_ORIGINS or CORS_ORIGINS == ['']: - # 如果没有设置,使用默认值而不是抛出异常 - CORS_ORIGINS = ['https://yourdomain.com'] + # 生产环境必须设置CORS域名 + raise ValueError("生产环境必须设置CORS_ORIGINS环境变量,指定允许的域名") # 生产环境性能配置 SQLALCHEMY_ENGINE_OPTIONS = { diff --git a/requirements.txt b/requirements.txt index 9efa935..94360e3 100644 --- a/requirements.txt +++ b/requirements.txt @@ -9,4 +9,5 @@ waitress>=3.0.0 redis>=5.0.1 pywin32>=306 requests>=2.28.0 -psutil>=5.9.0 \ No newline at end of file +psutil>=5.9.0 +bcrypt>=4.0.0 \ No newline at end of file diff --git a/src/flask_prompt_master/__pycache__/__init__.cpython-312.pyc b/src/flask_prompt_master/__pycache__/__init__.cpython-312.pyc index f9cec22..dd06a17 100644 Binary files a/src/flask_prompt_master/__pycache__/__init__.cpython-312.pyc and b/src/flask_prompt_master/__pycache__/__init__.cpython-312.pyc differ diff --git a/src/flask_prompt_master/__pycache__/config.cpython-312.pyc b/src/flask_prompt_master/__pycache__/config.cpython-312.pyc index 20eec85..d3346de 100644 Binary files a/src/flask_prompt_master/__pycache__/config.cpython-312.pyc and b/src/flask_prompt_master/__pycache__/config.cpython-312.pyc differ diff --git a/src/flask_prompt_master/admin/__init__.py b/src/flask_prompt_master/admin/__init__.py index d0128e7..a4bd246 100644 --- a/src/flask_prompt_master/admin/__init__.py +++ b/src/flask_prompt_master/admin/__init__.py @@ -37,7 +37,7 @@ def init_admin(app): login_manager.login_message = '请先登录' # 创建Admin实例 - admin = Admin(app, name='提示词大师后台管理', template_mode='bootstrap4') + admin = Admin(app, name='提示词大师后台管理') # 注册视图 admin.add_view(UserAdminView(User, db.session, name='用户管理', endpoint='admin_user')) diff --git a/src/flask_prompt_master/admin/__pycache__/__init__.cpython-312.pyc b/src/flask_prompt_master/admin/__pycache__/__init__.cpython-312.pyc index 3d2a4b9..29f25b9 100644 Binary files a/src/flask_prompt_master/admin/__pycache__/__init__.cpython-312.pyc and b/src/flask_prompt_master/admin/__pycache__/__init__.cpython-312.pyc differ diff --git a/src/flask_prompt_master/admin/forms/__pycache__/__init__.cpython-312.pyc b/src/flask_prompt_master/admin/forms/__pycache__/__init__.cpython-312.pyc index 8be1ada..8107976 100644 Binary files a/src/flask_prompt_master/admin/forms/__pycache__/__init__.cpython-312.pyc and b/src/flask_prompt_master/admin/forms/__pycache__/__init__.cpython-312.pyc differ diff --git a/src/flask_prompt_master/admin/forms/__pycache__/admin_forms.cpython-312.pyc b/src/flask_prompt_master/admin/forms/__pycache__/admin_forms.cpython-312.pyc index 952a71e..0dd750f 100644 Binary files a/src/flask_prompt_master/admin/forms/__pycache__/admin_forms.cpython-312.pyc and b/src/flask_prompt_master/admin/forms/__pycache__/admin_forms.cpython-312.pyc differ diff --git a/src/flask_prompt_master/admin/models/__pycache__/__init__.cpython-312.pyc b/src/flask_prompt_master/admin/models/__pycache__/__init__.cpython-312.pyc index 208747e..135aaac 100644 Binary files a/src/flask_prompt_master/admin/models/__pycache__/__init__.cpython-312.pyc and b/src/flask_prompt_master/admin/models/__pycache__/__init__.cpython-312.pyc differ diff --git a/src/flask_prompt_master/admin/models/__pycache__/admin_user.cpython-312.pyc b/src/flask_prompt_master/admin/models/__pycache__/admin_user.cpython-312.pyc index 77c8bc4..6f02b53 100644 Binary files a/src/flask_prompt_master/admin/models/__pycache__/admin_user.cpython-312.pyc and b/src/flask_prompt_master/admin/models/__pycache__/admin_user.cpython-312.pyc differ diff --git a/src/flask_prompt_master/admin/views/__pycache__/__init__.cpython-312.pyc b/src/flask_prompt_master/admin/views/__pycache__/__init__.cpython-312.pyc index f33e330..9dad4c9 100644 Binary files a/src/flask_prompt_master/admin/views/__pycache__/__init__.cpython-312.pyc and b/src/flask_prompt_master/admin/views/__pycache__/__init__.cpython-312.pyc differ diff --git a/src/flask_prompt_master/admin/views/__pycache__/analytics_admin.cpython-312.pyc b/src/flask_prompt_master/admin/views/__pycache__/analytics_admin.cpython-312.pyc index d20c289..a5c13f3 100644 Binary files a/src/flask_prompt_master/admin/views/__pycache__/analytics_admin.cpython-312.pyc and b/src/flask_prompt_master/admin/views/__pycache__/analytics_admin.cpython-312.pyc differ diff --git a/src/flask_prompt_master/admin/views/__pycache__/api_admin.cpython-312.pyc b/src/flask_prompt_master/admin/views/__pycache__/api_admin.cpython-312.pyc index 1eb6781..62c0a66 100644 Binary files a/src/flask_prompt_master/admin/views/__pycache__/api_admin.cpython-312.pyc and b/src/flask_prompt_master/admin/views/__pycache__/api_admin.cpython-312.pyc differ diff --git a/src/flask_prompt_master/admin/views/__pycache__/backup_admin.cpython-312.pyc b/src/flask_prompt_master/admin/views/__pycache__/backup_admin.cpython-312.pyc index 69d9c54..7a9bd57 100644 Binary files a/src/flask_prompt_master/admin/views/__pycache__/backup_admin.cpython-312.pyc and b/src/flask_prompt_master/admin/views/__pycache__/backup_admin.cpython-312.pyc differ diff --git a/src/flask_prompt_master/admin/views/__pycache__/batch_admin.cpython-312.pyc b/src/flask_prompt_master/admin/views/__pycache__/batch_admin.cpython-312.pyc index b79a551..0346d79 100644 Binary files a/src/flask_prompt_master/admin/views/__pycache__/batch_admin.cpython-312.pyc and b/src/flask_prompt_master/admin/views/__pycache__/batch_admin.cpython-312.pyc differ diff --git a/src/flask_prompt_master/admin/views/__pycache__/monitor_admin.cpython-312.pyc b/src/flask_prompt_master/admin/views/__pycache__/monitor_admin.cpython-312.pyc index 7509a84..2ff97b3 100644 Binary files a/src/flask_prompt_master/admin/views/__pycache__/monitor_admin.cpython-312.pyc and b/src/flask_prompt_master/admin/views/__pycache__/monitor_admin.cpython-312.pyc differ diff --git a/src/flask_prompt_master/admin/views/__pycache__/prompt_admin.cpython-312.pyc b/src/flask_prompt_master/admin/views/__pycache__/prompt_admin.cpython-312.pyc index 73f99b4..b0d0487 100644 Binary files a/src/flask_prompt_master/admin/views/__pycache__/prompt_admin.cpython-312.pyc and b/src/flask_prompt_master/admin/views/__pycache__/prompt_admin.cpython-312.pyc differ diff --git a/src/flask_prompt_master/admin/views/__pycache__/report_admin.cpython-312.pyc b/src/flask_prompt_master/admin/views/__pycache__/report_admin.cpython-312.pyc index b662fc6..d13fe23 100644 Binary files a/src/flask_prompt_master/admin/views/__pycache__/report_admin.cpython-312.pyc and b/src/flask_prompt_master/admin/views/__pycache__/report_admin.cpython-312.pyc differ diff --git a/src/flask_prompt_master/admin/views/__pycache__/system_admin.cpython-312.pyc b/src/flask_prompt_master/admin/views/__pycache__/system_admin.cpython-312.pyc index 089f00c..da31312 100644 Binary files a/src/flask_prompt_master/admin/views/__pycache__/system_admin.cpython-312.pyc and b/src/flask_prompt_master/admin/views/__pycache__/system_admin.cpython-312.pyc differ diff --git a/src/flask_prompt_master/admin/views/__pycache__/template_admin.cpython-312.pyc b/src/flask_prompt_master/admin/views/__pycache__/template_admin.cpython-312.pyc index 63ccfc3..c8c4f35 100644 Binary files a/src/flask_prompt_master/admin/views/__pycache__/template_admin.cpython-312.pyc and b/src/flask_prompt_master/admin/views/__pycache__/template_admin.cpython-312.pyc differ diff --git a/src/flask_prompt_master/admin/views/__pycache__/user_admin.cpython-312.pyc b/src/flask_prompt_master/admin/views/__pycache__/user_admin.cpython-312.pyc index 8318981..ee830fb 100644 Binary files a/src/flask_prompt_master/admin/views/__pycache__/user_admin.cpython-312.pyc and b/src/flask_prompt_master/admin/views/__pycache__/user_admin.cpython-312.pyc differ diff --git a/src/flask_prompt_master/config.py b/src/flask_prompt_master/config.py index 35d8da9..c771122 100644 --- a/src/flask_prompt_master/config.py +++ b/src/flask_prompt_master/config.py @@ -1,23 +1,36 @@ import os +import warnings from dotenv import load_dotenv # 在配置类定义前加载环境变量 load_dotenv() +# 警告:此文件已弃用,请使用 config/ 目录下的配置系统 +warnings.warn("src/flask_prompt_master/config.py 已弃用,请使用新的配置系统 (config/ 目录)", DeprecationWarning) + class Config: - SECRET_KEY = os.environ.get('SECRET_KEY') or 'dev-key' - - # MySQL数据库配置 - 腾讯云数据库 - SQLALCHEMY_DATABASE_URI = 'mysql+pymysql://root:!Rjb12191@gz-cynosdbmysql-grp-d26pzce5.sql.tencentcdb.com:24936/pro_db?charset=utf8mb4' + SECRET_KEY = os.environ.get('SECRET_KEY') + if not SECRET_KEY: + raise ValueError("SECRET_KEY 环境变量未设置") + + # MySQL数据库配置 - 从环境变量读取 + SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URL') + if not SQLALCHEMY_DATABASE_URI: + raise ValueError("DATABASE_URL 环境变量未设置") + SQLALCHEMY_TRACK_MODIFICATIONS = False - + # OpenAI兼容API配置 LLM_API_URL = os.environ.get('LLM_API_URL') or 'https://api.deepseek.com/v1' - LLM_API_KEY = os.environ.get('LLM_API_KEY') or 'sk-fdf7cc1c73504e628ec0119b7e11b8cc' - + LLM_API_KEY = os.environ.get('LLM_API_KEY') + if not LLM_API_KEY: + raise ValueError("LLM_API_KEY 环境变量未设置") + # 微信小程序配置 - WX_APPID = os.environ.get('WX_APPID') or 'wx2c65877d37fc29bf' # 替换为你的小程序 appid - WX_SECRET = os.environ.get('WX_SECRET') or '89aa97dda3c1347c6ae3d6ab4627f1f4' # 替换为你的小程序 secret - - # 添加跨域支持 - CORS_ORIGINS = ['*'] # 生产环境建议设置具体域名 + WX_APPID = os.environ.get('WX_APPID') + WX_SECRET = os.environ.get('WX_SECRET') + if not WX_APPID or not WX_SECRET: + raise ValueError("WX_APPID 和 WX_SECRET 环境变量未设置") + + # 跨域配置 + CORS_ORIGINS = os.environ.get('CORS_ORIGINS', '*').split(',') diff --git a/src/flask_prompt_master/forms/__pycache__/__init__.cpython-312.pyc b/src/flask_prompt_master/forms/__pycache__/__init__.cpython-312.pyc index 1062be3..fa0bfa6 100644 Binary files a/src/flask_prompt_master/forms/__pycache__/__init__.cpython-312.pyc and b/src/flask_prompt_master/forms/__pycache__/__init__.cpython-312.pyc differ diff --git a/src/flask_prompt_master/forms/__pycache__/forms.cpython-312.pyc b/src/flask_prompt_master/forms/__pycache__/forms.cpython-312.pyc index c99ee1c..00342e5 100644 Binary files a/src/flask_prompt_master/forms/__pycache__/forms.cpython-312.pyc and b/src/flask_prompt_master/forms/__pycache__/forms.cpython-312.pyc differ diff --git a/src/flask_prompt_master/models/__pycache__/__init__.cpython-312.pyc b/src/flask_prompt_master/models/__pycache__/__init__.cpython-312.pyc index 215fdcc..296c52e 100644 Binary files a/src/flask_prompt_master/models/__pycache__/__init__.cpython-312.pyc and b/src/flask_prompt_master/models/__pycache__/__init__.cpython-312.pyc differ diff --git a/src/flask_prompt_master/models/__pycache__/favorites.cpython-312.pyc b/src/flask_prompt_master/models/__pycache__/favorites.cpython-312.pyc index 039e937..1972b7e 100644 Binary files a/src/flask_prompt_master/models/__pycache__/favorites.cpython-312.pyc and b/src/flask_prompt_master/models/__pycache__/favorites.cpython-312.pyc differ diff --git a/src/flask_prompt_master/models/__pycache__/history_models.cpython-312.pyc b/src/flask_prompt_master/models/__pycache__/history_models.cpython-312.pyc index 9aed82e..3c86416 100644 Binary files a/src/flask_prompt_master/models/__pycache__/history_models.cpython-312.pyc and b/src/flask_prompt_master/models/__pycache__/history_models.cpython-312.pyc differ diff --git a/src/flask_prompt_master/models/__pycache__/models.cpython-312.pyc b/src/flask_prompt_master/models/__pycache__/models.cpython-312.pyc index ff1ca86..91673b6 100644 Binary files a/src/flask_prompt_master/models/__pycache__/models.cpython-312.pyc and b/src/flask_prompt_master/models/__pycache__/models.cpython-312.pyc differ diff --git a/src/flask_prompt_master/models/__pycache__/poetry_favorites.cpython-312.pyc b/src/flask_prompt_master/models/__pycache__/poetry_favorites.cpython-312.pyc index 9160c12..24f7cde 100644 Binary files a/src/flask_prompt_master/models/__pycache__/poetry_favorites.cpython-312.pyc and b/src/flask_prompt_master/models/__pycache__/poetry_favorites.cpython-312.pyc differ diff --git a/src/flask_prompt_master/routes/__pycache__/__init__.cpython-312.pyc b/src/flask_prompt_master/routes/__pycache__/__init__.cpython-312.pyc index b9286c9..d61960b 100644 Binary files a/src/flask_prompt_master/routes/__pycache__/__init__.cpython-312.pyc and b/src/flask_prompt_master/routes/__pycache__/__init__.cpython-312.pyc differ diff --git a/src/flask_prompt_master/routes/__pycache__/android_tools.cpython-312.pyc b/src/flask_prompt_master/routes/__pycache__/android_tools.cpython-312.pyc index 3131791..08abcaa 100644 Binary files a/src/flask_prompt_master/routes/__pycache__/android_tools.cpython-312.pyc and b/src/flask_prompt_master/routes/__pycache__/android_tools.cpython-312.pyc differ diff --git a/src/flask_prompt_master/routes/__pycache__/auth.cpython-312.pyc b/src/flask_prompt_master/routes/__pycache__/auth.cpython-312.pyc index cf475ac..22ce4c7 100644 Binary files a/src/flask_prompt_master/routes/__pycache__/auth.cpython-312.pyc and b/src/flask_prompt_master/routes/__pycache__/auth.cpython-312.pyc differ diff --git a/src/flask_prompt_master/routes/__pycache__/expert_generate_2.cpython-312.pyc b/src/flask_prompt_master/routes/__pycache__/expert_generate_2.cpython-312.pyc index 2005885..f5a25f7 100644 Binary files a/src/flask_prompt_master/routes/__pycache__/expert_generate_2.cpython-312.pyc and b/src/flask_prompt_master/routes/__pycache__/expert_generate_2.cpython-312.pyc differ diff --git a/src/flask_prompt_master/routes/__pycache__/expert_generate_3.cpython-312.pyc b/src/flask_prompt_master/routes/__pycache__/expert_generate_3.cpython-312.pyc index 877eeec..b70949d 100644 Binary files a/src/flask_prompt_master/routes/__pycache__/expert_generate_3.cpython-312.pyc and b/src/flask_prompt_master/routes/__pycache__/expert_generate_3.cpython-312.pyc differ diff --git a/src/flask_prompt_master/routes/__pycache__/favorites.cpython-312.pyc b/src/flask_prompt_master/routes/__pycache__/favorites.cpython-312.pyc index 363fe3a..49abde3 100644 Binary files a/src/flask_prompt_master/routes/__pycache__/favorites.cpython-312.pyc and b/src/flask_prompt_master/routes/__pycache__/favorites.cpython-312.pyc differ diff --git a/src/flask_prompt_master/routes/__pycache__/history_routes.cpython-312.pyc b/src/flask_prompt_master/routes/__pycache__/history_routes.cpython-312.pyc index 523d669..682fb81 100644 Binary files a/src/flask_prompt_master/routes/__pycache__/history_routes.cpython-312.pyc and b/src/flask_prompt_master/routes/__pycache__/history_routes.cpython-312.pyc differ diff --git a/src/flask_prompt_master/routes/__pycache__/meal_planning.cpython-312.pyc b/src/flask_prompt_master/routes/__pycache__/meal_planning.cpython-312.pyc index 36332ed..2309f19 100644 Binary files a/src/flask_prompt_master/routes/__pycache__/meal_planning.cpython-312.pyc and b/src/flask_prompt_master/routes/__pycache__/meal_planning.cpython-312.pyc differ diff --git a/src/flask_prompt_master/routes/__pycache__/meeting_minutes.cpython-312.pyc b/src/flask_prompt_master/routes/__pycache__/meeting_minutes.cpython-312.pyc index 5d27117..eeaad7b 100644 Binary files a/src/flask_prompt_master/routes/__pycache__/meeting_minutes.cpython-312.pyc and b/src/flask_prompt_master/routes/__pycache__/meeting_minutes.cpython-312.pyc differ diff --git a/src/flask_prompt_master/routes/__pycache__/placeholder_apps.cpython-312.pyc b/src/flask_prompt_master/routes/__pycache__/placeholder_apps.cpython-312.pyc index 171b81d..52c1c81 100644 Binary files a/src/flask_prompt_master/routes/__pycache__/placeholder_apps.cpython-312.pyc and b/src/flask_prompt_master/routes/__pycache__/placeholder_apps.cpython-312.pyc differ diff --git a/src/flask_prompt_master/routes/__pycache__/poetry.cpython-312.pyc b/src/flask_prompt_master/routes/__pycache__/poetry.cpython-312.pyc index 1d25b90..9b0f309 100644 Binary files a/src/flask_prompt_master/routes/__pycache__/poetry.cpython-312.pyc and b/src/flask_prompt_master/routes/__pycache__/poetry.cpython-312.pyc differ diff --git a/src/flask_prompt_master/routes/__pycache__/prompt_optimization.cpython-312.pyc b/src/flask_prompt_master/routes/__pycache__/prompt_optimization.cpython-312.pyc index 09cddd3..21d38ce 100644 Binary files a/src/flask_prompt_master/routes/__pycache__/prompt_optimization.cpython-312.pyc and b/src/flask_prompt_master/routes/__pycache__/prompt_optimization.cpython-312.pyc differ diff --git a/src/flask_prompt_master/routes/__pycache__/resume_optimization.cpython-312.pyc b/src/flask_prompt_master/routes/__pycache__/resume_optimization.cpython-312.pyc index a8770b6..c865898 100644 Binary files a/src/flask_prompt_master/routes/__pycache__/resume_optimization.cpython-312.pyc and b/src/flask_prompt_master/routes/__pycache__/resume_optimization.cpython-312.pyc differ diff --git a/src/flask_prompt_master/routes/__pycache__/routes.cpython-312.pyc b/src/flask_prompt_master/routes/__pycache__/routes.cpython-312.pyc index cfb41e5..bdee28b 100644 Binary files a/src/flask_prompt_master/routes/__pycache__/routes.cpython-312.pyc and b/src/flask_prompt_master/routes/__pycache__/routes.cpython-312.pyc differ diff --git a/src/flask_prompt_master/routes/__pycache__/smart_prompt_optimization.cpython-312.pyc b/src/flask_prompt_master/routes/__pycache__/smart_prompt_optimization.cpython-312.pyc index 9bcbfab..a979f00 100644 Binary files a/src/flask_prompt_master/routes/__pycache__/smart_prompt_optimization.cpython-312.pyc and b/src/flask_prompt_master/routes/__pycache__/smart_prompt_optimization.cpython-312.pyc differ diff --git a/src/flask_prompt_master/routes/__pycache__/travel_planning.cpython-312.pyc b/src/flask_prompt_master/routes/__pycache__/travel_planning.cpython-312.pyc index 1c66248..23bffcd 100644 Binary files a/src/flask_prompt_master/routes/__pycache__/travel_planning.cpython-312.pyc and b/src/flask_prompt_master/routes/__pycache__/travel_planning.cpython-312.pyc differ diff --git a/src/flask_prompt_master/routes/__pycache__/weekly_report.cpython-312.pyc b/src/flask_prompt_master/routes/__pycache__/weekly_report.cpython-312.pyc index 70898c5..f1cb04b 100644 Binary files a/src/flask_prompt_master/routes/__pycache__/weekly_report.cpython-312.pyc and b/src/flask_prompt_master/routes/__pycache__/weekly_report.cpython-312.pyc differ diff --git a/src/flask_prompt_master/services/__pycache__/__init__.cpython-312.pyc b/src/flask_prompt_master/services/__pycache__/__init__.cpython-312.pyc index c403d90..2d20371 100644 Binary files a/src/flask_prompt_master/services/__pycache__/__init__.cpython-312.pyc and b/src/flask_prompt_master/services/__pycache__/__init__.cpython-312.pyc differ diff --git a/src/flask_prompt_master/services/__pycache__/auth_service.cpython-312.pyc b/src/flask_prompt_master/services/__pycache__/auth_service.cpython-312.pyc index 38f6ac7..f26f4a9 100644 Binary files a/src/flask_prompt_master/services/__pycache__/auth_service.cpython-312.pyc and b/src/flask_prompt_master/services/__pycache__/auth_service.cpython-312.pyc differ diff --git a/src/flask_prompt_master/services/__pycache__/favorite_service.cpython-312.pyc b/src/flask_prompt_master/services/__pycache__/favorite_service.cpython-312.pyc index b7c725e..a7b3d84 100644 Binary files a/src/flask_prompt_master/services/__pycache__/favorite_service.cpython-312.pyc and b/src/flask_prompt_master/services/__pycache__/favorite_service.cpython-312.pyc differ diff --git a/src/flask_prompt_master/services/__pycache__/poetry_favorite_service.cpython-312.pyc b/src/flask_prompt_master/services/__pycache__/poetry_favorite_service.cpython-312.pyc index 06e886c..dda9370 100644 Binary files a/src/flask_prompt_master/services/__pycache__/poetry_favorite_service.cpython-312.pyc and b/src/flask_prompt_master/services/__pycache__/poetry_favorite_service.cpython-312.pyc differ diff --git a/src/flask_prompt_master/services/auth_service.py b/src/flask_prompt_master/services/auth_service.py index 20a14b8..ff95979 100644 --- a/src/flask_prompt_master/services/auth_service.py +++ b/src/flask_prompt_master/services/auth_service.py @@ -5,6 +5,7 @@ import hashlib import os import re +import bcrypt from datetime import datetime, timedelta from src.flask_prompt_master import db from src.flask_prompt_master.models.models import User @@ -14,13 +15,20 @@ class AuthService: @staticmethod def generate_salt(): - """生成随机盐值""" - return os.urandom(16).hex() - + """生成随机盐值(为兼容性保留,新用户使用bcrypt)""" + return 'bcrypt' # 新用户使用bcrypt,标识为'bcrypt' + @staticmethod def hash_password(password, salt): - """使用盐值加密密码""" - return hashlib.md5((password + salt).encode('utf-8')).hexdigest() + """加密密码:新用户使用bcrypt,旧用户保持MD5""" + if salt == 'bcrypt': + # 使用bcrypt哈希密码 + password_bytes = password.encode('utf-8') + hashed = bcrypt.hashpw(password_bytes, bcrypt.gensalt()) + return hashed.decode('utf-8') + else: + # 旧MD5哈希方式(向后兼容) + return hashlib.md5((password + salt).encode('utf-8')).hexdigest() @staticmethod def validate_password(password): @@ -28,6 +36,21 @@ class AuthService: if len(password) < 6: return False, "密码长度至少6位" return True, "密码格式正确" + + @staticmethod + def check_password(password, hashed_password, salt): + """验证密码:支持bcrypt和MD5""" + if salt == 'bcrypt': + # 使用bcrypt验证 + try: + password_bytes = password.encode('utf-8') + hashed_bytes = hashed_password.encode('utf-8') + return bcrypt.checkpw(password_bytes, hashed_bytes) + except Exception: + return False + else: + # 使用MD5验证 + return hashlib.md5((password + salt).encode('utf-8')).hexdigest() == hashed_password @staticmethod def validate_email(email): @@ -135,8 +158,7 @@ class AuthService: return {'success': False, 'message': '账户已被禁用'} # 验证密码 - hashed_password = AuthService.hash_password(login_pwd, user.login_salt) - if hashed_password != user.login_pwd: + if not AuthService.check_password(login_pwd, user.login_pwd, user.login_salt): return {'success': False, 'message': '用户名或密码错误'} # 更新最后登录时间 @@ -245,8 +267,7 @@ class AuthService: return {'success': False, 'message': '用户不存在'} # 验证旧密码 - old_hashed = AuthService.hash_password(old_password, user.login_salt) - if old_hashed != user.login_pwd: + if not AuthService.check_password(old_password, user.login_pwd, user.login_salt): return {'success': False, 'message': '原密码错误'} # 验证新密码 diff --git a/src/flask_prompt_master/utils/__pycache__/__init__.cpython-312.pyc b/src/flask_prompt_master/utils/__pycache__/__init__.cpython-312.pyc index 4b512d7..48ef0af 100644 Binary files a/src/flask_prompt_master/utils/__pycache__/__init__.cpython-312.pyc and b/src/flask_prompt_master/utils/__pycache__/__init__.cpython-312.pyc differ diff --git a/src/flask_prompt_master/utils/__pycache__/performance_monitor.cpython-312.pyc b/src/flask_prompt_master/utils/__pycache__/performance_monitor.cpython-312.pyc index 07670c6..8dc305a 100644 Binary files a/src/flask_prompt_master/utils/__pycache__/performance_monitor.cpython-312.pyc and b/src/flask_prompt_master/utils/__pycache__/performance_monitor.cpython-312.pyc differ diff --git a/test_config.py b/test_config.py new file mode 100644 index 0000000..7c95d95 --- /dev/null +++ b/test_config.py @@ -0,0 +1,166 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +测试新的配置系统 +""" + +import os +import sys +from dotenv import load_dotenv + +# 加载测试环境变量 +env_file = '.env.test' +if os.path.exists(env_file): + load_dotenv(env_file) + print(f"[OK] 已加载环境变量文件: {env_file}") +else: + print(f"[WARN] 环境变量文件不存在: {env_file}") + print("正在检查默认环境变量...") + load_dotenv() + +def test_config_system(): + """测试配置系统""" + print("\n[TEST] 测试配置系统...") + + try: + # 导入新的配置系统 + from config import get_config + + # 获取配置 + config_class = get_config() + print(f"[OK] 获取配置类: {config_class.__name__}") + + # 检查环境变量 + env = os.environ.get('FLASK_ENV', 'development') + print(f"[OK] 当前环境: {env}") + + # 创建配置实例 + config = config_class() + print(f"[OK] 配置实例创建成功") + + # 检查关键配置 + print(f"[OK] SECRET_KEY: {'已设置' if config.SECRET_KEY else '未设置'}") + print(f"[OK] DATABASE_URL: {'已设置' if config.SQLALCHEMY_DATABASE_URI else '未设置'}") + print(f"[OK] LLM_API_KEY: {'已设置' if config.LLM_API_KEY else '未设置'}") + + return True + + except Exception as e: + print(f"[ERROR] 配置系统测试失败: {str(e)}") + import traceback + traceback.print_exc() + return False + +def test_old_config_compatibility(): + """测试旧配置文件的兼容性""" + print("\n[TEST] 测试旧配置文件兼容性...") + + try: + # 测试旧的config.py + import warnings + + # 捕获警告 + with warnings.catch_warnings(record=True) as w: + warnings.simplefilter("always") + + # 导入旧的config.py(会触发警告) + from config import Config as OldConfig + + if w: + print(f"[OK] 检测到弃用警告: {w[0].message}") + else: + print("[WARN] 未检测到弃用警告(可能有问题)") + + # 尝试创建实例 + try: + old_config = OldConfig() + print(f"[OK] 旧配置类可实例化") + return True + except ValueError as e: + print(f"[OK] 旧配置类按要求抛出错误(正常): {e}") + return True + + except Exception as e: + print(f"[ERROR] 旧配置兼容性测试失败: {str(e)}") + return False + +def test_app_factory(): + """测试应用工厂""" + print("\n[TEST] 测试应用工厂...") + + try: + from src.flask_prompt_master import create_app + + # 创建应用(应该使用新的配置系统) + app = create_app() + print(f"[OK] 应用创建成功") + + # 检查应用配置 + print(f"[OK] 应用调试模式: {app.config.get('DEBUG', '未设置')}") + print(f"[OK] 数据库URI: {app.config.get('SQLALCHEMY_DATABASE_URI', '未设置')[:50]}...") + + return True + + except Exception as e: + print(f"[ERROR] 应用工厂测试失败: {str(e)}") + import traceback + traceback.print_exc() + return False + +def main(): + """主测试函数""" + print("=" * 60) + print("aitsc 项目配置系统测试") + print("=" * 60) + + # 显示当前工作目录 + print(f"工作目录: {os.getcwd()}") + + # 检查环境变量文件 + env_files = ['.env', '.env.test', 'env.example'] + for env_file in env_files: + if os.path.exists(env_file): + print(f"[OK] 找到环境变量文件: {env_file}") + else: + print(f"[WARN] 未找到环境变量文件: {env_file}") + + # 运行测试 + tests = [ + ("配置系统", test_config_system), + ("旧配置兼容性", test_old_config_compatibility), + ("应用工厂", test_app_factory), + ] + + results = [] + for test_name, test_func in tests: + success = test_func() + results.append((test_name, success)) + + # 汇总结果 + print("\n" + "=" * 60) + print("测试结果汇总") + print("=" * 60) + + all_passed = True + for test_name, success in results: + status = "[OK] 通过" if success else "[ERROR] 失败" + print(f"{test_name}: {status}") + if not success: + all_passed = False + + print("\n" + "=" * 60) + if all_passed: + print("[SUCCESS] 所有测试通过!项目可以正常运行。") + print("\n下一步操作:") + print("1. 复制 .env.example 为 .env") + print("2. 在 .env 中填写实际的环境变量值") + print("3. 删除或备份旧的 .env 文件(包含硬编码密码)") + print("4. 运行 python run_dev.py 启动应用") + else: + print("[WARN] 部分测试失败,需要进一步检查。") + + return all_passed + +if __name__ == '__main__': + success = main() + sys.exit(0 if success else 1) \ No newline at end of file