Files
gsfdc/server/app/commands/seed_edu_notices_sample.py
T

155 lines
5.2 KiB
Python

"""写入继续教育「教育公告」演示条目。
同标题已存在则跳过,不覆盖工作人员后来改过的正文。
口令只从环境变量读取。
"""
from __future__ import annotations
from html import escape, unescape
from pathlib import Path
from sqlalchemy import select
from app.db import Base, SessionLocal, get_engine
from app.models.content import AdminFile
from app.models.home import HomeArticle, create_article
from app.services.storage import ensure_buckets, make_object_key, upload_object
ROOT = Path(__file__).resolve().parents[3]
SOURCE = ROOT / "docs" / "参考" / "现站" / "基础数据"
COURSE = SOURCE / "继续教育" / "文章" / "557316" / "content.txt"
CAROUSEL = SOURCE / "首页轮播"
CATEGORY = "edu_notices"
def _paragraphs_from_lines(lines: list[str]) -> str:
return "".join(f"<p>{escape(line)}</p>" for line in lines if line.strip())
def _course_html() -> str:
if not COURSE.is_file():
return _paragraphs_from_lines(["2020 年线上继续教育课程安排整理中。"])
text = unescape(COURSE.read_text(encoding="utf-8"))
lines = [line.strip() for line in text.splitlines() if line.strip()]
body = _paragraphs_from_lines(lines)
body += "<p>整理自现站公开页面:http://www.gsrea.org.cn/newsinfo/557316.html</p>"
return body
def _content_type(path: Path) -> str:
suffix = path.suffix.lower()
if suffix == ".png":
return "image/png"
if suffix == ".webp":
return "image/webp"
if suffix == ".gif":
return "image/gif"
return "image/jpeg"
def _store_public(db, path: Path, filename: str) -> AdminFile | None:
if not path.is_file():
return None
row = db.scalar(
select(AdminFile).where(AdminFile.bucket == "public", AdminFile.filename == filename)
)
if row is not None:
return row
data = path.read_bytes()
key = make_object_key(filename)
upload_object("public", key, data, _content_type(path))
row = AdminFile(
bucket="public",
object_key=key,
filename=filename,
content_type=_content_type(path),
size=len(data),
created_by=None,
)
db.add(row)
db.commit()
db.refresh(row)
return row
def _samples(cover_id: int | None) -> list[dict]:
return [
{
"title": "2026年度房地产估价师继续教育培训安排",
"publishedAt": "2026-03-02T08:00:00",
"imageFileId": cover_id,
"bodyHtml": _paragraphs_from_lines(
[
"本条为演示库样例,正式安排以协会最新通知为准。",
"培训对象:本会注册房地产估价师及从业人员。",
"时间安排:2026年4月至11月,线上课程与兰州集中面授结合。",
"学时要求:完成规定学时并通过学习记录核验后,计入当年度继续教育。",
"报名与缴费仍通过现有甘肃省继续教育系统办理,本站只发布计划与公告。",
]
),
},
{
"title": "关于开展2025年估价师继续教育补学的通知",
"publishedAt": "2025-09-18T08:00:00",
"imageFileId": cover_id,
"bodyHtml": _paragraphs_from_lines(
[
"本条为演示库样例。",
"尚未完成2025年度规定学时的会员,可于10月31日前通过继续教育系统补学。",
"补学课程包括估价报告常见问题、城市更新估价要点与行业诚信要求。",
"咨询电话:0931-8126195。",
]
),
},
{
"title": "2020年豫甘两会线上估价师继续教育课程安排",
"publishedAt": "2020-07-03T08:00:00",
"imageFileId": None,
"bodyHtml": _course_html(),
},
]
def seed() -> None:
import app.models.content # noqa: F401
import app.models.home # noqa: F401
ensure_buckets()
engine = get_engine()
Base.metadata.create_all(bind=engine)
SessionLocal.configure(bind=engine)
db = SessionLocal()
try:
cover = _store_public(db, CAROUSEL / "8488214.jpg", "edu-notice-cover.jpg")
added = 0
for item in _samples(cover.id if cover else None):
exists = db.scalar(
select(HomeArticle.id).where(
HomeArticle.category == CATEGORY,
HomeArticle.title == item["title"],
)
)
if exists is not None:
continue
create_article(
db,
{
"category": CATEGORY,
"title": item["title"],
"publishedAt": item["publishedAt"],
"published": True,
"bodyHtml": item["bodyHtml"],
"imageFileId": item["imageFileId"],
"attachmentFileIds": [],
},
)
added += 1
print(f"教育公告演示数据:新增 {added} 条。")
finally:
db.close()
if __name__ == "__main__":
seed()