Files
waitlist/app/config.py
Roberto Musso f956f0a260 feat: Brevo double opt-in + contact sync
- Add brevo.py: transactional email sending + contact list sync via Brevo API
- Add token.py: stateless HMAC-signed confirmation tokens (no DB migration needed)
- Update routes.py: POST /waitlist sends confirmation email, GET /waitlist/confirm verifies token
- Update config.py: Brevo + confirmation settings (gracefully disabled when BREVO_API_KEY is empty)
- Update .env.example with new Brevo and confirmation variables
- Add httpx dependency
- Add 8 new tests (token roundtrip/expiry/tamper, confirm endpoint, Brevo mock)
2026-04-11 18:48:58 +02:00

39 lines
1.2 KiB
Python

import secrets
from pydantic_settings import BaseSettings
class Settings(BaseSettings):
DATABASE_URL: str = "postgresql+asyncpg://waitlist:changeme@localhost:5432/waitlist_db"
ALLOWED_ORIGINS: str = "https://adiuvai.com,https://www.adiuvai.com"
RATE_LIMIT_PER_MINUTE: int = 5
ENVIRONMENT: str = "development"
# Brevo (email)
BREVO_API_KEY: str = ""
BREVO_SENDER_EMAIL: str = "noreply@adiuvai.com"
BREVO_SENDER_NAME: str = "adiuvAI"
BREVO_LIST_ID: int = 0 # Brevo contact list ID for waitlist subscribers
# Confirmation link
CONFIRM_SECRET: str = secrets.token_hex(32) # override in production .env
CONFIRM_BASE_URL: str = "https://waitlist.adiuvai.com"
CONFIRM_TOKEN_EXPIRY_HOURS: int = 48
model_config = {"env_file": ".env", "env_file_encoding": "utf-8"}
@property
def origins_list(self) -> list[str]:
return [o.strip() for o in self.ALLOWED_ORIGINS.split(",") if o.strip()]
@property
def sync_database_url(self) -> str:
return self.DATABASE_URL.replace("+asyncpg", "+psycopg2")
@property
def brevo_configured(self) -> bool:
return bool(self.BREVO_API_KEY)
settings = Settings()