여러 줄 주석이 설명보다 경위(예전·실측·지적)를 적고 있어 읽는 사람이 결론을 찾기 어려웠다. - ts·tsx·js·mjs·css·py 478개: 여러 줄 주석은 첫 문장 한 줄로, 과거형·날짜 문장은 삭제 - 주석 위치는 TypeScript 파서·파이썬 tokenize/ast 로 찾는다 — 문자열 안의 # · /* 는 건드리지 않는다 - eslint·ts·noqa·type: ignore 같은 지시 주석은 그대로 둔다 파이썬 275개 정리 전후 AST 동일, TS 298개 주석 뺀 토큰 동일(빈 JSX 주석 10곳만 차이). site·frontend·admin tsc, site vitest 105 passed Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
132 lines
5.2 KiB
Python
132 lines
5.2 KiB
Python
#!/usr/bin/env python3
|
|
# -*- coding: utf-8 -*-
|
|
"""테스트 place에 야놀자 크롤링으로 넣은 객실 fact/사진을 **수동으로 검수·승인**해서, 실제 미리보기 렌더러(site_payload.to_site_payload → UnitsSection)에 뜨는지 확인하는 1회성 스크립트."""
|
|
from __future__ import annotations
|
|
|
|
import argparse
|
|
import asyncio
|
|
import json
|
|
import os
|
|
import sys
|
|
import uuid
|
|
|
|
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
|
os.environ.setdefault("APP_ENV", "local")
|
|
|
|
from sqlalchemy import select # noqa: E402
|
|
|
|
from common.database.db_session_manager import DB_SESSION_MNG # noqa: E402
|
|
from common.database.model.models import places, place_facts, place_photos # noqa: E402
|
|
from common.enums import DBWRType, ErrorType, FactStatus, MediaStatus # noqa: E402
|
|
from common.models.gmodel import UserInfo # noqa: E402
|
|
from common.utils.gtime import GTime # noqa: E402
|
|
from crud.fact_crud import FactCRUD # noqa: E402
|
|
from crud.media_crud import MediaCRUD # noqa: E402
|
|
from crud.place_crud import PlaceCRUD # noqa: E402
|
|
from crud.site_crud import SiteCRUD # noqa: E402
|
|
from crud.job_crud import JobQueue # noqa: E402
|
|
from router.v1.fact.protocol import Req_TransitionFact # noqa: E402
|
|
from services.fact_service import FactService # noqa: E402
|
|
from services.site_service import SiteService # noqa: E402
|
|
|
|
# 검수 전 상태(우리가 이번에 넣은 값들)만 건드린다.
|
|
_PENDING_FACT_STATUSES = (FactStatus.UNVERIFIED.value, FactStatus.PENDING_OWNER.value)
|
|
|
|
|
|
async def _load_place(place_id: str):
|
|
stmt = select(places).where(places.place_id == uuid.UUID(place_id), places.deleted == False) # noqa: E712
|
|
err, row = await DB_SESSION_MNG.execute_lambda(
|
|
places.DBType(), DBWRType.DB_READ.value, lambda s: DB_SESSION_MNG.execute(s, stmt)
|
|
)
|
|
if err != ErrorType.SUCCESS or not row:
|
|
return None
|
|
return row[0]
|
|
|
|
|
|
async def _unit_scope_facts(place_id: str):
|
|
stmt = select(place_facts).where(
|
|
place_facts.place_id == uuid.UUID(place_id),
|
|
place_facts.deleted == False, # noqa: E712
|
|
place_facts.unit_id.is_not(None),
|
|
place_facts.status.in_(_PENDING_FACT_STATUSES),
|
|
)
|
|
err, rows = await DB_SESSION_MNG.execute_lambda(
|
|
place_facts.DBType(), DBWRType.DB_READ.value, lambda s: DB_SESSION_MNG.execute(s, stmt)
|
|
)
|
|
return rows if err == ErrorType.SUCCESS else []
|
|
|
|
|
|
async def _unit_scope_pending_photos(place_id: str):
|
|
stmt = select(place_photos).where(
|
|
place_photos.place_id == uuid.UUID(place_id),
|
|
place_photos.deleted == False, # noqa: E712
|
|
place_photos.unit_id.is_not(None),
|
|
place_photos.status == MediaStatus.PENDING_REVIEW.value,
|
|
)
|
|
err, rows = await DB_SESSION_MNG.execute_lambda(
|
|
place_photos.DBType(), DBWRType.DB_READ.value, lambda s: DB_SESSION_MNG.execute(s, stmt)
|
|
)
|
|
return rows if err == ErrorType.SUCCESS else []
|
|
|
|
|
|
async def run(place_id: str) -> None:
|
|
place = await _load_place(place_id)
|
|
if place is None:
|
|
raise SystemExit(f"place를 찾을 수 없습니다: {place_id}")
|
|
|
|
actor = UserInfo(user_id=str(place.owner_user_id), id="yanolja_test_verify", role=1)
|
|
fact_service = FactService(FactCRUD(), PlaceCRUD())
|
|
media_crud = MediaCRUD()
|
|
|
|
facts = await _unit_scope_facts(place_id)
|
|
print(f"[검수 대상 fact] {len(facts)}건")
|
|
verified = 0
|
|
for f in facts:
|
|
res = await fact_service.transition(
|
|
actor, place_id, str(f.fact_id), Req_TransitionFact(status=FactStatus.VERIFIED)
|
|
)
|
|
if res.result.success:
|
|
verified += 1
|
|
else:
|
|
print(f" ! {f.key}({f.fact_id}) 전이 실패: {res.result.desc}")
|
|
print(f" -> VERIFIED 처리 {verified}/{len(facts)}건")
|
|
|
|
photos = await _unit_scope_pending_photos(place_id)
|
|
print(f"[승인 대상 사진] {len(photos)}건")
|
|
approved = 0
|
|
now = GTime.UTC()
|
|
for p in photos:
|
|
alt_text = p.label or "객실 사진"
|
|
run_err, _rowcount = await DB_SESSION_MNG.execute_lambda_claim(
|
|
place_photos.DBType(),
|
|
lambda s, m=p.media_id, a=alt_text: media_crud.apply_vision(
|
|
s, m, p.label, a, None, MediaStatus.APPROVED.value, now
|
|
),
|
|
)
|
|
if run_err == ErrorType.SUCCESS:
|
|
approved += 1
|
|
print(f" -> APPROVED 처리 {approved}/{len(photos)}건 (alt_text 채움)")
|
|
|
|
site_service = SiteService(SiteCRUD(), PlaceCRUD(), JobQueue())
|
|
payload = await site_service.preview_payload(actor, place_id)
|
|
units = (payload or {}).get("units", [])
|
|
print(f"\n[/preview 재확인] units {len(units)}개")
|
|
for u in units:
|
|
print(f" - {u.get('name')}: fact {len(u.get('facts', []))}개, media {len(u.get('mediaIds', []))}장")
|
|
if not units:
|
|
print(" (여전히 비어 있습니다 — payload 구조나 상태값을 다시 확인하세요)")
|
|
print(json.dumps(payload, ensure_ascii=False, default=str)[:2000])
|
|
|
|
await DB_SESSION_MNG.dispose_all()
|
|
|
|
|
|
def main() -> None:
|
|
parser = argparse.ArgumentParser(description="테스트 place의 야놀자 객실 데이터를 검수·승인해서 미리보기에 반영")
|
|
parser.add_argument("--place-id", required=True)
|
|
args = parser.parse_args()
|
|
asyncio.run(run(args.place_id))
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|