Align GoChat with Chatwoot frontend contracts
This commit is contained in:
@@ -7,6 +7,7 @@ import (
|
||||
"net/http/httptest"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@@ -19,6 +20,7 @@ import (
|
||||
"github.com/gochat/gochat/internal/model"
|
||||
"github.com/gochat/gochat/internal/repository"
|
||||
"github.com/gochat/gochat/internal/service"
|
||||
"github.com/gochat/gochat/internal/ws"
|
||||
)
|
||||
|
||||
func uintPtr(v uint) *uint { return &v }
|
||||
@@ -51,6 +53,38 @@ func setupNotificationHandler(t *testing.T, db *gorm.DB) *NotificationHandler {
|
||||
return NewNotificationHandler(ns)
|
||||
}
|
||||
|
||||
type notificationEventHub struct {
|
||||
mu sync.Mutex
|
||||
accounts map[uint][]byte
|
||||
}
|
||||
|
||||
func newNotificationEventHub() *notificationEventHub {
|
||||
return ¬ificationEventHub{accounts: map[uint][]byte{}}
|
||||
}
|
||||
|
||||
func (h *notificationEventHub) SendToAccount(accountID uint, data []byte) {
|
||||
h.mu.Lock()
|
||||
defer h.mu.Unlock()
|
||||
h.accounts[accountID] = data
|
||||
}
|
||||
|
||||
func (h *notificationEventHub) SendToRoom(_ string, _ []byte) {}
|
||||
|
||||
func (h *notificationEventHub) accountData(accountID uint) []byte {
|
||||
h.mu.Lock()
|
||||
defer h.mu.Unlock()
|
||||
return h.accounts[accountID]
|
||||
}
|
||||
|
||||
func decodeNotificationEvent(t *testing.T, hub *notificationEventHub, accountID uint) ws.WSMessage {
|
||||
t.Helper()
|
||||
data := hub.accountData(accountID)
|
||||
require.NotNil(t, data)
|
||||
var msg ws.WSMessage
|
||||
require.NoError(t, json.Unmarshal(data, &msg))
|
||||
return msg
|
||||
}
|
||||
|
||||
func setupNotificationRouter(handler *NotificationHandler) *gin.Engine {
|
||||
gin.SetMode(gin.TestMode)
|
||||
router := gin.New()
|
||||
@@ -279,6 +313,30 @@ func TestNotificationGet(t *testing.T) {
|
||||
sqlDB.Close()
|
||||
}
|
||||
|
||||
func TestNotificationGetDoesNotPublishRealtimeEvent(t *testing.T) {
|
||||
db := setupNotificationDB(t)
|
||||
handler := setupNotificationHandler(t, db)
|
||||
hub := newNotificationEventHub()
|
||||
handler.WithEventPublisher(ws.NewEventPublisherLocal(hub, nil))
|
||||
router := setupNotificationRouter(handler)
|
||||
|
||||
user := &model.User{Name: "Notification Get User", Email: "notification-get@example.com", Password: "pass", AccountID: 1}
|
||||
require.NoError(t, db.Create(user).Error)
|
||||
accountID := uint(1)
|
||||
notification := &model.Notification{UserID: user.ID, AccountID: &accountID, NotificationType: "conversation_mention", PrimaryActorType: "Conversation", PrimaryActorID: 1}
|
||||
require.NoError(t, db.Create(notification).Error)
|
||||
|
||||
w := httptest.NewRecorder()
|
||||
req, _ := http.NewRequest("GET", fmt.Sprintf("/api/v1/accounts/1/notifications/%d", notification.ID), nil)
|
||||
req.Header.Set("X-User-ID", strconv.FormatUint(uint64(user.ID), 10))
|
||||
router.ServeHTTP(w, req)
|
||||
require.Equal(t, http.StatusOK, w.Code)
|
||||
require.Nil(t, hub.accountData(accountID))
|
||||
|
||||
sqlDB, _ := db.DB()
|
||||
sqlDB.Close()
|
||||
}
|
||||
|
||||
func TestNotificationGetDifferentID(t *testing.T) {
|
||||
db := setupNotificationDB(t)
|
||||
handler := setupNotificationHandler(t, db)
|
||||
@@ -757,6 +815,76 @@ func TestNotificationHandler_UnreadWithDB(t *testing.T) {
|
||||
sqlDB.Close()
|
||||
}
|
||||
|
||||
func TestNotificationHandler_MutationsPublishChatwootRealtimePayload(t *testing.T) {
|
||||
db := setupNotificationDB(t)
|
||||
handler := setupNotificationHandler(t, db)
|
||||
hub := newNotificationEventHub()
|
||||
handler.WithEventPublisher(ws.NewEventPublisherLocal(hub, nil))
|
||||
router := setupNotificationRouter(handler)
|
||||
|
||||
user := &model.User{Name: "Notification Realtime User", Email: "notification-realtime@example.com", Password: "pass", AccountID: 1}
|
||||
require.NoError(t, db.Create(user).Error)
|
||||
accountID := uint(1)
|
||||
now := time.Now()
|
||||
readNotification := &model.Notification{UserID: user.ID, AccountID: &accountID, NotificationType: "conversation_assignment", PrimaryActorType: "Conversation", PrimaryActorID: 1}
|
||||
unreadNotification := &model.Notification{UserID: user.ID, AccountID: &accountID, NotificationType: "conversation_mention", PrimaryActorType: "Conversation", PrimaryActorID: 2, ReadAt: &now}
|
||||
snoozeNotification := &model.Notification{UserID: user.ID, AccountID: &accountID, NotificationType: "assigned_conversation_new_message", PrimaryActorType: "Conversation", PrimaryActorID: 3}
|
||||
deleteNotification := &model.Notification{UserID: user.ID, AccountID: &accountID, NotificationType: "message_created", PrimaryActorType: "Conversation", PrimaryActorID: 4}
|
||||
require.NoError(t, db.Create(readNotification).Error)
|
||||
require.NoError(t, db.Create(unreadNotification).Error)
|
||||
require.NoError(t, db.Create(snoozeNotification).Error)
|
||||
require.NoError(t, db.Create(deleteNotification).Error)
|
||||
|
||||
request := func(method, path, body string) ws.WSMessage {
|
||||
w := httptest.NewRecorder()
|
||||
req, _ := http.NewRequest(method, path, strings.NewReader(body))
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
req.Header.Set("X-User-ID", strconv.FormatUint(uint64(user.ID), 10))
|
||||
router.ServeHTTP(w, req)
|
||||
require.Equal(t, http.StatusOK, w.Code, w.Body.String())
|
||||
return decodeNotificationEvent(t, hub, accountID)
|
||||
}
|
||||
|
||||
msg := request(http.MethodPut, fmt.Sprintf("/api/v1/accounts/1/notifications/%d", readNotification.ID), "")
|
||||
require.Equal(t, ws.EventNotificationUpdated, msg.Event)
|
||||
data := msg.Data.(map[string]any)
|
||||
require.Equal(t, float64(2), data["unread_count"])
|
||||
require.Equal(t, float64(4), data["count"])
|
||||
notification := data["notification"].(map[string]any)
|
||||
require.Equal(t, float64(readNotification.ID), notification["id"])
|
||||
require.NotNil(t, notification["read_at"])
|
||||
|
||||
msg = request(http.MethodPost, fmt.Sprintf("/api/v1/accounts/1/notifications/%d/unread", unreadNotification.ID), "")
|
||||
require.Equal(t, ws.EventNotificationUpdated, msg.Event)
|
||||
data = msg.Data.(map[string]any)
|
||||
notification = data["notification"].(map[string]any)
|
||||
require.Equal(t, float64(unreadNotification.ID), notification["id"])
|
||||
require.Nil(t, notification["read_at"])
|
||||
require.Equal(t, float64(3), data["unread_count"])
|
||||
require.Equal(t, float64(4), data["count"])
|
||||
|
||||
snoozeUnix := time.Now().Add(time.Hour).Unix()
|
||||
msg = request(http.MethodPost, fmt.Sprintf("/api/v1/accounts/1/notifications/%d/snooze", snoozeNotification.ID), fmt.Sprintf(`{"snoozed_until":%d}`, snoozeUnix))
|
||||
require.Equal(t, ws.EventNotificationUpdated, msg.Event)
|
||||
data = msg.Data.(map[string]any)
|
||||
require.Equal(t, float64(3), data["unread_count"])
|
||||
require.Equal(t, float64(4), data["count"])
|
||||
notification = data["notification"].(map[string]any)
|
||||
require.Equal(t, float64(snoozeNotification.ID), notification["id"])
|
||||
require.NotNil(t, notification["snoozed_until"])
|
||||
|
||||
msg = request(http.MethodDelete, fmt.Sprintf("/api/v1/accounts/1/notifications/%d", deleteNotification.ID), "")
|
||||
require.Equal(t, ws.EventNotificationDeleted, msg.Event)
|
||||
data = msg.Data.(map[string]any)
|
||||
require.Equal(t, float64(2), data["unread_count"])
|
||||
require.Equal(t, float64(3), data["count"])
|
||||
notification = data["notification"].(map[string]any)
|
||||
require.Equal(t, float64(deleteNotification.ID), notification["id"])
|
||||
|
||||
sqlDB, _ := db.DB()
|
||||
sqlDB.Close()
|
||||
}
|
||||
|
||||
func TestNotificationHandler_Unread_InvalidID(t *testing.T) {
|
||||
db := setupNotificationDB(t)
|
||||
handler := setupNotificationHandler(t, db)
|
||||
|
||||
Reference in New Issue
Block a user