로그인한 사장님이 자기 사이트를 볼 화면이 없었다. 사이트는 place_id 로 한 건씩만 읽혀서 (site_crud.get_site_by_place) 사업장 목록으로 그리면 줄마다 사이트를 다시 물어 N+1 이 된다. - site_crud.list_company_sites: places LEFT JOIN sites LEFT JOIN site_versions 한 번. 사이트가 아직 없는 사업장(위저드만 걸어온 것)도 내려간다 — 빠지면 만들다 만 것을 찾을 길이 없다 - protocol.MySiteData: 한 줄 = 사업장 + 사이트. render(정적 파일 존재)는 넣지 않았다 — 보고서 파일을 읽는 값이라 줄 수만큼 파일 IO 가 된다. 단건(Res_Site)이 계속 소유한다 - site_service.list_my_sites: 회사 스코프. needs_rebuild 는 단건과 같은 규칙으로 판정한다 - GET /v1/site/list 는 라우터 객체를 따로 둔다 — 기존 라우터는 접두어에 place_id 가 박혀 있다 테스트 5건 추가(비어 있는 사업장·조인·회사 격리·재빌드 일치·비로그인), 539 passed (기존 실패 4건은 이 변경 전에도 같다 — build_publish 3 · snapshot 1)
91 lines
4.2 KiB
Python
91 lines
4.2 KiB
Python
"""내 사이트 목록 — 로그인한 사장님이 자기 사이트 전부를 보는 화면의 뒷단.
|
|
|
|
이 경로가 절대 하면 안 되는 것:
|
|
- 사이트가 아직 없는 사업장을 빼는 것 — 위저드를 걸어오다 만 가게가 목록에서 사라지면
|
|
사장님은 그걸 다시 찾을 길이 없다(에디터 주소를 아무도 기억하지 않는다).
|
|
- 회사 스코프를 놓치는 것 — 남의 가게가 내 목록에 섞이면 그건 목록이 아니라 사고다.
|
|
- 단건(GET /v1/place/{id}/site)과 다른 재빌드 판정을 내는 것 — 목록과 에디터가 서로 다른
|
|
답을 하면 사장님은 어느 쪽을 믿을지 알 수 없다.
|
|
"""
|
|
import uuid
|
|
|
|
from sqlalchemy import text
|
|
|
|
from common.enums import ErrorType, SiteStatus
|
|
|
|
|
|
async def _place(client, headers, name):
|
|
r = await client.post("/v1/place", headers=headers, json={"name": name, "category": 1})
|
|
return r.json()["place"]["place_id"]
|
|
|
|
|
|
async def _list(client, headers, **params):
|
|
return (await client.get("/v1/site/list", headers=headers, params=params)).json()
|
|
|
|
|
|
async def test_place_without_site_is_still_listed(auth_headers, client):
|
|
"""검증: 사이트 행이 없는 사업장(위저드만 걸어온 것)도 목록에 나온다.
|
|
기대결과: 줄은 있고 site_id 는 없다 — 화면이 '만드는 중'으로 그릴 근거다."""
|
|
h = await auth_headers("my1")
|
|
await _place(client, h, "아직펜션")
|
|
|
|
body = await _list(client, h)
|
|
assert body["result"]["code"] == ErrorType.SUCCESS.value
|
|
assert body["total"] == 1
|
|
row = body["sites"][0]
|
|
assert row["name"] == "아직펜션"
|
|
assert row.get("site_id") is None
|
|
assert row.get("status") is None
|
|
|
|
|
|
async def test_site_row_is_joined_into_the_line(auth_headers, client):
|
|
"""검증: 사업장과 사이트가 한 줄로 합쳐져 온다(줄마다 사이트를 다시 묻지 않는다).
|
|
기대결과: 템플릿·주소가 목록에 그대로 보인다."""
|
|
h = await auth_headers("my2")
|
|
pid = await _place(client, h, "합쳐진펜션")
|
|
await client.post(f"/v1/place/{pid}/site/template", headers=h, json={"template_id": "stay-quiet-margin"})
|
|
await client.post(f"/v1/place/{pid}/site/slug", headers=h, json={"slug": "joined-stay"})
|
|
|
|
row = (await _list(client, h))["sites"][0]
|
|
assert row["site_id"]
|
|
assert row["template_id"] == "stay-quiet-margin"
|
|
assert row["domain"] == "joined-stay"
|
|
assert row["status"] == SiteStatus.DRAFT.value
|
|
|
|
|
|
async def test_other_company_sites_are_not_listed(auth_headers, client, other_company_id):
|
|
"""검증: 회사(테넌트) 스코프. 남의 회사 사업장은 보이지 않는다.
|
|
기대결과: 각자 자기 것만 1건."""
|
|
mine = await auth_headers("my3")
|
|
theirs = await auth_headers("my3b", other_company_id)
|
|
await _place(client, mine, "내펜션")
|
|
await _place(client, theirs, "남의펜션")
|
|
|
|
assert [r["name"] for r in (await _list(client, mine))["sites"]] == ["내펜션"]
|
|
assert [r["name"] for r in (await _list(client, theirs))["sites"]] == ["남의펜션"]
|
|
|
|
|
|
async def test_needs_rebuild_matches_the_single_site_answer(auth_headers, client, db_engine):
|
|
"""검증: 재빌드 판정이 단건 조회와 같은 답을 낸다.
|
|
기대결과: 노출값이 바뀐 사업장은 목록에서도 needs_rebuild=true."""
|
|
h = await auth_headers("my4")
|
|
pid = await _place(client, h, "고친펜션")
|
|
# 템플릿 저장이 사이트 행을 만든다. 그 뒤 노출값이 바뀐 것으로 표시한다.
|
|
await client.post(f"/v1/place/{pid}/site/template", headers=h, json={"template_id": "t"})
|
|
async with db_engine.begin() as conn:
|
|
await conn.execute(
|
|
text("UPDATE places SET content_updated_at = now() WHERE place_id = :pid"),
|
|
{"pid": uuid.UUID(pid)},
|
|
)
|
|
|
|
single = (await client.get(f"/v1/place/{pid}/site", headers=h)).json()
|
|
row = (await _list(client, h))["sites"][0]
|
|
assert row["needs_rebuild"] is True
|
|
assert row["needs_rebuild"] == single["needs_rebuild"]
|
|
|
|
|
|
async def test_list_requires_login(client):
|
|
"""검증: 내 것을 보는 화면이므로 토큰 없이는 열리지 않는다.
|
|
기대결과: 401."""
|
|
assert (await client.get("/v1/site/list")).status_code == 401
|