Add meeting display fields
This commit is contained in:
+104
-4
@@ -1926,8 +1926,9 @@ func serveIMMeetingList(wrt http.ResponseWriter, req *http.Request) {
|
||||
return
|
||||
}
|
||||
items := make([]map[string]any, 0, len(meetings))
|
||||
userSummaries := meetingUserSummaries(principal.TenantID, meetings)
|
||||
for i := range meetings {
|
||||
items = append(items, meetingPayload(&meetings[i], principal.Uid))
|
||||
items = append(items, meetingPayloadWithUserSummaries(&meetings[i], principal.Uid, userSummaries))
|
||||
}
|
||||
writeIMSuccess(wrt, req, map[string]any{
|
||||
"items": items,
|
||||
@@ -7273,22 +7274,37 @@ func organizationSearchPayloads(items []types.OrganizationSearchItem) []map[stri
|
||||
}
|
||||
|
||||
func meetingPayload(meeting *types.Meeting, viewer types.Uid) map[string]any {
|
||||
participants := meetingParticipantPayloads(meeting.Participants)
|
||||
return meetingPayloadWithUserSummaries(meeting, viewer, nil)
|
||||
}
|
||||
|
||||
func meetingPayloadWithUserSummaries(meeting *types.Meeting, viewer types.Uid, userSummaries map[types.Uid]map[string]any) map[string]any {
|
||||
participants := meetingParticipantPayloadsWithSummaries(meeting.Participants, userSummaries)
|
||||
organizer := meetingUserSummary(meeting.OrganizerID, userSummaries)
|
||||
startAt := meeting.StartAt.UTC()
|
||||
endAt := meeting.EndAt.UTC()
|
||||
data := map[string]any{
|
||||
"meeting_id": meeting.MeetingID,
|
||||
"title": meeting.Title,
|
||||
"organizer_id": meeting.OrganizerID.UserId(),
|
||||
"start_at": meeting.StartAt.UTC().Format(time.RFC3339Nano),
|
||||
"end_at": meeting.EndAt.UTC().Format(time.RFC3339Nano),
|
||||
"organizer": organizer,
|
||||
"start_at": startAt.Format(time.RFC3339Nano),
|
||||
"end_at": endAt.Format(time.RFC3339Nano),
|
||||
"meeting_time": meetingTimeRange(startAt, endAt),
|
||||
"time_range": meetingTimeRange(startAt, endAt),
|
||||
"location": meeting.Location,
|
||||
"state": meeting.State,
|
||||
"reminder_minutes": meeting.ReminderMinutes,
|
||||
"version": meeting.Version,
|
||||
"participants": participants,
|
||||
"participant_count": len(participants),
|
||||
"participant_names": meetingParticipantNames(participants),
|
||||
"permissions": meetingPermissionsPayload(meeting, viewer),
|
||||
"created_at": meeting.CreatedAt.UTC().Format(time.RFC3339Nano),
|
||||
"updated_at": meeting.UpdatedAt.UTC().Format(time.RFC3339Nano),
|
||||
}
|
||||
if displayName, ok := organizer["display_name"]; ok {
|
||||
data["organizer_display_name"] = displayName
|
||||
}
|
||||
if meeting.CanceledAt != nil {
|
||||
data["canceled_at"] = meeting.CanceledAt.UTC().Format(time.RFC3339Nano)
|
||||
}
|
||||
@@ -7302,12 +7318,24 @@ func meetingPayload(meeting *types.Meeting, viewer types.Uid) map[string]any {
|
||||
}
|
||||
|
||||
func meetingParticipantPayloads(participants []types.MeetingParticipant) []map[string]any {
|
||||
return meetingParticipantPayloadsWithSummaries(participants, nil)
|
||||
}
|
||||
|
||||
func meetingParticipantPayloadsWithSummaries(participants []types.MeetingParticipant, userSummaries map[types.Uid]map[string]any) []map[string]any {
|
||||
items := make([]map[string]any, 0, len(participants))
|
||||
for _, participant := range participants {
|
||||
item := map[string]any{
|
||||
"user_id": participant.UserID.UserId(),
|
||||
"response": participant.Response,
|
||||
}
|
||||
if summary := meetingUserSummary(participant.UserID, userSummaries); summary != nil {
|
||||
if displayName, ok := summary["display_name"]; ok {
|
||||
item["display_name"] = displayName
|
||||
}
|
||||
if avatar, ok := summary["avatar_file_id"]; ok {
|
||||
item["avatar_file_id"] = avatar
|
||||
}
|
||||
}
|
||||
if participant.ResponseAt != nil {
|
||||
item["response_at"] = participant.ResponseAt.UTC().Format(time.RFC3339Nano)
|
||||
}
|
||||
@@ -7316,6 +7344,78 @@ func meetingParticipantPayloads(participants []types.MeetingParticipant) []map[s
|
||||
return items
|
||||
}
|
||||
|
||||
func meetingUserSummaries(tenantID types.TenantID, meetings []types.Meeting) map[types.Uid]map[string]any {
|
||||
if store.Users == nil {
|
||||
return nil
|
||||
}
|
||||
seen := make(map[types.Uid]bool)
|
||||
uids := make([]types.Uid, 0, len(meetings)*2)
|
||||
for _, meeting := range meetings {
|
||||
if !meeting.OrganizerID.IsZero() && !seen[meeting.OrganizerID] {
|
||||
seen[meeting.OrganizerID] = true
|
||||
uids = append(uids, meeting.OrganizerID)
|
||||
}
|
||||
for _, participant := range meeting.Participants {
|
||||
if !participant.UserID.IsZero() && !seen[participant.UserID] {
|
||||
seen[participant.UserID] = true
|
||||
uids = append(uids, participant.UserID)
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(uids) == 0 {
|
||||
return nil
|
||||
}
|
||||
users, err := store.Users.GetAll(tenantID, uids...)
|
||||
if err != nil {
|
||||
logs.Warn.Printf("im http: failed to load meeting user summaries: %v", err)
|
||||
return nil
|
||||
}
|
||||
summaries := make(map[types.Uid]map[string]any, len(users))
|
||||
for i := range users {
|
||||
uid := users[i].Uid()
|
||||
if uid.IsZero() {
|
||||
uid = types.ParseUid(users[i].Id)
|
||||
}
|
||||
if !uid.IsZero() {
|
||||
summaries[uid] = userSummaryPayload(&users[i], "")
|
||||
}
|
||||
}
|
||||
return summaries
|
||||
}
|
||||
|
||||
func meetingUserSummary(uid types.Uid, summaries map[types.Uid]map[string]any) map[string]any {
|
||||
if uid.IsZero() {
|
||||
return nil
|
||||
}
|
||||
if summary, ok := summaries[uid]; ok && summary != nil {
|
||||
return summary
|
||||
}
|
||||
return map[string]any{
|
||||
"user_id": uid.UserId(),
|
||||
"display_name": uid.UserId(),
|
||||
}
|
||||
}
|
||||
|
||||
func meetingParticipantNames(participants []map[string]any) []string {
|
||||
names := make([]string, 0, len(participants))
|
||||
for _, participant := range participants {
|
||||
if name := strings.TrimSpace(fmt.Sprint(participant["display_name"])); name != "" {
|
||||
names = append(names, name)
|
||||
}
|
||||
}
|
||||
return names
|
||||
}
|
||||
|
||||
func meetingTimeRange(startAt, endAt time.Time) string {
|
||||
if startAt.IsZero() || endAt.IsZero() {
|
||||
return ""
|
||||
}
|
||||
if startAt.Format("2006-01-02") == endAt.Format("2006-01-02") {
|
||||
return startAt.Format("2006-01-02 15:04") + "-" + endAt.Format("15:04")
|
||||
}
|
||||
return startAt.Format("2006-01-02 15:04") + "-" + endAt.Format("2006-01-02 15:04")
|
||||
}
|
||||
|
||||
func meetingParticipantUIDs(meeting *types.Meeting) []types.Uid {
|
||||
if meeting == nil {
|
||||
return nil
|
||||
|
||||
+18
-1
@@ -2374,6 +2374,7 @@ func TestServeIMMeetingsList(t *testing.T) {
|
||||
viewer := types.Uid(42)
|
||||
expectIMBearer(t, ctrl, "token-1", 7, viewer)
|
||||
oldMeetings := store.Meetings
|
||||
oldUsers := store.Users
|
||||
now := time.Now().UTC().Round(time.Millisecond)
|
||||
meetings := &testMeetingsStore{list: []types.Meeting{{
|
||||
MeetingID: "mtg_test",
|
||||
@@ -2391,7 +2392,15 @@ func TestServeIMMeetingsList(t *testing.T) {
|
||||
},
|
||||
}}}
|
||||
store.Meetings = meetings
|
||||
defer func() { store.Meetings = oldMeetings }()
|
||||
users := mock_store.NewMockUsersPersistenceInterface(ctrl)
|
||||
organizer := types.User{Public: map[string]any{"fn": "mzb"}}
|
||||
organizer.SetUid(viewer)
|
||||
users.EXPECT().GetAll(types.TenantID(7), viewer).Return([]types.User{organizer}, nil)
|
||||
store.Users = users
|
||||
defer func() {
|
||||
store.Meetings = oldMeetings
|
||||
store.Users = oldUsers
|
||||
}()
|
||||
|
||||
req := httptest.NewRequest(http.MethodGet, "/v1/im/meetings?limit=20&cursor=c1", nil)
|
||||
req.Header.Set("Authorization", "Bearer token-1")
|
||||
@@ -2409,6 +2418,14 @@ func TestServeIMMeetingsList(t *testing.T) {
|
||||
if items[0].(map[string]any)["meeting_id"] != "mtg_test" || data["has_more"] != true {
|
||||
t.Fatalf("unexpected meeting payload: %#v", data)
|
||||
}
|
||||
item := items[0].(map[string]any)
|
||||
if item["organizer_display_name"] != "mzb" || item["participant_count"].(float64) != 1 {
|
||||
t.Fatalf("missing meeting display fields: %#v", item)
|
||||
}
|
||||
participants := item["participants"].([]any)
|
||||
if participants[0].(map[string]any)["display_name"] != "mzb" {
|
||||
t.Fatalf("missing participant display name: %#v", participants)
|
||||
}
|
||||
}
|
||||
|
||||
func TestServeIMMeetingMyResponse(t *testing.T) {
|
||||
|
||||
Reference in New Issue
Block a user