feat: add admin survey invite CRUD endpoints
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
82
backend/app/api/endpoints/admin_survey.py
Normal file
82
backend/app/api/endpoints/admin_survey.py
Normal file
@@ -0,0 +1,82 @@
|
||||
"""Admin endpoints for managing survey invites."""
|
||||
import logging
|
||||
from typing import Annotated
|
||||
|
||||
from fastapi import APIRouter, Depends
|
||||
from sqlalchemy import select
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from app.api.deps import require_admin
|
||||
from app.core.config import settings
|
||||
from app.core.database import get_db
|
||||
from app.core.email import EmailService
|
||||
from app.models.survey_invite import SurveyInvite
|
||||
from app.models.user import User
|
||||
from app.schemas.survey import SurveyInviteCreate, SurveyInviteResponse
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
router = APIRouter(prefix="/admin", tags=["admin-survey"])
|
||||
|
||||
FRONTEND_URL = "https://resolutionflow.com"
|
||||
|
||||
|
||||
def _build_invite_response(invite: SurveyInvite) -> SurveyInviteResponse:
|
||||
base_url = FRONTEND_URL if not settings.DEBUG else "http://localhost:5173"
|
||||
return SurveyInviteResponse(
|
||||
id=str(invite.id),
|
||||
token=invite.token,
|
||||
recipient_name=invite.recipient_name,
|
||||
recipient_email=invite.recipient_email,
|
||||
status=invite.status,
|
||||
email_sent=invite.email_sent,
|
||||
created_at=invite.created_at,
|
||||
completed_at=invite.completed_at,
|
||||
survey_url=f"{base_url}/survey?t={invite.token}",
|
||||
)
|
||||
|
||||
|
||||
@router.post("/survey-invites", response_model=SurveyInviteResponse)
|
||||
async def create_survey_invite(
|
||||
data: SurveyInviteCreate,
|
||||
db: Annotated[AsyncSession, Depends(get_db)],
|
||||
current_user: Annotated[User, Depends(require_admin)],
|
||||
):
|
||||
"""Create a survey invite. Optionally sends email."""
|
||||
invite = SurveyInvite(
|
||||
recipient_name=data.recipient_name,
|
||||
recipient_email=data.recipient_email,
|
||||
)
|
||||
db.add(invite)
|
||||
await db.flush()
|
||||
|
||||
if data.send_email and data.recipient_email:
|
||||
try:
|
||||
base_url = FRONTEND_URL if not settings.DEBUG else "http://localhost:5173"
|
||||
survey_url = f"{base_url}/survey?t={invite.token}"
|
||||
sent = await EmailService.send_survey_invite_email(
|
||||
to_email=data.recipient_email,
|
||||
recipient_name=data.recipient_name,
|
||||
survey_url=survey_url,
|
||||
)
|
||||
if sent:
|
||||
invite.email_sent = True
|
||||
except Exception:
|
||||
logger.exception("Failed to send survey invite email")
|
||||
|
||||
await db.commit()
|
||||
await db.refresh(invite)
|
||||
return _build_invite_response(invite)
|
||||
|
||||
|
||||
@router.get("/survey-invites", response_model=list[SurveyInviteResponse])
|
||||
async def list_survey_invites(
|
||||
db: Annotated[AsyncSession, Depends(get_db)],
|
||||
current_user: Annotated[User, Depends(require_admin)],
|
||||
):
|
||||
"""List all survey invites."""
|
||||
result = await db.execute(
|
||||
select(SurveyInvite).order_by(SurveyInvite.created_at.desc())
|
||||
)
|
||||
invites = result.scalars().all()
|
||||
return [_build_invite_response(i) for i in invites]
|
||||
@@ -10,6 +10,8 @@ from app.api.endpoints import ai_fix
|
||||
from app.api.endpoints import ai_chat
|
||||
from app.api.endpoints import copilot
|
||||
from app.api.endpoints import assistant_chat
|
||||
from app.api.endpoints import survey
|
||||
from app.api.endpoints import admin_survey
|
||||
|
||||
api_router = APIRouter()
|
||||
|
||||
@@ -44,3 +46,5 @@ api_router.include_router(ai_fix.router)
|
||||
api_router.include_router(ai_chat.router)
|
||||
api_router.include_router(copilot.router)
|
||||
api_router.include_router(assistant_chat.router)
|
||||
api_router.include_router(survey.router)
|
||||
api_router.include_router(admin_survey.router)
|
||||
|
||||
Reference in New Issue
Block a user