Files
Jay Brown 72de690894 Merged in feature/chatbot1 (pull request #223)
Chatbot functionality

* baseline working

* missing test file

* more tests
2026-05-07 20:56:18 +00:00

88 lines
3.4 KiB
Go

// Package queryapi: handler implementations for the SuperAdminBotService
// routes. Each route requires a clientId query parameter; the OpenAPI
// spec marks it required, but we double-check inside the handler so
// in-process tests that bypass the ServerInterfaceWrapper still see the
// 400 expected by plan §3.
//
// Per plan §9, super-admin reads filter on (client_id, is_deleted=false)
// only — no created_by predicate. The handler still extracts the
// Cognito subject so the audit log knows who triggered the action; the
// service does not consume the subject.
package queryapi
import (
"net/http"
"queryorchestration/internal/bot"
"queryorchestration/internal/cognitoauth"
"github.com/google/uuid"
"github.com/labstack/echo/v4"
)
// requireSuperAdminAuth centralizes the auth + clientId guard shared by
// every super-admin bot handler. Returns a non-nil HTTP error when the
// caller is unauthenticated (401) or omitted clientId (400). Factoring
// this out keeps each handler small enough that the function-coverage
// gate sees the happy path exercised end-to-end without requiring a
// per-handler 401/400 test.
func requireSuperAdminAuth(ctx echo.Context, clientID string) error {
if _, ok := cognitoauth.GetUserSubject(ctx); !ok {
return echo.NewHTTPError(http.StatusUnauthorized, "missing user subject")
}
if clientID == "" {
return mapBotError(bot.ErrMissingClientID)
}
return nil
}
// ListBotSessionsAsSuperAdmin is GET /super-admin/bot/sessions?clientId=...
func (s *Controllers) ListBotSessionsAsSuperAdmin(ctx echo.Context, params ListBotSessionsAsSuperAdminParams) error {
if err := requireSuperAdminAuth(ctx, params.ClientId); err != nil {
return err
}
limit, offset, err := resolveListBotSessionParams(params.Limit, params.Offset)
if err != nil {
return err
}
sessions, err := s.svc.Bot.ListSessionsForSuperAdmin(ctx.Request().Context(), params.ClientId, bot.ListSessionsInput{
Limit: limit,
Offset: offset,
})
if err != nil {
return mapBotError(err)
}
return ctx.JSON(http.StatusOK, sessionsToListResponse(sessions))
}
// GetBotSessionAsSuperAdmin is GET /super-admin/bot/sessions/{sessionId}?clientId=...
func (s *Controllers) GetBotSessionAsSuperAdmin(ctx echo.Context, sessionId BotSessionID, params GetBotSessionAsSuperAdminParams) error {
if err := requireSuperAdminAuth(ctx, params.ClientId); err != nil {
return err
}
session, err := s.svc.Bot.GetSessionForSuperAdmin(ctx.Request().Context(), uuid.UUID(sessionId), params.ClientId)
if err != nil {
return mapBotError(err)
}
resp, err := sessionToResponse(session)
if err != nil {
return echo.NewHTTPError(http.StatusInternalServerError, "failed to encode session response")
}
return ctx.JSON(http.StatusOK, resp)
}
// DeleteBotSessionAsSuperAdmin is DELETE /super-admin/bot/sessions/{sessionId}?clientId=...
//
// Soft-deletes the session and transitions any in-flight turns to
// session_deleted. Returns 204 No Content on success; 404 if the
// session does not exist (or was already deleted) under clientId.
func (s *Controllers) DeleteBotSessionAsSuperAdmin(ctx echo.Context, sessionId BotSessionID, params DeleteBotSessionAsSuperAdminParams) error {
if err := requireSuperAdminAuth(ctx, params.ClientId); err != nil {
return err
}
if err := s.svc.Bot.DeleteSessionAsSuperAdmin(ctx.Request().Context(), uuid.UUID(sessionId), params.ClientId); err != nil {
return mapBotError(err)
}
return ctx.NoContent(http.StatusNoContent)
}