Arag / app /services /email_extensions.py
AuthorBot
Add enterprise growth APIs, billing, admin UI, and test suite.
12930b5
Raw
History Blame Contribute Delete
4.41 kB
"""Author RAG β€” Email Service Extensions.
Adds email templates required by Phase 1 billing flows:
- send_welcome: fired on account activation (POST /api/auth/activate)
- send_password_reset: fired by forgot-password flow
- send_payment_failed: dunning email (fired by Stripe webhook)
- send_subscription_cancelled: cancellation confirmation
- send_token_warning: author approaching budget limit (80% / 95%)
All methods are thin wrappers around _send() β€” the existing SMTP infrastructure.
"""
def _extend_email_service():
"""Monkey-patch new methods onto EmailService if they don't exist yet."""
from app.services.email_service import EmailService
from app.config import get_settings
cfg = get_settings()
if not hasattr(EmailService, "send_password_reset"):
def send_password_reset(self, to_email: str, reset_url: str) -> None:
"""Send HMAC-signed password reset link."""
self._send(
to=to_email,
subject="Reset your ChatBot AI password",
body=(
f"Hi,\n\n"
f"Click the link below to reset your password. "
f"This link expires in 1 hour.\n\n"
f"{reset_url}\n\n"
f"If you didn't request a password reset, you can ignore this email.\n\n"
f"β€” The ChatBot AI Team"
),
)
EmailService.send_password_reset = send_password_reset
if not hasattr(EmailService, "send_payment_failed"):
def send_payment_failed(self, to_email: str, author_name: str, grace_days: int = 7) -> None:
"""Dunning email β€” payment failed, grace period active."""
self._send(
to=to_email,
subject="⚠️ Payment failed β€” action required",
body=(
f"Hi {author_name},\n\n"
f"We couldn't process your subscription payment. "
f"Your chatbot will continue working for {grace_days} more days.\n\n"
f"Please update your payment method to avoid interruption:\n"
f"{cfg.FRONTEND_URL}/dashboard/billing\n\n"
f"Questions? Reply to this email.\n\n"
f"β€” The ChatBot AI Team"
),
)
EmailService.send_payment_failed = send_payment_failed
if not hasattr(EmailService, "send_subscription_cancelled"):
def send_subscription_cancelled(self, to_email: str, author_name: str, access_until: str) -> None:
"""Cancellation confirmation β€” access continues to period end."""
self._send(
to=to_email,
subject="Your subscription has been cancelled",
body=(
f"Hi {author_name},\n\n"
f"Your ChatBot AI subscription has been cancelled. "
f"You have access until {access_until}.\n\n"
f"We'd love to know why you left β€” reply to this email with feedback.\n\n"
f"You can reactivate any time at: {cfg.FRONTEND_URL}/#pricing\n\n"
f"β€” The ChatBot AI Team"
),
)
EmailService.send_subscription_cancelled = send_subscription_cancelled
if not hasattr(EmailService, "send_token_warning"):
def send_token_warning(self, to_email: str, author_name: str, pct_used: int) -> None:
"""Proactive token budget warning (80% or 95%)."""
threshold = "almost" if pct_used >= 95 else "80%"
self._send(
to=to_email,
subject=f"⚑ You've used {pct_used}% of your monthly AI budget",
body=(
f"Hi {author_name},\n\n"
f"You've used {pct_used}% of your monthly token budget. "
f"{'Your chatbot may stop responding soon.' if pct_used >= 95 else 'Heads up β€” you may want to upgrade before month end.'}\n\n"
f"Upgrade your plan: {cfg.FRONTEND_URL}/#pricing\n\n"
f"Or manage your billing: {cfg.FRONTEND_URL}/dashboard/billing\n\n"
f"β€” The ChatBot AI Team"
),
)
EmailService.send_token_warning = send_token_warning
# Auto-extend on import
_extend_email_service()