o2o-site-AEO/solution/backend/services/teams_webhook.py
Mina Choi 11d30bb3d1 [chore] solution,admin,ontology: 코드 주석을 한 줄로 — 히스토리 주석 삭제
여러 줄 주석이 설명보다 경위(예전·실측·지적)를 적고 있어 읽는 사람이 결론을 찾기 어려웠다.

- 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>
2026-09-28 16:05:19 +09:00

56 lines
1.7 KiB
Python

"""Microsoft Teams Workflows(수신 webhook) 로 어댑티브 카드 한 장을 보낸다."""
import os
import httpx
from common.logger import LOG
WEBHOOK_URL_ENV = "TEAMS_WEBHOOK_URL"
TIMEOUT_SEC = 10.0
def is_configured() -> bool:
return bool(os.environ.get(WEBHOOK_URL_ENV, "").strip())
def _webhook_url() -> str:
return os.environ.get(WEBHOOK_URL_ENV, "").strip()
def _card(title: str, detail: str) -> dict:
"""Adaptive Card 1.2 — Teams Workflows 가 받는 최소 모양(search_console_alerts.py 와 같은 스키마)."""
return {
"type": "message",
"attachments": [{
"contentType": "application/vnd.microsoft.card.adaptive",
"contentUrl": None,
"content": {
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
"type": "AdaptiveCard",
"version": "1.2",
"body": [
{"type": "TextBlock", "text": title, "weight": "Bolder", "wrap": True},
{"type": "TextBlock", "text": detail, "wrap": True},
],
},
}],
}
async def send(title: str, detail: str) -> bool:
"""설정된 경우에만 보낸다."""
url = _webhook_url()
if not url:
return False
if not url.startswith("https://"):
LOG.w("[alert] TEAMS_WEBHOOK_URL_INVALID — https 가 아니다")
return False
try:
async with httpx.AsyncClient(timeout=TIMEOUT_SEC, follow_redirects=False) as client:
response = await client.post(url, json=_card(title, detail))
response.raise_for_status()
return True
except httpx.HTTPError:
LOG.w("[alert] TEAMS_DELIVERY_FAILED")
return False