From 08ebe7b53d8f63fa2f4e8698eb78ac9c5a2f6a1e Mon Sep 17 00:00:00 2001 From: king Date: Fri, 14 Aug 2026 13:44:43 +0900 Subject: [PATCH] =?UTF-8?q?feat(cafe24):=20=EC=83=81=EB=8B=A8=20=EA=B3=B5?= =?UTF-8?q?=ED=86=B5=20=ED=99=8D=EB=B3=B4=20=EC=88=A8=EA=B8=B0=EA=B8=B0=20?= =?UTF-8?q?=EC=B2=B4=ED=81=AC=EB=B0=95=EC=8A=A4=20(PC=C2=B7=EB=AA=A8?= =?UTF-8?q?=EB=B0=94=EC=9D=BC=20=EB=8F=99=EC=8B=9C)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 요청은 스킨 detail.html 의 `const numbers = [...]` 를 고치는 것이었지만, 카페24 Admin API 로는 스킨 HTML 파일을 읽거나 쓸 수 없다. 확인 결과 테마는 조회만 가능하고(GET /admin/themes) 스킨 파일 엔드포인트가 없다. 쓸 수 있는 것은 테마 페이지와 스크립트 태그뿐이다. 그래서 같은 결과를 상품 상세설명 안의 CSS 로 낸다. 상세설명은 이미 우리가 쓸 수 있는 영역이고, 상품별로 켜고 끌 수 있으며, 상태가 그 상품 소스에 그대로 보인다. 새 권한이나 재인증도 필요하지 않다. id 로 우리 블록만 찾으므로 사람이 쓴 " +) +_HIDE_PROMO_RE = re.compile( + r"[ \t]*]*\bid\s*=\s*[\"']%s[\"'][^>]*>.*?\s*" % re.escape(HIDE_PROMO_ID), + re.IGNORECASE | re.DOTALL, +) + + +def has_hidden_promo(html: str) -> bool: + """이 상품의 상세설명에 공통 홍보 숨김 블록이 들어 있는가.""" + return bool(_HIDE_PROMO_RE.search(html or "")) + + +def set_promo_hidden(html: str, hidden: bool) -> str: + """숨김 블록을 넣거나 뺀다. 여러 번 호출해도 결과가 같다(멱등). + + 넣을 때는 맨 앞에 둔다 — 찾기 쉽고, 상세설명 어디에 있어도 CSS 효과는 같다. + """ + stripped = _HIDE_PROMO_RE.sub("", html or "") + if not hidden: + return stripped + if not stripped.strip(): + return HIDE_PROMO_BLOCK + return HIDE_PROMO_BLOCK + "\n" + stripped.lstrip("\n") + + def fingerprint(html: str) -> str: """편집 시작 시점의 카페24 값 지문. 적용 직전 값과 비교해 충돌을 잡는다. diff --git a/app/modules/cafe24/templates/cafe24/_editor.html b/app/modules/cafe24/templates/cafe24/_editor.html index 5e71d05..91be241 100644 --- a/app/modules/cafe24/templates/cafe24/_editor.html +++ b/app/modules/cafe24/templates/cafe24/_editor.html @@ -55,7 +55,17 @@
- PC 상세설명 HTML · {{ desc.description | length }}자 + + PC 상세설명 HTML · {{ desc.description | length }}자 + + diff --git a/app/modules/cafe24/templates/cafe24/products.html b/app/modules/cafe24/templates/cafe24/products.html index 7eaccbd..03b30b9 100644 --- a/app/modules/cafe24/templates/cafe24/products.html +++ b/app/modules/cafe24/templates/cafe24/products.html @@ -1,7 +1,7 @@ {% extends "erp_base.html" %} {% block head_extra %} - + {% endblock %} {% block content %} diff --git a/app/modules/cafe24/templates/cafe24/schedules.html b/app/modules/cafe24/templates/cafe24/schedules.html index e62501a..31df825 100644 --- a/app/modules/cafe24/templates/cafe24/schedules.html +++ b/app/modules/cafe24/templates/cafe24/schedules.html @@ -1,7 +1,7 @@ {% extends "erp_base.html" %} {% block head_extra %} - + {% endblock %} {% block content %} diff --git a/app/modules/cafe24/templates/cafe24/system.html b/app/modules/cafe24/templates/cafe24/system.html index 33a7c4d..a40c35b 100644 --- a/app/modules/cafe24/templates/cafe24/system.html +++ b/app/modules/cafe24/templates/cafe24/system.html @@ -1,7 +1,7 @@ {% extends "erp_base.html" %} {% block head_extra %} - + {% endblock %} {% block content %} diff --git a/app/modules/cafe24/tests/test_cafe24.py b/app/modules/cafe24/tests/test_cafe24.py index 2fb4a80..ff73bfb 100644 --- a/app/modules/cafe24/tests/test_cafe24.py +++ b/app/modules/cafe24/tests/test_cafe24.py @@ -535,6 +535,45 @@ def test_format_then_encode_roundtrip(): assert saved == raw +# ════════════════════════════════════════════════════════════ +# 상단 공통 홍보 숨기기 (스킨 파일을 못 고치므로 상세설명 CSS 로 처리) +# ════════════════════════════════════════════════════════════ +def test_promo_hidden_add_and_remove(): + body = "
" + on = store.set_promo_hidden(body, True) + assert store.has_hidden_promo(on) is True + assert ".edb-img-tag-w{display:none !important}" in on + assert body in on # 원래 내용은 그대로 남는다 + + off = store.set_promo_hidden(on, False) + assert store.has_hidden_promo(off) is False + assert off.strip() == body + + +def test_promo_hidden_is_idempotent(): + body = "
x
" + once = store.set_promo_hidden(body, True) + assert store.set_promo_hidden(once, True) == once + twice_off = store.set_promo_hidden(store.set_promo_hidden(once, False), False) + assert twice_off.strip() == body + + +def test_promo_hidden_survives_formatting(): + """정리(포맷)를 거쳐도 숨김 상태가 유지되고 인식된다.""" + formatted = store.format_html(store.set_promo_hidden("

내용

", True)) + assert store.has_hidden_promo(formatted) is True + assert store.has_hidden_promo(store.format_html(store.set_promo_hidden(formatted, False))) is False + + +def test_promo_hidden_keeps_other_style_blocks(): + """사람이 쓴
x
" + on = store.set_promo_hidden(body, True) + off = store.set_promo_hidden(on, False) + assert ".v{max-width:100%}" in off + assert off.strip() == body + + def test_fingerprint_detects_change(): a = store.fingerprint("

