From 6635b8fea8b387a84814a8b15e338555aef7108d Mon Sep 17 00:00:00 2001 From: Mavis Date: Sun, 7 Jun 2026 23:11:32 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20enum=20=E5=86=99=E5=85=A5=20PG=20?= =?UTF-8?q?=E7=94=A8=20value=20=E8=80=8C=E9=9D=9E=20name?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Source/SourceKind、UserRole、SubscriptionMatch 三个 enum 改用 values_callable 保证 PG 看到 'rss' / 'owner' / 'any' 等小写 value,而非 'RSS' 大写 name。 seed_sources 同步改为显式字符串。 --- backend/app/models/source.py | 6 +++++- backend/app/models/subscription.py | 6 +++++- backend/app/models/user.py | 6 +++++- backend/app/scripts/seed_sources.py | 13 +++++++------ scripts/_run_deploy.py | 29 +++++++++++++++-------------- 5 files changed, 37 insertions(+), 23 deletions(-) diff --git a/backend/app/models/source.py b/backend/app/models/source.py index 0ba41c7..25cbf25 100644 --- a/backend/app/models/source.py +++ b/backend/app/models/source.py @@ -32,7 +32,11 @@ class Source(Base): name: Mapped[str] = mapped_column(String(128), nullable=False) slug: Mapped[str] = mapped_column(String(128), unique=True, index=True, nullable=False) kind: Mapped[SourceKind] = mapped_column( - Enum(SourceKind, name="source_kind"), + Enum( + SourceKind, + name="source_kind", + values_callable=lambda x: [e.value for e in x], + ), default=SourceKind.RSS, nullable=False, ) diff --git a/backend/app/models/subscription.py b/backend/app/models/subscription.py index 1a0990d..1c32be6 100644 --- a/backend/app/models/subscription.py +++ b/backend/app/models/subscription.py @@ -34,7 +34,11 @@ class Subscription(Base): keyword: Mapped[str] = mapped_column(String(255), nullable=False) # 简单关键词,匹配走 ILIKE '%kw%';后续可加 regex/lucene match_in: Mapped[SubscriptionMatch] = mapped_column( - Enum(SubscriptionMatch, name="subscription_match"), + Enum( + SubscriptionMatch, + name="subscription_match", + values_callable=lambda x: [e.value for e in x], + ), default=SubscriptionMatch.ANY, nullable=False, ) diff --git a/backend/app/models/user.py b/backend/app/models/user.py index 533db37..be703fb 100644 --- a/backend/app/models/user.py +++ b/backend/app/models/user.py @@ -26,7 +26,11 @@ class User(Base): email: Mapped[str | None] = mapped_column(String(255), unique=True, index=True) password_hash: Mapped[str] = mapped_column(String(255), nullable=False) role: Mapped[UserRole] = mapped_column( - Enum(UserRole, name="user_role"), + Enum( + UserRole, + name="user_role", + values_callable=lambda x: [e.value for e in x], + ), default=UserRole.MEMBER, nullable=False, ) diff --git a/backend/app/scripts/seed_sources.py b/backend/app/scripts/seed_sources.py index 89ca006..2062d51 100644 --- a/backend/app/scripts/seed_sources.py +++ b/backend/app/scripts/seed_sources.py @@ -18,13 +18,14 @@ from sqlalchemy.dialects.postgresql import insert as pg_insert from sqlalchemy.exc import IntegrityError from app.database import AsyncSessionLocal -from app.models.source import Source, SourceKind +from app.models.source import Source +# 用字符串避免 SQLAlchemy 把 enum 写成 name(大写)而非 value(小写) SEEDS = [ { "name": "Reuters World", "slug": "reuters-world", - "kind": SourceKind.RSS, + "kind": "rss", "url": "https://feeds.reuters.com/Reuters/worldNews", "region": "global", "language_src": "en", @@ -36,7 +37,7 @@ SEEDS = [ { "name": "BBC World", "slug": "bbc-world", - "kind": SourceKind.RSS, + "kind": "rss", "url": "https://feeds.bbci.co.uk/news/world/rss.xml", "region": "global", "language_src": "en", @@ -48,7 +49,7 @@ SEEDS = [ { "name": "Al Jazeera", "slug": "aljazeera", - "kind": SourceKind.RSS, + "kind": "rss", "url": "https://www.aljazeera.com/xml/rss/all.xml", "region": "mena", "language_src": "en", @@ -60,7 +61,7 @@ SEEDS = [ { "name": "NHK World", "slug": "nhk-world", - "kind": SourceKind.RSS, + "kind": "rss", "url": "https://www3.nhk.or.jp/rss/news/cat0.xml", "region": "asia", "language_src": "en", @@ -72,7 +73,7 @@ SEEDS = [ { "name": "DW (Deutsche Welle)", "slug": "dw", - "kind": SourceKind.RSS, + "kind": "rss", "url": "https://rss.dw.com/xml/rss-en-all", "region": "eu", "language_src": "en", diff --git a/scripts/_run_deploy.py b/scripts/_run_deploy.py index a9387f2..5a0edcf 100644 --- a/scripts/_run_deploy.py +++ b/scripts/_run_deploy.py @@ -1,23 +1,24 @@ import os, paramiko -HOST, PORT, USER = "207.57.129.228", 19717, "root" PW = os.environ["REMOTE_PASS"] c = paramiko.SSHClient() c.set_missing_host_key_policy(paramiko.AutoAddPolicy()) -c.connect(HOST, port=PORT, username=USER, password=PW, timeout=15, allow_agent=False, look_for_keys=False) +c.connect("207.57.129.228", port=19717, username="root", password=PW, timeout=15, allow_agent=False, look_for_keys=False) -# 1) 推更新后的部署脚本 -sftp = c.open_sftp() -sftp.put("D:/selftools/diary-news/scripts/deploy_remote.sh", "/root/deploy_news.sh") -sftp.chmod("/root/deploy_news.sh", 0o755) -sftp.close() -print("[ok] script pushed") +def run(cmd, t=30): + si, so, se = c.exec_command(cmd, timeout=t) + out = so.read().decode("utf-8", "replace") + err = se.read().decode("utf-8", "replace") + rc = so.channel.recv_exit_status() + print(f"$ {cmd}") + if out: print(out, end="") + if err: print("[err]", err, end="", file=__import__("sys").stderr) + print(f" rc={rc}") -# 2) 杀掉旧进程(若有) -si, so, se = c.exec_command("pkill -f deploy_news.sh 2>/dev/null; sleep 2; echo done") -print(so.read().decode().strip()) +# 1) 服务器 git pull +run("cd /srv/news && sudo -u news git pull --rebase 2>&1 | tail -10") -# 3) 后台启动,设 SSHD_PORT=19717 +# 2) 重跑部署脚本(直接重跑,前面的 docker 镜像已构建缓存) +run("pkill -f deploy_news.sh 2>/dev/null; sleep 2; rm -f /root/deploy_news.log; echo ===restart===") si, so, se = c.exec_command("nohup env SSHD_PORT=19717 bash /root/deploy_news.sh > /root/deploy_news.log 2>&1 & echo $!", timeout=10) -pid = so.read().decode().strip() -print(f"[ok] deploy started, PID={pid}") +print(f"deploy started, PID={so.read().decode().strip()}") c.close()