stay 는 굽기 보호 주소라 그 사업장 글을 승인하면 발행이 거절되고 글은 승인 상태로 남았다. 목업 화면의 미니블로그는 파일에 박힌 글이라 승인해도 바뀌지 않았다. - services/mockup_blog.py: window.__SITE_PAYLOAD__.posts 만 교체 — 기존 글 유지 · 새 글 추가 · 최신순, 직전 파일은 index.html.bak-blog - build_service: 발행 주소가 stay·stay2 면 굽지 않고 글만 갱신 후 승인분을 게재로(버전·Teams 실패 알림 없음) 테스트 3건 추가(test_mockup_blog). 빌드·블로그·롤백·썸네일 105 passed Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
61 lines
2.1 KiB
Python
61 lines
2.1 KiB
Python
"""목업(stay · stay2)은 굽지 않고 index.html 의 미니블로그 글만 갈아 끼운다."""
|
|
import json
|
|
import os
|
|
from pathlib import Path
|
|
|
|
from common.logger import LOG
|
|
from services import render_service
|
|
|
|
MOCKUP_SLUGS = frozenset({"stay", "stay2"})
|
|
PAYLOAD_MARKER = "window.__SITE_PAYLOAD__"
|
|
BACKUP_NAME = "index.html.bak-blog"
|
|
|
|
|
|
class MockupBlogError(Exception):
|
|
pass
|
|
|
|
|
|
def is_mockup(slug: str) -> bool:
|
|
return slug in MOCKUP_SLUGS
|
|
|
|
|
|
def index_path(slug: str) -> Path:
|
|
return Path(render_service.output_dir()) / "s" / slug / "index.html"
|
|
|
|
|
|
def _payload_span(html: str) -> tuple[int, int, dict]:
|
|
marker = html.find(PAYLOAD_MARKER)
|
|
if marker < 0:
|
|
raise MockupBlogError("payload 가 없다")
|
|
start = html.index("{", marker)
|
|
payload, end = json.JSONDecoder().raw_decode(html, start)
|
|
return start, end, payload
|
|
|
|
|
|
def merge_posts(existing: list[dict], snapshot_posts: list[dict]) -> list[dict]:
|
|
merged = {post["postId"]: post for post in existing if post.get("postId")}
|
|
for row in snapshot_posts:
|
|
body = (row.get("body") or "").strip()
|
|
if not body:
|
|
continue
|
|
merged[row["post_id"]] = {"postId": row["post_id"], "body": row["body"], "publishedAt": row["published_at"]}
|
|
return sorted(merged.values(), key=lambda post: post.get("publishedAt") or "", reverse=True)
|
|
|
|
|
|
def refresh_posts(slug: str, snapshot_posts: list[dict]) -> int:
|
|
path = index_path(slug)
|
|
if not path.is_file():
|
|
raise MockupBlogError(f"목업 파일이 없다: {path}")
|
|
html = path.read_text(encoding="utf-8")
|
|
start, end, payload = _payload_span(html)
|
|
payload["posts"] = merge_posts(payload.get("posts") or [], snapshot_posts)
|
|
encoded = json.dumps(payload, ensure_ascii=False).replace("</", "<\\/")
|
|
updated = html[:start] + encoded + html[end:]
|
|
|
|
(path.parent / BACKUP_NAME).write_text(html, encoding="utf-8")
|
|
tmp = path.with_name(f".{path.name}.tmp")
|
|
tmp.write_text(updated, encoding="utf-8")
|
|
os.replace(tmp, path)
|
|
LOG.i(f"[mockup-blog] {slug} 미니블로그 {len(payload['posts'])}건으로 갱신")
|
|
return len(payload["posts"])
|