Arag / app /services /support_service.py
AuthorBot
Add fixed Contact Us tab and support email flow in admin panel.
851e167
Raw
History Blame Contribute Delete
4.32 kB
"""Author RAG β€” Support Service.
Business logic for admin support: publish-help request orchestration.
"""
from datetime import datetime, timezone
import structlog
from fastapi import HTTPException
from sqlalchemy.ext.asyncio import AsyncSession
from app.config import get_settings
from app.models.user import User
from app.repositories.book_repo import BookRepository
from app.schemas.admin import ContactRequest, PublishHelpRequest
from app.services.book_url_scraper import PLATFORM_DISPLAY
from app.services.platform_presence import SCORED_PLATFORMS
logger = structlog.get_logger(__name__)
_PLATFORM_NAMES = {
p["platform_id"]: p["display_name"] for p in SCORED_PLATFORMS
}
class SupportService:
"""Orchestrates publish-help requests and support config."""
def __init__(self, db: AsyncSession) -> None:
self._db = db
self._books = BookRepository(db)
@staticmethod
def get_config() -> dict:
"""Return support contact info for the admin UI."""
cfg = get_settings()
return {
"support_email": str(cfg.SUPPORT_EMAIL) if cfg.SUPPORT_EMAIL else None,
}
async def queue_publish_help_request(
self, user: User, body: PublishHelpRequest
) -> dict:
"""Validate, build payload, and queue publish-help email to support."""
cfg = get_settings()
if not cfg.SUPPORT_EMAIL:
raise HTTPException(503, "Support email is not configured")
book_meta = await self._resolve_book_meta(user.id, body)
platform_names = [
_PLATFORM_NAMES.get(pid, PLATFORM_DISPLAY.get(pid, pid.replace("_", " ").title()))
for pid in body.platform_ids
]
payload = {
"author_name": user.full_name or user.email,
"author_email": user.email,
"book_title": body.book_title,
"book_id": body.book_id,
"isbn": (book_meta or {}).get("isbn"),
"book_author": (book_meta or {}).get("book_author"),
"source_url": body.source_url or (book_meta or {}).get("source_url"),
"platform_names": platform_names,
"message": body.message,
"submitted_at": datetime.now(timezone.utc).isoformat(),
}
from app.tasks.email_task import send_publish_help_request as send_publish_help_task
send_publish_help_task.delay(payload)
logger.info(
"Publish help request queued",
author_id=user.id,
book_id=body.book_id,
platforms=body.platform_ids,
)
return {"message": "Request received β€” we'll reply within 24 hours"}
async def queue_contact_request(
self, user: User, body: ContactRequest
) -> dict:
"""Validate and queue a general contact email to support."""
cfg = get_settings()
if not cfg.SUPPORT_EMAIL:
raise HTTPException(503, "Support email is not configured")
category_labels = {
"general": "General",
"billing": "Billing",
"technical": "Technical",
"publishing": "Publishing",
}
payload = {
"author_name": user.full_name or user.email,
"author_email": user.email,
"category": category_labels.get(body.category, body.category),
"message": body.message,
"submitted_at": datetime.now(timezone.utc).isoformat(),
}
from app.tasks.email_task import send_contact_request as send_contact_task
send_contact_task.delay(payload)
logger.info("Contact request queued", author_id=user.id, category=body.category)
return {"message": "Message sent β€” we'll reply within 24 hours"}
async def _resolve_book_meta(
self, author_id: str, body: PublishHelpRequest
) -> dict | None:
"""Load ISBN/author/source_url from DB when book_id is provided."""
if not body.book_id:
return None
book = await self._books.get_by_id(body.book_id)
if not book or book.author_id != author_id:
raise HTTPException(404, "Book not found")
return {
"isbn": book.isbn,
"source_url": book.source_url or body.source_url,
"book_author": book.book_author,
}