Files
admin/app/config.py
T
wenfp 5717c651b2 feat(deploy): 添加 Gitea 自动部署 Webhook 及配套工具
新增 `/deploy/webhook` 接口,支持 Gitea HMAC 签名校验、指定分支部署、构建并发锁与超时控制
添加前端项目部署脚本 `scripts/deploy_front.sh`,负责拉取代码、安装依赖并执行构建
新增部署相关配置项并更新 `.env.example` 示例配置
更新项目文档说明自动部署的使用约定
补充 `.gitignore` 规则忽略证书和 PEM 格式文件
2026-07-27 11:51:55 +08:00

176 lines
5.2 KiB
Python

import os
from dataclasses import dataclass
from pathlib import Path
PROJECT_ROOT = Path(__file__).parents[1].resolve()
def load_local_env() -> None:
env_path = PROJECT_ROOT / ".env"
if not env_path.exists():
return
for raw_line in env_path.read_text(encoding="utf-8").splitlines():
line = raw_line.strip()
if not line or line.startswith("#") or "=" not in line:
continue
key, value = line.split("=", 1)
os.environ.setdefault(key.strip(), value.strip().strip('"').strip("'"))
load_local_env()
AUTH_REQUIRE_HTTPS = os.getenv("AUTH_REQUIRE_HTTPS", "1") == "1"
AUTH_ALLOW_INSECURE_LOCAL = os.getenv("AUTH_ALLOW_INSECURE_LOCAL", "1") == "1"
AUTH_COOKIE_SECURE = os.getenv("AUTH_COOKIE_SECURE", "1") == "1"
# 阿里云 OSS 配置预留:可以直接在这里填写,也可以用同名环境变量覆盖。
OSS_ENDPOINT = os.getenv("OSS_ENDPOINT", "")
OSS_INTERNAL_ENDPOINT = os.getenv("OSS_INTERNAL_ENDPOINT", "")
OSS_USE_INTERNAL = os.getenv("OSS_USE_INTERNAL", "0") == "1"
OSS_BUCKET_NAME = os.getenv("OSS_BUCKET_NAME", "")
OSS_ACCESS_KEY_ID = os.getenv("OSS_ACCESS_KEY_ID", "")
OSS_ACCESS_KEY_SECRET = os.getenv("OSS_ACCESS_KEY_SECRET", "")
OSS_PUBLIC_BASE_URL = os.getenv("OSS_PUBLIC_BASE_URL", "")
OSS_UPLOAD_PREFIX = os.getenv("OSS_UPLOAD_PREFIX", "product-images")
WECHAT_PAY_APPID = os.getenv("WECHAT_PAY_APPID", "")
WECHAT_PAY_MCH_ID = os.getenv("WECHAT_PAY_MCH_ID", "")
WECHAT_PAY_MCH_SERIAL_NO = os.getenv("WECHAT_PAY_MCH_SERIAL_NO", "")
WECHAT_PAY_API_V3_KEY = os.getenv("WECHAT_PAY_API_V3_KEY", "")
WECHAT_PAY_PRIVATE_KEY_PATH = os.getenv("WECHAT_PAY_PRIVATE_KEY_PATH", "")
WECHAT_PAY_PUBLIC_KEY_PATH = os.getenv("WECHAT_PAY_PUBLIC_KEY_PATH", "")
WECHAT_PAY_NOTIFY_URL = os.getenv("WECHAT_PAY_NOTIFY_URL", "")
WECHAT_PAY_API_BASE_URL = os.getenv("WECHAT_PAY_API_BASE_URL", "https://api.mch.weixin.qq.com")
WECHAT_PAY_SKIP_NOTIFY_VERIFY = os.getenv("WECHAT_PAY_SKIP_NOTIFY_VERIFY", "0") == "1"
DEPLOY_WEBHOOK_SECRET = os.getenv("DEPLOY_WEBHOOK_SECRET", "")
DEPLOY_PROJECT_DIR = os.getenv("DEPLOY_PROJECT_DIR", str(PROJECT_ROOT))
DEPLOY_FRONT_DIR = os.getenv("DEPLOY_FRONT_DIR", "front")
DEPLOY_BRANCH = os.getenv("DEPLOY_BRANCH", "")
DEPLOY_SCRIPT_PATH = os.getenv("DEPLOY_SCRIPT_PATH", str(PROJECT_ROOT / "scripts" / "deploy_front.sh"))
DEPLOY_COMMAND_TIMEOUT = int(os.getenv("DEPLOY_COMMAND_TIMEOUT", "600"))
DEPLOY_LOCK_PATH = os.getenv("DEPLOY_LOCK_PATH", "/tmp/py-web-deploy.lock")
@dataclass(frozen=True)
class OSSSettings:
endpoint: str
internal_endpoint: str
use_internal: bool
bucket_name: str
access_key_id: str
access_key_secret: str
public_base_url: str
upload_prefix: str
@property
def is_configured(self) -> bool:
return all(
[
self.endpoint,
self.bucket_name,
self.access_key_id,
self.access_key_secret,
]
)
@property
def upload_endpoint(self) -> str:
if self.use_internal and self.internal_endpoint:
return self.internal_endpoint
return self.endpoint
oss_settings = OSSSettings(
endpoint=OSS_ENDPOINT,
internal_endpoint=OSS_INTERNAL_ENDPOINT,
use_internal=OSS_USE_INTERNAL,
bucket_name=OSS_BUCKET_NAME,
access_key_id=OSS_ACCESS_KEY_ID,
access_key_secret=OSS_ACCESS_KEY_SECRET,
public_base_url=OSS_PUBLIC_BASE_URL,
upload_prefix=OSS_UPLOAD_PREFIX,
)
@dataclass(frozen=True)
class AuthSettings:
require_https: bool
allow_insecure_local: bool
cookie_secure: bool
auth_settings = AuthSettings(
require_https=AUTH_REQUIRE_HTTPS,
allow_insecure_local=AUTH_ALLOW_INSECURE_LOCAL,
cookie_secure=AUTH_COOKIE_SECURE,
)
@dataclass(frozen=True)
class WeChatPaySettings:
appid: str
mch_id: str
mch_serial_no: str
api_v3_key: str
private_key_path: str
public_key_path: str
notify_url: str
api_base_url: str
skip_notify_verify: bool
@property
def is_configured(self) -> bool:
return all(
[
self.appid,
self.mch_id,
self.mch_serial_no,
self.api_v3_key,
self.private_key_path,
self.notify_url,
]
)
wechat_pay_settings = WeChatPaySettings(
appid=WECHAT_PAY_APPID,
mch_id=WECHAT_PAY_MCH_ID,
mch_serial_no=WECHAT_PAY_MCH_SERIAL_NO,
api_v3_key=WECHAT_PAY_API_V3_KEY,
private_key_path=WECHAT_PAY_PRIVATE_KEY_PATH,
public_key_path=WECHAT_PAY_PUBLIC_KEY_PATH,
notify_url=WECHAT_PAY_NOTIFY_URL,
api_base_url=WECHAT_PAY_API_BASE_URL,
skip_notify_verify=WECHAT_PAY_SKIP_NOTIFY_VERIFY,
)
@dataclass(frozen=True)
class DeploySettings:
webhook_secret: str
project_dir: str
front_dir: str
branch: str
script_path: str
command_timeout: int
lock_path: str
@property
def is_configured(self) -> bool:
return bool(self.webhook_secret and self.script_path)
deploy_settings = DeploySettings(
webhook_secret=DEPLOY_WEBHOOK_SECRET,
project_dir=DEPLOY_PROJECT_DIR,
front_dir=DEPLOY_FRONT_DIR,
branch=DEPLOY_BRANCH,
script_path=DEPLOY_SCRIPT_PATH,
command_timeout=DEPLOY_COMMAND_TIMEOUT,
lock_path=DEPLOY_LOCK_PATH,
)