H-337: fix Web Channel availability and realtime delivery (#60)
* H-337: fix Web Channel availability and realtime delivery * fix(widget): preserve realtime sender and activity contracts * fix(widget): keep realtime sender payloads consistent * fix(widget): make public message persistence atomic * fix(inbox): keep availability projection out of schema --------- Co-authored-by: Rogee <rogee@ipao.vip>
This commit is contained in:
@@ -12,20 +12,14 @@ import (
|
||||
"github.com/gochat/gochat/internal/model"
|
||||
"github.com/gochat/gochat/internal/service"
|
||||
"github.com/gochat/gochat/internal/webhookutil"
|
||||
wspkg "github.com/gochat/gochat/internal/ws"
|
||||
)
|
||||
|
||||
type widgetEventPublisher interface {
|
||||
PublishWidgetEvent(accountID uint, pubsubToken string, eventType string, payload interface{})
|
||||
}
|
||||
|
||||
// WidgetHandler handles the public-facing widget API endpoints.
|
||||
// These endpoints are accessed by the embedded JS widget on customer websites
|
||||
// and do not require agent JWT authentication — they use a widget_token instead.
|
||||
// Reference: Chatwoot app/controllers/api/v1/widget_messages_controller.rb
|
||||
type WidgetHandler struct {
|
||||
widgetService *service.WidgetService
|
||||
eventPublisher widgetEventPublisher
|
||||
widgetService *service.WidgetService
|
||||
}
|
||||
|
||||
// NewHandler creates a new WidgetHandler with the WidgetService dependency.
|
||||
@@ -35,11 +29,6 @@ func NewHandler(widgetService *service.WidgetService) *WidgetHandler {
|
||||
}
|
||||
}
|
||||
|
||||
func (h *WidgetHandler) WithEventPublisher(publisher widgetEventPublisher) *WidgetHandler {
|
||||
h.eventPublisher = publisher
|
||||
return h
|
||||
}
|
||||
|
||||
// Init handles widget initialization — authenticates/creates a contact
|
||||
// and returns a widget_token (pubsub_token) for subsequent requests.
|
||||
// POST /widget/init
|
||||
@@ -212,7 +201,6 @@ func (h *WidgetHandler) SendMessage(c *gin.Context) {
|
||||
if len(resp.Attachments) > 0 {
|
||||
payload["attachments"] = widgetAttachmentPayloads(resp.Attachments)
|
||||
}
|
||||
h.publishWidgetMessageEvent(req.WidgetToken, payload)
|
||||
c.JSON(http.StatusOK, resp)
|
||||
return
|
||||
}
|
||||
@@ -220,7 +208,6 @@ func (h *WidgetHandler) SendMessage(c *gin.Context) {
|
||||
if len(resp.Attachments) > 0 {
|
||||
payload["attachments"] = widgetAttachmentPayloads(resp.Attachments)
|
||||
}
|
||||
h.publishWidgetMessageEvent(req.WidgetToken, payload)
|
||||
c.JSON(http.StatusOK, payload)
|
||||
}
|
||||
|
||||
@@ -262,40 +249,6 @@ func (h *WidgetHandler) UpdateMessage(c *gin.Context) {
|
||||
c.JSON(http.StatusOK, gin.H{"contact": widgetContactFullPayload(contact)})
|
||||
}
|
||||
|
||||
func (h *WidgetHandler) publishWidgetMessageEvent(pubsubToken string, payload gin.H) {
|
||||
if h.eventPublisher == nil || payload == nil {
|
||||
return
|
||||
}
|
||||
accountID := uintFromPayload(payload["account_id"])
|
||||
if accountID == 0 {
|
||||
accountID = uintFromPayload(payload["accountId"])
|
||||
}
|
||||
if accountID == 0 {
|
||||
return
|
||||
}
|
||||
h.eventPublisher.PublishWidgetEvent(accountID, pubsubToken, wspkg.EventMessageCreated, payload)
|
||||
}
|
||||
|
||||
func uintFromPayload(value any) uint {
|
||||
switch typed := value.(type) {
|
||||
case uint:
|
||||
return typed
|
||||
case int:
|
||||
if typed > 0 {
|
||||
return uint(typed)
|
||||
}
|
||||
case int64:
|
||||
if typed > 0 {
|
||||
return uint(typed)
|
||||
}
|
||||
case float64:
|
||||
if typed > 0 {
|
||||
return uint(typed)
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// GetLatestMessages implements Chatwoot's GET /api/v1/widget/messages endpoint.
|
||||
func (h *WidgetHandler) GetLatestMessages(c *gin.Context) {
|
||||
widgetToken := widgetTokenFromRequest(c)
|
||||
|
||||
Reference in New Issue
Block a user