feat: add bootstrap entry badges

This commit is contained in:
richjohnrambo
2026-08-20 15:59:16 +08:00
parent d467323ecb
commit 6db2938672
9 changed files with 707 additions and 24 deletions
+58 -8
View File
@@ -92,6 +92,9 @@ type testRelationsStore struct {
deleted bool
canSend *bool
reason string
pendingCount int
countTenant types.TenantID
countUser types.Uid
friends []types.FriendListItem
friendRequests []types.FriendRequestListItem
searchResults []types.UserSearchItem
@@ -794,6 +797,12 @@ func (s *testRelationsStore) ListFriendRequests(_ types.TenantID, _ types.Uid, _
return s.friendRequests, "", nil
}
func (s *testRelationsStore) CountPendingFriendRequests(tenantID types.TenantID, uid types.Uid) (int, error) {
s.countTenant = tenantID
s.countUser = uid
return s.pendingCount, nil
}
func (s *testRelationsStore) ResolveFriendRequest(_ types.TenantID, requestID string, actor types.Uid, status string, handledAt time.Time) (*types.FriendRequest, error) {
return &types.FriendRequest{
TenantID: 7,
@@ -1695,15 +1704,23 @@ func TestServeIMBootstrapIncludesHomeCapabilities(t *testing.T) {
expectIMBearer(t, ctrl, "token-1", 7, 42)
oldSecurity := store.Security
oldWorkbench := store.Workbench
security := &testSecurityStore{realName: &types.RealNameVerification{Status: "verified"}}
oldRelations := store.Relations
security := &testSecurityStore{
realName: &types.RealNameVerification{Status: "verified"},
unreadNotifications: 4,
}
relations := &testRelationsStore{pendingCount: 2}
workbench := &testWorkbenchStore{version: 9, modules: []types.WorkbenchModule{
{Code: "organization", Name: "组织架构", Route: "/organization", Enabled: true, Permission: "enabled"},
{Code: "external", Name: "外链", Route: "https://example.com", Enabled: true, Permission: "enabled"},
{Code: "organization", Name: "组织架构", Route: "/organization", UnreadCount: 3, Enabled: true, Permission: "enabled"},
{Code: "meetings", Name: "会议通知", Route: "/meetings", UnreadCount: 5, Enabled: false, Permission: "enabled"},
{Code: "external", Name: "外链", Route: "https://example.com", UnreadCount: 9, Enabled: true, Permission: "enabled"},
}}
store.Security = security
store.Relations = relations
store.Workbench = workbench
defer func() {
store.Security = oldSecurity
store.Relations = oldRelations
store.Workbench = oldWorkbench
}()
@@ -1723,6 +1740,12 @@ func TestServeIMBootstrapIncludesHomeCapabilities(t *testing.T) {
if security.realNameTenant != 7 || security.realNameUser != 42 {
t.Fatalf("bootstrap realname lookup scope: tenant=%d uid=%s", security.realNameTenant, security.realNameUser)
}
if security.unreadTenant != 7 || security.unreadUser != 42 {
t.Fatalf("bootstrap system unread lookup scope: tenant=%d uid=%s", security.unreadTenant, security.unreadUser)
}
if relations.countTenant != 7 || relations.countUser != 42 {
t.Fatalf("bootstrap friend request count scope: tenant=%d uid=%s", relations.countTenant, relations.countUser)
}
if !workbench.calledOnce || workbench.tenantID != 7 || workbench.uid != 42 {
t.Fatalf("bootstrap workbench lookup scope: store=%#v", workbench)
}
@@ -1730,9 +1753,32 @@ func TestServeIMBootstrapIncludesHomeCapabilities(t *testing.T) {
t.Fatalf("unexpected bootstrap workbench version: %#v", data)
}
modules := data["modules"].([]any)
if len(modules) != 1 || modules[0].(map[string]any)["code"] != "organization" {
if len(modules) != 2 || modules[0].(map[string]any)["code"] != "organization" || modules[1].(map[string]any)["code"] != "meetings" {
t.Fatalf("unexpected bootstrap modules: %#v", modules)
}
if modules[0].(map[string]any)["unread_count"].(float64) != 3 {
t.Fatalf("unexpected bootstrap module unread: %#v", modules[0])
}
badges := data["entry_badges"].(map[string]any)
if badges["new_friends_pending_count"].(float64) != 2 ||
badges["contacts_total_unread"].(float64) != 2 ||
badges["system_unread_count"].(float64) != 4 ||
badges["workbench_total_unread"].(float64) != 3 {
t.Fatalf("unexpected bootstrap badges: %#v", badges)
}
entries := data["entries"].(map[string]any)
newFriends := entries["new_friends"].(map[string]any)
if newFriends["route"] != "/contacts/new-friends" || newFriends["unread_count"].(float64) != 2 || newFriends["unread_source"] != "business" {
t.Fatalf("unexpected new friends entry: %#v", newFriends)
}
systemMessages := entries["system_messages"].(map[string]any)
if systemMessages["topic"] != "sys" || systemMessages["unread_count"].(float64) != 4 || systemMessages["unread_source"] != "business" {
t.Fatalf("unexpected system messages entry: %#v", systemMessages)
}
fileAssistant := entries["file_assistant"].(map[string]any)
if fileAssistant["topic"] != "slf" || fileAssistant["unread_source"] != "topic" {
t.Fatalf("unexpected file assistant entry: %#v", fileAssistant)
}
realname := data["security"].(map[string]any)["realname"].(map[string]any)
if realname["status"] != "verified" {
t.Fatalf("unexpected bootstrap realname status: %#v", realname)
@@ -2747,7 +2793,8 @@ func TestServeIMGroupCreate(t *testing.T) {
subs := mock_store.NewMockSubsPersistenceInterface(ctrl)
store.Topics = topics
store.Subs = subs
store.GroupBusiness = &testGroupBusinessStore{}
groupBusiness := &testGroupBusinessStore{}
store.GroupBusiness = groupBusiness
defer func() {
store.Store = oldStore
store.Topics = oldTopics
@@ -2760,7 +2807,7 @@ func TestServeIMGroupCreate(t *testing.T) {
TenantID: 7,
Owner: types.Uid(42).String(),
SubCnt: 2,
Public: map[string]any{"name": "New Group", "avatar_file_id": "file-1", "version": 1},
Public: map[string]any{"name": "New Group", "avatar_file_id": "file-1", "description": "Project discussion", "version": 1},
}, nil)
subs.EXPECT().Get(types.TenantID(7), "grpnewgroup", types.Uid(42), false).Return(&types.Subscription{
TenantID: 7,
@@ -2770,7 +2817,7 @@ func TestServeIMGroupCreate(t *testing.T) {
ModeGiven: types.ModeCFull,
}, nil)
req := httptest.NewRequest(http.MethodPost, "/v1/im/groups", bytes.NewBufferString(`{"name":"New Group","member_user_ids":["usrAgAAAAAAAAA"],"avatar_file_id":"file-1"}`))
req := httptest.NewRequest(http.MethodPost, "/v1/im/groups", bytes.NewBufferString(`{"name":"New Group","description":"Project discussion","member_user_ids":["usrAgAAAAAAAAA"],"avatar_file_id":"file-1"}`))
req.Header.Set("Authorization", "Bearer token-1")
rec := httptest.NewRecorder()
@@ -2780,9 +2827,12 @@ func TestServeIMGroupCreate(t *testing.T) {
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["topic"] != "grpnewgroup" || data["name"] != "New Group" {
if data["topic"] != "grpnewgroup" || data["name"] != "New Group" || data["description"] != "Project discussion" {
t.Fatalf("unexpected group create response: %#v", data)
}
if groupBusiness.settings == nil || groupBusiness.settings.Description != "Project discussion" {
t.Fatalf("group settings missing description: %#v", groupBusiness.settings)
}
}
func TestServeIMGroupDetailPatchSettingsProfileAndLeave(t *testing.T) {