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
+91 -2
View File
@@ -391,6 +391,7 @@ type imGroupCreateRequest struct {
Name string `json:"name"`
MemberUserIDs []string `json:"member_user_ids,omitempty"`
AvatarFileID string `json:"avatar_file_id,omitempty"`
Description string `json:"description,omitempty"`
}
type imGroupPatchRequest struct {
@@ -1340,6 +1341,12 @@ func serveIMBootstrap(wrt http.ResponseWriter, req *http.Request) {
return
}
}
modulePayloads := workbenchModulePayloads(modules)
entryBadges, entries, err := bootstrapEntryPayloads(principal.TenantID, principal.Uid, modulePayloads)
if err != nil {
writeIMRelationError(wrt, req, err)
return
}
writeIMSuccess(wrt, req, map[string]any{
"features": map[string]any{
"create_group": true,
@@ -1354,7 +1361,9 @@ func serveIMBootstrap(wrt http.ResponseWriter, req *http.Request) {
"user_search": true,
"scan_qr": true,
},
"modules": workbenchModulePayloads(modules),
"entry_badges": entryBadges,
"entries": entries,
"modules": modulePayloads,
"workbench_version": workbenchVersion,
"system_topic": map[string]any{
"topic": "sys",
@@ -3293,12 +3302,20 @@ func serveIMGroupCreate(wrt http.ResponseWriter, req *http.Request) {
writeIMError(wrt, req, http.StatusBadRequest, 30000, imReasonMalformedRequest, "malformed request", nil)
return
}
description := strings.TrimSpace(body.Description)
if len([]rune(description)) > 200 {
writeIMError(wrt, req, http.StatusBadRequest, 30000, imReasonMalformedRequest, "malformed request", map[string]any{"field": "description"})
return
}
topicName := genTopicName()
now := time.Now().UTC().Round(time.Millisecond)
public := map[string]any{"name": name, "version": 1}
if avatar := strings.TrimSpace(body.AvatarFileID); avatar != "" {
public["avatar_file_id"] = avatar
}
if description != "" {
public["description"] = description
}
topic := &types.Topic{
ObjHeader: types.ObjHeader{Id: topicName},
TenantID: principal.TenantID,
@@ -3312,6 +3329,7 @@ func serveIMGroupCreate(wrt http.ResponseWriter, req *http.Request) {
OwnerUserID: principal.Uid,
Name: name,
AvatarFileID: strings.TrimSpace(body.AvatarFileID),
Description: description,
GroupStatus: types.GroupStatusActive,
MemberUploadFiles: true,
MemberPrivateChat: true,
@@ -5921,7 +5939,7 @@ func workbenchModulePayloads(modules []types.WorkbenchModule) []map[string]any {
"name": module.Name,
"icon_file_id": module.IconFileID,
"route": module.Route,
"unread_count": 0,
"unread_count": module.UnreadCount,
"enabled": module.Enabled,
"permission": module.Permission,
})
@@ -5929,6 +5947,77 @@ func workbenchModulePayloads(modules []types.WorkbenchModule) []map[string]any {
return items
}
func bootstrapEntryPayloads(tenantID types.TenantID, uid types.Uid, modules []map[string]any) (map[string]any, map[string]any, error) {
newFriendsPending := 0
if store.Relations != nil {
count, err := store.Relations.CountPendingFriendRequests(tenantID, uid)
if err != nil && !errors.Is(err, types.ErrNotFound) && !errors.Is(err, types.ErrUnsupported) {
return nil, nil, err
}
if err == nil {
newFriendsPending = count
}
}
systemUnread := 0
if store.Security != nil {
count, err := store.Security.CountUnreadSystemNotifications(tenantID, uid)
if err != nil && !errors.Is(err, types.ErrNotFound) && !errors.Is(err, types.ErrUnsupported) {
return nil, nil, err
}
if err == nil {
systemUnread = count
}
}
workbenchTotalUnread := 0
for _, module := range modules {
enabled, _ := module["enabled"].(bool)
if !enabled {
continue
}
workbenchTotalUnread += intFromAny(module["unread_count"])
}
entryBadges := map[string]any{
"contacts_total_unread": newFriendsPending,
"new_friends_pending_count": newFriendsPending,
"groups_unread_count": 0,
"file_assistant_unread_count": 0,
"system_unread_count": systemUnread,
"workbench_total_unread": workbenchTotalUnread,
}
entries := map[string]any{
"new_friends": map[string]any{
"enabled": true,
"route": "/contacts/new-friends",
"unread_count": newFriendsPending,
"unread_source": "business",
},
"groups": map[string]any{
"enabled": true,
"route": "/contacts/groups",
"unread_count": 0,
"unread_source": "business",
},
"file_assistant": map[string]any{
"enabled": true,
"route": "/chat/file-assistant",
"topic": "slf",
"unread_count": 0,
"unread_source": "topic",
},
"system_messages": map[string]any{
"enabled": true,
"route": "/chat/system",
"topic": "sys",
"unread_count": systemUnread,
"unread_source": "business",
},
}
return entryBadges, entries, nil
}
func organizationDepartmentPayloads(departments []types.OrganizationDepartment) []map[string]any {
items := make([]map[string]any, 0, len(departments))
for _, department := range departments {