feat(cafe24): 편집기에 상품 다이렉트 주소 + 클립보드 복사
상세 화면 상단에 고객이 보는 상세페이지 주소를 보여주고 「주소 복사」·「쇼핑몰에서
열기」를 붙였다.
https://miras.co.kr/product/detail.html?product_no=119
도메인은 하드코딩하지 않고 CAFE24_SHOP_URL 로 받는다. 커스텀 도메인은 mall_id 로
알 수 없기 때문이다. 미설정 시 카페24 기본 도메인(https://<mall_id>.cafe24.com)으로
대체해 환경변수가 없어도 항상 유효한 주소가 나온다. 스킴 누락·끝 슬래시도 정규화한다.
주소 칸은 readonly <input> 이라 기존 복사 버튼(data-copy)이 값을 그대로 읽어간다 —
클립보드 로직을 새로 만들지 않았다. 클립보드 API 가 막힌 환경에서는 입력칸 선택으로
대체되고, 칸을 클릭하면 전체 선택된다.
CAFE24_SHOP_URL 은 .env.example 과 문서에 설명을 함께 넣었다(신규 환경변수 규칙).
검증: 유닛테스트 61개 통과(신규 2개 — 스킴/슬래시 유무 3가지 입력에서 같은 주소,
미설정 시 카페24 도메인 대체). 렌더 확인 — 주소 표시·복사 버튼·새 창 열기(noopener),
주소를 만들 수 없으면 줄 자체를 숨김.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -131,6 +131,8 @@ def _editor_ctx(st: Any, product_no: int) -> dict[str, Any]:
|
||||
info = products.normalize_product(product) if product else {}
|
||||
return {
|
||||
"product_no": product_no,
|
||||
# 고객이 보는 상세페이지 주소 (CAFE24_SHOP_URL, 없으면 카페24 기본 도메인)
|
||||
"product_url": api.config.product_url(product_no),
|
||||
"info": {
|
||||
**info,
|
||||
"price": str(product.get("price") or ""),
|
||||
|
||||
@@ -29,6 +29,18 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{# 고객이 보는 상세페이지 주소. readonly input 이라 기존 복사 버튼(data-copy)이
|
||||
그대로 동작한다(값을 box.value 로 읽는다). #}
|
||||
{% if product_url %}
|
||||
<div class="cf24-url-row">
|
||||
<input class="cf24-url" id="cf24-url" type="text" readonly value="{{ product_url }}"
|
||||
onclick="this.select();" aria-label="상품 상세페이지 주소" />
|
||||
<button class="erp-btn erp-btn-outline" type="button" data-copy="cf24-url">주소 복사</button>
|
||||
<a class="erp-btn erp-btn-outline" href="{{ product_url }}"
|
||||
target="_blank" rel="noopener noreferrer">쇼핑몰에서 열기</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if desc %}
|
||||
<form class="cf24-editor-form" method="post"
|
||||
action="/cafe24/products/{{ product_no }}/apply"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{% extends "erp_base.html" %}
|
||||
|
||||
{% block head_extra %}
|
||||
<link rel="stylesheet" href="/static/cafe24.css?v=20260814q" />
|
||||
<link rel="stylesheet" href="/static/cafe24.css?v=20260814r" />
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{% extends "erp_base.html" %}
|
||||
|
||||
{% block head_extra %}
|
||||
<link rel="stylesheet" href="/static/cafe24.css?v=20260814q" />
|
||||
<link rel="stylesheet" href="/static/cafe24.css?v=20260814r" />
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{% extends "erp_base.html" %}
|
||||
|
||||
{% block head_extra %}
|
||||
<link rel="stylesheet" href="/static/cafe24.css?v=20260814q" />
|
||||
<link rel="stylesheet" href="/static/cafe24.css?v=20260814r" />
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
@@ -134,6 +134,36 @@ def test_config_basics():
|
||||
assert "mall.write_product" in config.scope_param
|
||||
|
||||
|
||||
def test_product_url_uses_shop_url_env():
|
||||
"""다이렉트 주소는 CAFE24_SHOP_URL 기준. 스킴·끝 슬래시가 없어도 맞춘다."""
|
||||
saved = os.environ.get("CAFE24_SHOP_URL")
|
||||
try:
|
||||
for value in ("https://miras.co.kr", "miras.co.kr", "https://miras.co.kr/"):
|
||||
os.environ["CAFE24_SHOP_URL"] = value
|
||||
config = _config()
|
||||
assert (
|
||||
config.product_url(119)
|
||||
== "https://miras.co.kr/product/detail.html?product_no=119"
|
||||
), value
|
||||
finally:
|
||||
if saved is None:
|
||||
os.environ.pop("CAFE24_SHOP_URL", None)
|
||||
else:
|
||||
os.environ["CAFE24_SHOP_URL"] = saved
|
||||
|
||||
|
||||
def test_product_url_falls_back_to_cafe24_domain():
|
||||
"""CAFE24_SHOP_URL 이 없어도 항상 유효한 주소가 나와야 한다."""
|
||||
saved = os.environ.pop("CAFE24_SHOP_URL", None)
|
||||
try:
|
||||
assert _config().product_url(119) == (
|
||||
"https://testmall.cafe24.com/product/detail.html?product_no=119"
|
||||
)
|
||||
finally:
|
||||
if saved is not None:
|
||||
os.environ["CAFE24_SHOP_URL"] = saved
|
||||
|
||||
|
||||
def test_authorize_url_has_state_and_no_secret():
|
||||
url = oauth.build_authorize_url(_config(), state="STATE123")
|
||||
assert url.startswith("https://testmall.cafe24api.com/api/v2/oauth/authorize?")
|
||||
|
||||
Reference in New Issue
Block a user