A

") assert a == store.fingerprint("

A

") diff --git a/app/static/cafe24.css b/app/static/cafe24.css index fdf3649..c89fa42 100644 --- a/app/static/cafe24.css +++ b/app/static/cafe24.css @@ -240,6 +240,15 @@ align-items: center; } +.cf24-check-inline { + display: inline-flex; + align-items: center; + gap: 4px; + margin-left: var(--sp-12, 12px); + cursor: pointer; + color: var(--color-rich-black, #0a0a0a); +} + .cf24-memo { width: 260px; padding: 6px var(--sp-10, 10px); diff --git a/docs/CAFE24_MODULE.md b/docs/CAFE24_MODULE.md index b035724..4edf19f 100644 --- a/docs/CAFE24_MODULE.md +++ b/docs/CAFE24_MODULE.md @@ -196,6 +196,40 @@ cafe24_oauth_tokens 저장 - 닫는 태그가 빠진 HTML 이 흔하므로 들여쓰기 깊이에 상한(12)을 둔다. 어떤 이유로든 실패하면 **원본을 그대로** 돌려준다(정리보다 안 깨지는 게 중요). +### 2-3. 상단 공통 홍보 숨기기 + +스킨(`detail.html`)에는 공통 홍보를 지울 상품번호가 박혀 있다. + +```js +const numbers = [12,31,32, ...]; // .edb-img-tag-w 를 remove() +``` + +**카페24 Admin API 로는 이 파일을 고칠 수 없다.** 확인 결과 스킨/테마는 조회만 +가능하고(`GET /admin/themes`), 스킨 HTML 파일을 읽거나 쓰는 엔드포인트가 없다. +쓸 수 있는 것은 테마 페이지와 스크립트 태그(`/admin/scripttags`)뿐이다. + +그래서 같은 결과를 **상품 상세설명 안의 CSS** 로 낸다. 상세설명은 우리가 쓸 수 있고, +상품별로 켜고 끌 수 있으며, 상태가 그 상품 소스에 그대로 보인다. + +```html + +``` + +- 편집기 상단 **「상단 공통 홍보 숨기기」** 체크박스로 켜고 끈다. 적용할 때 반영된다. +- `id` 로 우리 블록만 찾는다 — 사람이 쓴 `