87fca22ea0
상단 공통 홍보를 스킨 쪽에서 처리할 수 있는지 실물로 확인하려면 토큰에 디자인 권한이 있어야 한다. 개발자센터 앱에는 이미 추가됐고, 우리가 요청하는 scope 에도 넣는다. 재인증을 해야 실제 토큰에 반영된다. 확인해 둔 사실을 config.py 주석으로 남겼다. 카페24 Admin API 에는 스킨 HTML 파일(detail.html)을 직접 읽거나 쓰는 엔드포인트가 없다. 조회 가능한 것은 테마 목록과 테마 페이지뿐이며, 스크립트 태그 주입은 디자인이 아니라 mall.write_store 권한이고 인라인 코드가 아닌 외부 HTTPS URL 만 받는다. 요청 scope 를 DEFAULT_SCOPES 한 곳으로 모아, 앞으로 늘어날 때 authorize 와 클라이언트가 어긋나지 않게 했다. 검증: 유닛테스트 49개 통과. scope_param 출력 확인. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
86 lines
3.2 KiB
Python
86 lines
3.2 KiB
Python
"""카페24 연동 설정 — 환경변수만 읽는다(하드코딩 금지).
|
|
|
|
app/main.py 의 env() 헬퍼와 동일하게 os.getenv + strip 규칙을 쓴다.
|
|
integrations 계층은 app.main 을 import 하지 않는다(순환 import 방지).
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import os
|
|
from dataclasses import dataclass
|
|
|
|
# 상품관리에 필요한 최소 scope. 향후 주문관리는 ORDER_SCOPES 를 더한다.
|
|
PRODUCT_SCOPES: tuple[str, ...] = ("mall.read_product", "mall.write_product")
|
|
ORDER_SCOPES: tuple[str, ...] = ("mall.read_order", "mall.write_order")
|
|
|
|
# 디자인(테마) — 상단 공통 홍보 숨김을 스킨 쪽에서 처리할 수 있는지 확인/구현용.
|
|
# ⚠️ 카페24 Admin API 에는 스킨 HTML 파일(detail.html)을 직접 읽거나 쓰는
|
|
# 엔드포인트가 없다. 조회 가능한 것은 테마 목록과 테마 페이지뿐이다.
|
|
# 스크립트 태그 주입은 디자인이 아니라 mall.write_store(상점) 권한이며
|
|
# 인라인 코드가 아닌 외부 HTTPS URL 만 받는다.
|
|
DESIGN_SCOPES: tuple[str, ...] = ("mall.read_design", "mall.write_design")
|
|
|
|
# 실제로 요청하는 scope 묶음. 개발자센터 앱에 등록된 권한과 어긋나면 인증이
|
|
# 거부되므로, 여기에 추가할 때는 앱 권한도 함께 확인해야 한다.
|
|
DEFAULT_SCOPES: tuple[str, ...] = PRODUCT_SCOPES + DESIGN_SCOPES
|
|
|
|
DEFAULT_API_VERSION = "2026-03-01"
|
|
|
|
|
|
def _env(name: str, default: str = "") -> str:
|
|
value = os.getenv(name, "").strip()
|
|
return value if value else default
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class Cafe24Config:
|
|
mall_id: str
|
|
client_id: str
|
|
client_secret: str
|
|
redirect_uri: str
|
|
api_version: str
|
|
token_secret: str
|
|
scopes: tuple[str, ...]
|
|
|
|
@property
|
|
def configured(self) -> bool:
|
|
"""OAuth 를 시작할 수 있는 최소 조건."""
|
|
return bool(self.mall_id and self.client_id and self.client_secret and self.redirect_uri)
|
|
|
|
@property
|
|
def missing(self) -> list[str]:
|
|
"""설정 안내 화면에 표시할 미설정 환경변수 이름들."""
|
|
pairs = (
|
|
("CAFE24_MALL_ID", self.mall_id),
|
|
("CAFE24_CLIENT_ID", self.client_id),
|
|
("CAFE24_CLIENT_SECRET", self.client_secret),
|
|
("CAFE24_REDIRECT_URI", self.redirect_uri),
|
|
("CAFE24_TOKEN_SECRET", self.token_secret),
|
|
)
|
|
return [name for name, value in pairs if not value]
|
|
|
|
@property
|
|
def api_base(self) -> str:
|
|
return f"https://{self.mall_id}.cafe24api.com/api/v2"
|
|
|
|
@property
|
|
def scope_param(self) -> str:
|
|
return ",".join(self.scopes)
|
|
|
|
|
|
def load_config(*, scopes: tuple[str, ...] = DEFAULT_SCOPES) -> Cafe24Config:
|
|
"""환경변수에서 설정을 읽는다. 값이 없어도 예외를 던지지 않는다.
|
|
|
|
미설정 판단은 호출부가 `configured` / `missing` 으로 한다
|
|
(앱 기동을 막지 않기 위해 — 다른 모듈과 동일한 정책).
|
|
"""
|
|
return Cafe24Config(
|
|
mall_id=_env("CAFE24_MALL_ID"),
|
|
client_id=_env("CAFE24_CLIENT_ID"),
|
|
client_secret=_env("CAFE24_CLIENT_SECRET"),
|
|
redirect_uri=_env("CAFE24_REDIRECT_URI"),
|
|
api_version=_env("CAFE24_API_VERSION", DEFAULT_API_VERSION),
|
|
token_secret=_env("CAFE24_TOKEN_SECRET"),
|
|
scopes=scopes,
|
|
)
|