141 lines
4.8 KiB
Go
141 lines
4.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"
|
|
)
|
|
|
|
// WebWidgetOfflineHandler handles admin CRUD for widget offline messages.
|
|
// These endpoints require agent JWT authentication and account scope.
|
|
// Reference: Chatwoot admin view of pending offline messages from web widget visitors.
|
|
type WebWidgetOfflineHandler struct {
|
|
widgetSvc *service.WidgetService
|
|
inboxSvc *service.InboxService
|
|
}
|
|
|
|
// NewWebWidgetOfflineHandler creates a new admin widget offline message handler.
|
|
func NewWebWidgetOfflineHandler(widgetSvc *service.WidgetService, inboxSvc *service.InboxService) *WebWidgetOfflineHandler {
|
|
return &WebWidgetOfflineHandler{widgetSvc: widgetSvc, inboxSvc: inboxSvc}
|
|
}
|
|
|
|
// ListOfflineMessages retrieves paginated offline messages for an account.
|
|
// GET /api/v1/accounts/:account_id/web_widgets/offline_messages
|
|
func (h *WebWidgetOfflineHandler) ListOfflineMessages(c *gin.Context) {
|
|
accountIDStr := c.Param("id")
|
|
accountID, err := strconv.ParseUint(accountIDStr, 10, 64)
|
|
if err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid account_id"})
|
|
return
|
|
}
|
|
|
|
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
|
|
pageSize, _ := strconv.Atoi(c.DefaultQuery("page_size", "25"))
|
|
if page < 1 {
|
|
page = 1
|
|
}
|
|
if pageSize < 1 || pageSize > 100 {
|
|
pageSize = 25
|
|
}
|
|
|
|
msgs, total, err := h.widgetSvc.ListOfflineMessagesByAccount(c.Request.Context(), uint(accountID), page, pageSize)
|
|
if err != nil {
|
|
applogger.L().Errorf("Failed to list offline messages for account=%d: %v", accountID, err)
|
|
c.JSON(http.StatusUnprocessableEntity, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
|
|
c.JSON(http.StatusOK, gin.H{
|
|
"offline_messages": msgs,
|
|
"meta": gin.H{
|
|
"page": page,
|
|
"page_size": pageSize,
|
|
"total_count": total,
|
|
},
|
|
})
|
|
}
|
|
|
|
// ListOfflineMessagesByInbox retrieves offline messages for a specific inbox.
|
|
// GET /api/v1/accounts/:account_id/inboxes/:inbox_id/web_widget/offline_messages
|
|
func (h *WebWidgetOfflineHandler) ListOfflineMessagesByInbox(c *gin.Context) {
|
|
inboxIDStr := c.Param("inbox_id")
|
|
inboxID, err := strconv.ParseUint(inboxIDStr, 10, 64)
|
|
if err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid inbox_id"})
|
|
return
|
|
}
|
|
|
|
accountIDStr := c.Param("id")
|
|
accountID, err := strconv.ParseUint(accountIDStr, 10, 64)
|
|
if err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid account_id"})
|
|
return
|
|
}
|
|
|
|
// Verify inbox belongs to account
|
|
inbox, err := h.inboxSvc.GetByAccountAndID(c.Request.Context(), uint(accountID), uint(inboxID))
|
|
if err != nil {
|
|
c.JSON(http.StatusNotFound, gin.H{"error": "inbox not found"})
|
|
return
|
|
}
|
|
if inbox.ChannelType != "web_widget" {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "offline messages only supported for web_widget channel"})
|
|
return
|
|
}
|
|
|
|
msgs, err := h.widgetSvc.GetOfflineMessages(c.Request.Context(), uint(inboxID))
|
|
if err != nil {
|
|
applogger.L().Errorf("Failed to get offline messages for inbox=%d: %v", inboxID, err)
|
|
c.JSON(http.StatusUnprocessableEntity, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
|
|
c.JSON(http.StatusOK, gin.H{"offline_messages": msgs})
|
|
}
|
|
|
|
// DismissOfflineMessage marks an offline message as dismissed by an agent.
|
|
// PUT /api/v1/accounts/:account_id/web_widgets/offline_messages/:offline_message_id/dismiss
|
|
func (h *WebWidgetOfflineHandler) DismissOfflineMessage(c *gin.Context) {
|
|
offlineMsgIDStr := c.Param("offline_message_id")
|
|
offlineMsgID, err := strconv.ParseUint(offlineMsgIDStr, 10, 64)
|
|
if err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid offline_message_id"})
|
|
return
|
|
}
|
|
|
|
err = h.widgetSvc.DismissOfflineMessage(c.Request.Context(), uint(offlineMsgID))
|
|
if err != nil {
|
|
applogger.L().Errorf("Failed to dismiss offline message=%d: %v", offlineMsgID, err)
|
|
c.JSON(http.StatusUnprocessableEntity, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
|
|
c.JSON(http.StatusOK, gin.H{"message": "offline message dismissed"})
|
|
}
|
|
|
|
// ConvertOfflineMessage converts an offline message into a conversation.
|
|
// PUT /api/v1/accounts/:account_id/web_widgets/offline_messages/:offline_message_id/convert
|
|
func (h *WebWidgetOfflineHandler) ConvertOfflineMessage(c *gin.Context) {
|
|
offlineMsgIDStr := c.Param("offline_message_id")
|
|
offlineMsgID, err := strconv.ParseUint(offlineMsgIDStr, 10, 64)
|
|
if err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid offline_message_id"})
|
|
return
|
|
}
|
|
|
|
conversation, message, err := h.widgetSvc.ConvertOfflineMessageToConversation(c.Request.Context(), uint(offlineMsgID))
|
|
if err != nil {
|
|
applogger.L().Errorf("Failed to convert offline message=%d: %v", offlineMsgID, err)
|
|
c.JSON(http.StatusUnprocessableEntity, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
|
|
c.JSON(http.StatusOK, gin.H{
|
|
"conversation": conversation,
|
|
"message": message,
|
|
})
|
|
} |