Files
gochat/internal/handler/api/v1/captain_document_handler.go
T
2026-06-04 15:44:48 +08:00

171 lines
5.8 KiB
Go

package v1
import (
"net/http"
"strconv"
"github.com/gin-gonic/gin"
"github.com/gochat/gochat/internal/service"
applogger "github.com/gochat/gochat/pkg/logger"
"github.com/gochat/gochat/pkg/pagination"
"github.com/gochat/gochat/pkg/response"
)
// CaptainDocumentHandler handles CaptainDocument REST API endpoints.
// Reference: Chatwoot enterprise/app/controllers/api/v1/captain/documents_controller.rb
type CaptainDocumentHandler struct {
svc *service.CaptainDocumentService
}
// NewCaptainDocumentHandler creates a new CaptainDocumentHandler.
func NewCaptainDocumentHandler(svc *service.CaptainDocumentService) *CaptainDocumentHandler {
return &CaptainDocumentHandler{svc: svc}
}
// Create creates a new captain document.
// POST /api/v1/accounts/:account_id/captain_assistants/:assistant_id/documents
func (h *CaptainDocumentHandler) Create(c *gin.Context) {
accountID, err := strconv.ParseUint(c.Param("id"), 10, 64)
if err != nil {
response.AbortWithStatusError(c, http.StatusBadRequest, response.ErrBadRequest, "invalid account_id")
return
}
assistantID, err := strconv.ParseUint(c.Param("assistant_id"), 10, 64)
if err != nil {
response.AbortWithStatusError(c, http.StatusBadRequest, response.ErrBadRequest, "invalid assistant_id")
return
}
var req service.CreateDocumentRequest
if err := c.ShouldBindJSON(&req); err != nil {
response.AbortWithStatusError(c, http.StatusBadRequest, response.ErrValidation, err.Error())
return
}
doc, err := h.svc.Create(c.Request.Context(), uint(assistantID), uint(accountID), &req)
if err != nil {
applogger.L().Errorf("Create captain document: %v", err)
response.AbortWithStatusError(c, http.StatusInternalServerError, response.ErrInternal, "failed to create document")
return
}
response.Created(c, doc)
}
// Get retrieves a captain document by ID.
// GET /api/v1/accounts/:account_id/captain_documents/:id
func (h *CaptainDocumentHandler) Get(c *gin.Context) {
id, err := strconv.ParseUint(c.Param("id"), 10, 64)
if err != nil {
response.AbortWithStatusError(c, http.StatusBadRequest, response.ErrBadRequest, "invalid id")
return
}
doc, err := h.svc.Get(c.Request.Context(), uint(id))
if err != nil {
applogger.L().Errorf("Get captain document: %v", err)
response.AbortWithStatusError(c, http.StatusNotFound, response.ErrNotFound, "document not found")
return
}
response.OK(c, doc)
}
// Update updates an existing captain document.
// PUT /api/v1/accounts/:account_id/captain_documents/:id
func (h *CaptainDocumentHandler) Update(c *gin.Context) {
id, err := strconv.ParseUint(c.Param("id"), 10, 64)
if err != nil {
response.AbortWithStatusError(c, http.StatusBadRequest, response.ErrBadRequest, "invalid id")
return
}
var req service.UpdateDocumentRequest
if err := c.ShouldBindJSON(&req); err != nil {
response.AbortWithStatusError(c, http.StatusBadRequest, response.ErrValidation, err.Error())
return
}
doc, err := h.svc.Update(c.Request.Context(), uint(id), &req)
if err != nil {
applogger.L().Errorf("Update captain document: %v", err)
response.AbortWithStatusError(c, http.StatusInternalServerError, response.ErrInternal, "failed to update document")
return
}
response.OK(c, doc)
}
// Delete deletes a captain document.
// DELETE /api/v1/accounts/:account_id/captain_documents/:id
func (h *CaptainDocumentHandler) Delete(c *gin.Context) {
id, err := strconv.ParseUint(c.Param("id"), 10, 64)
if err != nil {
response.AbortWithStatusError(c, http.StatusBadRequest, response.ErrBadRequest, "invalid id")
return
}
if err := h.svc.Delete(c.Request.Context(), uint(id)); err != nil {
applogger.L().Errorf("Delete captain document: %v", err)
response.AbortWithStatusError(c, http.StatusInternalServerError, response.ErrInternal, "failed to delete document")
return
}
response.NoContent(c)
}
// List retrieves documents for an assistant.
// GET /api/v1/accounts/:account_id/captain_assistants/:assistant_id/documents
func (h *CaptainDocumentHandler) List(c *gin.Context) {
assistantID, err := strconv.ParseUint(c.Param("assistant_id"), 10, 64)
if err != nil {
response.AbortWithStatusError(c, http.StatusBadRequest, response.ErrBadRequest, "invalid assistant_id")
return
}
p := pagination.Parse(c)
docs, count, err := h.svc.List(c.Request.Context(), uint(assistantID), p.Offset, p.PerPage)
if err != nil {
applogger.L().Errorf("List captain documents: %v", err)
response.AbortWithStatusError(c, http.StatusInternalServerError, response.ErrInternal, "failed to list documents")
return
}
response.OKWithMeta(c, docs, p.Page, p.PerPage, count)
}
// ProcessDocument triggers document content extraction and embedding generation.
// POST /api/v1/accounts/:account_id/captain_documents/:id/process
func (h *CaptainDocumentHandler) ProcessDocument(c *gin.Context) {
id, err := strconv.ParseUint(c.Param("id"), 10, 64)
if err != nil {
response.AbortWithStatusError(c, http.StatusBadRequest, response.ErrBadRequest, "invalid id")
return
}
if err := h.svc.ProcessDocument(c.Request.Context(), uint(id)); err != nil {
applogger.L().Errorf("ProcessDocument: %v", err)
response.AbortWithStatusError(c, http.StatusInternalServerError, response.ErrInternal, "failed to process document")
return
}
response.OK(c, gin.H{"processed": true})
}
// SyncDocument triggers re-fetching content from the external URL.
// POST /api/v1/accounts/:account_id/captain_documents/:id/sync
func (h *CaptainDocumentHandler) SyncDocument(c *gin.Context) {
id, err := strconv.ParseUint(c.Param("id"), 10, 64)
if err != nil {
response.AbortWithStatusError(c, http.StatusBadRequest, response.ErrBadRequest, "invalid id")
return
}
if err := h.svc.SyncDocument(c.Request.Context(), uint(id)); err != nil {
applogger.L().Errorf("SyncDocument: %v", err)
response.AbortWithStatusError(c, http.StatusInternalServerError, response.ErrInternal, "failed to sync document")
return
}
response.OK(c, gin.H{"synced": true})
}