o2o-site-AEO/solution/backend/services/mockup_blog.py
Mina Choi db7c9254f5 [feat] solution/backend: 목업(stay·stay2) 사업장 글이 게재되면 index.html 의 미니블로그만 갈아 끼움
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>
2026-10-01 11:26:54 +09:00

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"])