사이트 발행 성공과 Google 색인 관측은 별도 상태다. 외부 API 장애로 발행이 실패하거나 재시작 때 추적 정보가 사라지지 않도록 분리. - Google 클라이언트·배치·DB·Teams 알림 모듈 분리 - 기존 스케줄러 연결, 재시도·중복 실행 방지와 선택 설정 추가 - ORM·초기 DDL·마이그레이션·운영 설정 문서 동시 갱신 검증: 관련 59건 통과, compose 설정·diff 검사 통과. 추가 회귀 23건 통과, 기존 발행 검수 실패 1건은 변경 전 코드에서도 재현. 운영 배포·Google/Teams 실호출 미실행.
44 lines
1.8 KiB
Python
44 lines
1.8 KiB
Python
"""Google 로그인 설정과 분리한다. 서비스 계정 키는 서버 파일로만 읽는다."""
|
|
import os
|
|
from dataclasses import dataclass
|
|
from urllib.parse import urlsplit
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class SearchConsoleSettings:
|
|
property_url: str
|
|
credentials_file: str
|
|
alert_url: str = ""
|
|
alert_days: int = 7
|
|
|
|
|
|
def load_settings() -> SearchConsoleSettings | None:
|
|
if os.environ.get("GSC_ENABLED") != "1":
|
|
return None
|
|
prop = os.environ.get("GSC_PROPERTY_URL", "").strip()
|
|
key_file = os.environ.get("GSC_CREDENTIALS_FILE", "").strip()
|
|
if not prop or not key_file:
|
|
raise ValueError("GSC_CONFIG_MISSING")
|
|
parsed = urlsplit(prop)
|
|
domain_property = prop.startswith("sc-domain:") and bool(prop.removeprefix("sc-domain:"))
|
|
root_property = (parsed.scheme == "https" and parsed.hostname and parsed.path == "/"
|
|
and not parsed.query and not parsed.fragment and not parsed.username)
|
|
if not domain_property and not root_property:
|
|
raise ValueError("GSC_PROPERTY_INVALID")
|
|
days = int(os.environ.get("GSC_ALERT_DAYS", "7"))
|
|
if days < 1:
|
|
raise ValueError("GSC_ALERT_DAYS_INVALID")
|
|
return SearchConsoleSettings(prop, key_file, os.environ.get("GSC_ALERT_WEBHOOK_URL", ""), days)
|
|
|
|
|
|
def belongs_to_property(page_url: str, property_url: str) -> bool:
|
|
parsed = urlsplit(page_url)
|
|
if parsed.scheme != "https" or not parsed.hostname or parsed.username or parsed.password:
|
|
return False
|
|
if parsed.query or parsed.fragment:
|
|
return False
|
|
if property_url.startswith("sc-domain:"):
|
|
domain = property_url.removeprefix("sc-domain:").lower()
|
|
return bool(domain) and (parsed.hostname == domain or parsed.hostname.endswith("." + domain))
|
|
return page_url.startswith(property_url)
|