feat: add message mutation sync
This commit is contained in:
@@ -548,6 +548,15 @@ func (s *testGroupBusinessStore) ListMutes(_ types.TenantID, _ string, _ string,
|
||||
return s.mutes, "", nil
|
||||
}
|
||||
|
||||
func (s *testGroupBusinessStore) GetMute(_ types.TenantID, _ string, uid types.Uid) (*types.GroupMute, error) {
|
||||
for i := range s.mutes {
|
||||
if s.mutes[i].UserID == uid && s.mutes[i].Status == types.GroupMuteStatusActive {
|
||||
return &s.mutes[i], nil
|
||||
}
|
||||
}
|
||||
return nil, types.ErrNotFound
|
||||
}
|
||||
|
||||
func (s *testGroupBusinessStore) UpsertMute(_ types.TenantID, mute *types.GroupMute) (*types.GroupMute, error) {
|
||||
mute.Version = 1
|
||||
s.mutes = append(s.mutes, *mute)
|
||||
@@ -5625,6 +5634,56 @@ func TestServeIMGroupAdminsMutesAndOwnerTransfer(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestServeIMGroupMutesMemberGetsOwnMuteOnly(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
oldStore := store.Store
|
||||
oldSubs := store.Subs
|
||||
oldGroupBusiness := store.GroupBusiness
|
||||
mockStore := mock_store.NewMockPersistentStorageInterface(ctrl)
|
||||
tokenAuth := mock_auth.NewMockAuthHandler(ctrl)
|
||||
mockStore.EXPECT().GetLogicalAuthHandler("token").Return(tokenAuth).Times(2)
|
||||
tokenAuth.EXPECT().IsInitialized().Return(true).Times(2)
|
||||
tokenAuth.EXPECT().Authenticate(auth.AuthContext{}, []byte("token-1")).
|
||||
Return(&auth.Rec{TenantID: 7, Uid: 43, AuthLevel: auth.LevelAuth}, nil, nil).Times(2)
|
||||
store.Store = mockStore
|
||||
subs := mock_store.NewMockSubsPersistenceInterface(ctrl)
|
||||
store.Subs = subs
|
||||
memberSub := &types.Subscription{TenantID: 7, User: types.Uid(43).String(), Topic: "grpAlpha", ModeWant: types.ModeCPublic, ModeGiven: types.ModeCPublic}
|
||||
subs.EXPECT().Get(types.TenantID(7), "grpAlpha", types.Uid(43), false).Return(memberSub, nil).Times(2)
|
||||
groupStore := &testGroupBusinessStore{mutes: []types.GroupMute{
|
||||
{Topic: "grpAlpha", UserID: types.Uid(42), MutedBy: types.Uid(99), MutedAt: time.Now().UTC(), Status: types.GroupMuteStatusActive, Version: 1},
|
||||
{Topic: "grpAlpha", UserID: types.Uid(43), MutedBy: types.Uid(99), MutedAt: time.Now().UTC(), Reason: "test", Status: types.GroupMuteStatusActive, Version: 2},
|
||||
}}
|
||||
store.GroupBusiness = groupStore
|
||||
defer func() {
|
||||
store.Store = oldStore
|
||||
store.Subs = oldSubs
|
||||
store.GroupBusiness = oldGroupBusiness
|
||||
}()
|
||||
|
||||
getReq := httptest.NewRequest(http.MethodGet, "/v1/im/groups/grpAlpha/mutes", nil)
|
||||
getReq.Header.Set("Authorization", "Bearer token-1")
|
||||
getRec := httptest.NewRecorder()
|
||||
serveIMGroupResource(getRec, getReq)
|
||||
if getRec.Code != http.StatusOK {
|
||||
t.Fatalf("member mute get status: got %d body=%s", getRec.Code, getRec.Body.String())
|
||||
}
|
||||
data := decodeIMHTTPResponse(t, getRec).Data.(map[string]any)
|
||||
items := data["items"].([]any)
|
||||
if len(items) != 1 || items[0].(map[string]any)["user_id"] != types.Uid(43).UserId() {
|
||||
t.Fatalf("member should only see own mute item: %#v", items)
|
||||
}
|
||||
|
||||
postReq := httptest.NewRequest(http.MethodPost, "/v1/im/groups/grpAlpha/mutes/batch", bytes.NewBufferString(`{"user_ids":["`+types.Uid(42).UserId()+`"]}`))
|
||||
postReq.Header.Set("Authorization", "Bearer token-1")
|
||||
postRec := httptest.NewRecorder()
|
||||
serveIMGroupResource(postRec, postReq)
|
||||
if postRec.Code != http.StatusForbidden {
|
||||
t.Fatalf("member mute post status: got %d body=%s", postRec.Code, postRec.Body.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestServeIMGroupDissolveConsumesActionToken(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
@@ -7647,6 +7706,62 @@ func TestServeIMMessageRecall(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestServeIMMessageMutations(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
actor := types.Uid(42)
|
||||
expectIMBearer(t, ctrl, "token-1", 7, actor)
|
||||
oldSubs := store.Subs
|
||||
oldMessages := store.Messages
|
||||
subs := mock_store.NewMockSubsPersistenceInterface(ctrl)
|
||||
messages := mock_store.NewMockMessagesPersistenceInterface(ctrl)
|
||||
store.Subs = subs
|
||||
store.Messages = messages
|
||||
defer func() {
|
||||
store.Subs = oldSubs
|
||||
store.Messages = oldMessages
|
||||
}()
|
||||
|
||||
subs.EXPECT().Get(types.TenantID(7), "grpRecall", actor, false).Return(&types.Subscription{
|
||||
TenantID: 7,
|
||||
User: actor.String(),
|
||||
Topic: "grpRecall",
|
||||
ModeWant: types.ModeCPublic,
|
||||
ModeGiven: types.ModeCPublic,
|
||||
}, nil)
|
||||
mutatedAt := time.Date(2026, 9, 15, 10, 0, 0, 0, time.UTC)
|
||||
messages.EXPECT().Mutations(types.TenantID(7), "grpRecall", actor, int64(1), 20).Return([]types.MessageMutation{{
|
||||
SeqId: 9,
|
||||
Version: 2,
|
||||
Event: "message.recalled",
|
||||
Operator: actor.UserId(),
|
||||
MutatedAt: mutatedAt,
|
||||
MutationVersion: 3,
|
||||
}}, "3", false, int64(3), nil)
|
||||
|
||||
req := httptest.NewRequest(http.MethodGet, "/v1/im/topics/grpRecall/message-mutations?since_version=1&limit=20", nil)
|
||||
req.Header.Set("Authorization", "Bearer token-1")
|
||||
rec := httptest.NewRecorder()
|
||||
|
||||
serveIMTopicMessageAction(rec, req)
|
||||
|
||||
if rec.Code != http.StatusOK {
|
||||
t.Fatalf("status: got %d, want %d; body=%s", rec.Code, http.StatusOK, rec.Body.String())
|
||||
}
|
||||
data := decodeIMHTTPResponse(t, rec).Data.(map[string]any)
|
||||
if data["mutation_version"].(float64) != 3 || data["next_cursor"] != "3" {
|
||||
t.Fatalf("unexpected mutation response: %#v", data)
|
||||
}
|
||||
items := data["items"].([]any)
|
||||
if len(items) != 1 {
|
||||
t.Fatalf("unexpected mutation items: %#v", items)
|
||||
}
|
||||
item := items[0].(map[string]any)
|
||||
if item["seq"].(float64) != 9 || item["version"].(float64) != 2 || item["event"] != "message.recalled" {
|
||||
t.Fatalf("unexpected mutation item: %#v", item)
|
||||
}
|
||||
}
|
||||
|
||||
func TestServeIMMessageBatchRecallPartialSuccess(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
|
||||
Reference in New Issue
Block a user