fix: align meeting note payloads
This commit is contained in:
+64
-26
@@ -226,27 +226,32 @@ func meetingPayload(meeting store.Meeting, viewer int64) map[string]any {
|
||||
if recorderID == 0 {
|
||||
recorderID = meeting.OrganizerID
|
||||
}
|
||||
organizer := userSummary(meeting.OrganizerID, meeting.Organizer)
|
||||
recorder := userSummary(recorderID, meeting.Recorder)
|
||||
state := meetingState(meeting)
|
||||
data := map[string]any{
|
||||
"meeting_id": meeting.MeetingID,
|
||||
"title": meeting.Title,
|
||||
"organizer_id": formatUserID(meeting.OrganizerID),
|
||||
"organizer": userSummary(meeting.OrganizerID),
|
||||
"recorder_user_id": formatUserID(recorderID),
|
||||
"recorder": userSummary(recorderID),
|
||||
"start_at": meeting.StartAt.UTC().Format(time.RFC3339Nano),
|
||||
"end_at": meeting.EndAt.UTC().Format(time.RFC3339Nano),
|
||||
"meeting_time": timeRange(meeting.StartAt, meeting.EndAt),
|
||||
"time_range": timeRange(meeting.StartAt, meeting.EndAt),
|
||||
"location": meeting.Location,
|
||||
"state": meeting.State,
|
||||
"reminder_minutes": jsonList(meeting.ReminderMinutes),
|
||||
"version": meeting.Version,
|
||||
"participants": participants,
|
||||
"participant_count": len(participants),
|
||||
"participant_names": []string{},
|
||||
"permissions": meetingPermissions(meeting, viewer),
|
||||
"created_at": meeting.CreatedAt.UTC().Format(time.RFC3339Nano),
|
||||
"updated_at": meeting.UpdatedAt.UTC().Format(time.RFC3339Nano),
|
||||
"meeting_id": meeting.MeetingID,
|
||||
"title": meeting.Title,
|
||||
"organizer_id": formatUserID(meeting.OrganizerID),
|
||||
"organizer": organizer,
|
||||
"organizer_display_name": organizer["display_name"],
|
||||
"recorder_user_id": formatUserID(recorderID),
|
||||
"recorder": recorder,
|
||||
"recorder_display_name": recorder["display_name"],
|
||||
"start_at": meeting.StartAt.UTC().Format(time.RFC3339Nano),
|
||||
"end_at": meeting.EndAt.UTC().Format(time.RFC3339Nano),
|
||||
"meeting_time": timeRange(meeting.StartAt, meeting.EndAt),
|
||||
"time_range": timeRange(meeting.StartAt, meeting.EndAt),
|
||||
"location": meeting.Location,
|
||||
"state": state,
|
||||
"reminder_minutes": jsonList(meeting.ReminderMinutes),
|
||||
"version": meeting.Version,
|
||||
"participants": participants,
|
||||
"participant_count": len(participants),
|
||||
"participant_names": meetingParticipantNames(participants),
|
||||
"permissions": meetingPermissions(meeting, viewer),
|
||||
"created_at": meeting.CreatedAt.UTC().Format(time.RFC3339Nano),
|
||||
"updated_at": meeting.UpdatedAt.UTC().Format(time.RFC3339Nano),
|
||||
}
|
||||
if meeting.CanceledAt != nil {
|
||||
data["canceled_at"] = meeting.CanceledAt.UTC().Format(time.RFC3339Nano)
|
||||
@@ -263,7 +268,11 @@ func meetingPayload(meeting store.Meeting, viewer int64) map[string]any {
|
||||
func meetingParticipantPayloads(participants []store.MeetingParticipant) []map[string]any {
|
||||
items := make([]map[string]any, 0, len(participants))
|
||||
for _, participant := range participants {
|
||||
item := map[string]any{"user_id": formatUserID(participant.UserID), "response": participant.Response}
|
||||
summary := userSummary(participant.UserID, participant.User)
|
||||
item := map[string]any{"user_id": formatUserID(participant.UserID), "response": participant.Response, "display_name": summary["display_name"]}
|
||||
if avatarFileID, ok := summary["avatar_file_id"]; ok {
|
||||
item["avatar_file_id"] = avatarFileID
|
||||
}
|
||||
if participant.ResponseAt != nil {
|
||||
item["response_at"] = participant.ResponseAt.UTC().Format(time.RFC3339Nano)
|
||||
}
|
||||
@@ -319,7 +328,7 @@ func meetingNoteFilePayload(file store.MeetingNoteFile, viewer int64) map[string
|
||||
"preview_mode": file.PreviewMode,
|
||||
"preview_file_id": file.PreviewFileID,
|
||||
"uploader_user_id": formatUserID(file.UploaderID),
|
||||
"uploader": userSummary(file.UploaderID),
|
||||
"uploader": userSummary(file.UploaderID, store.UserSummary{}),
|
||||
"version": file.Version,
|
||||
"permissions": map[string]any{
|
||||
"can_preview": file.Status == "active",
|
||||
@@ -420,7 +429,7 @@ func mailboxSubmissionPayload(submission store.MailboxSubmission) map[string]any
|
||||
|
||||
func meetingPermissions(meeting store.Meeting, viewer int64) map[string]any {
|
||||
isOrganizer := meeting.OrganizerID == viewer
|
||||
isScheduled := meeting.State == "scheduled"
|
||||
isScheduled := meetingState(meeting) == "scheduled"
|
||||
return map[string]any{
|
||||
"can_update": isOrganizer && isScheduled,
|
||||
"can_cancel": isOrganizer && isScheduled,
|
||||
@@ -434,12 +443,41 @@ func meetingNotePermissions(meeting store.Meeting, viewer int64) map[string]any
|
||||
if recorderID == 0 {
|
||||
recorderID = meeting.OrganizerID
|
||||
}
|
||||
canWrite := recorderID == viewer || meeting.OrganizerID == viewer
|
||||
readable := meetingState(meeting) == "ended"
|
||||
canWrite := readable && (recorderID == viewer || meeting.OrganizerID == viewer)
|
||||
return map[string]any{"can_view": true, "can_upload": canWrite, "can_replace": canWrite, "can_delete": canWrite, "can_download": true}
|
||||
}
|
||||
|
||||
func userSummary(userID int64) map[string]any {
|
||||
return map[string]any{"user_id": formatUserID(userID), "display_name": formatUserID(userID)}
|
||||
func userSummary(userID int64, summary store.UserSummary) map[string]any {
|
||||
displayName := strings.TrimSpace(summary.DisplayName)
|
||||
if displayName == "" {
|
||||
displayName = formatUserID(userID)
|
||||
}
|
||||
data := map[string]any{"user_id": formatUserID(userID), "display_name": displayName}
|
||||
if strings.TrimSpace(summary.AvatarFileID) != "" {
|
||||
data["avatar_file_id"] = strings.TrimSpace(summary.AvatarFileID)
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
func meetingState(meeting store.Meeting) string {
|
||||
state := strings.TrimSpace(meeting.State)
|
||||
if state == "scheduled" && !meeting.EndAt.IsZero() && !time.Now().UTC().Before(meeting.EndAt.UTC()) {
|
||||
return "ended"
|
||||
}
|
||||
return state
|
||||
}
|
||||
|
||||
func meetingParticipantNames(participants []map[string]any) []string {
|
||||
names := make([]string, 0, len(participants))
|
||||
for _, participant := range participants {
|
||||
name, _ := participant["display_name"].(string)
|
||||
name = strings.TrimSpace(name)
|
||||
if name != "" {
|
||||
names = append(names, name)
|
||||
}
|
||||
}
|
||||
return names
|
||||
}
|
||||
|
||||
func jsonList(raw string) []any {
|
||||
|
||||
@@ -47,6 +47,50 @@ func TestPayloadUserIDsAreStrings(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestMeetingPayloadIncludesNamesAndDerivedEndedState(t *testing.T) {
|
||||
now := time.Now().UTC()
|
||||
userA, err := parseUserID("usrag7w9xJ6hto")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
userB, err := parseUserID("usr1RqTFgHSenM")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
payload := meetingPayload(store.Meeting{
|
||||
MeetingID: "mtg_1",
|
||||
Title: "周会",
|
||||
OrganizerID: userA,
|
||||
RecorderID: userA,
|
||||
Organizer: store.UserSummary{UserID: userA, DisplayName: "张三"},
|
||||
Recorder: store.UserSummary{UserID: userA, DisplayName: "张三"},
|
||||
StartAt: now.Add(-2 * time.Hour),
|
||||
EndAt: now.Add(-time.Hour),
|
||||
State: "scheduled",
|
||||
CreatedAt: now,
|
||||
UpdatedAt: now,
|
||||
Participants: []store.MeetingParticipant{
|
||||
{UserID: userB, Response: "pending", User: store.UserSummary{UserID: userB, DisplayName: "李四"}},
|
||||
},
|
||||
}, userA)
|
||||
|
||||
if payload["state"] != "ended" {
|
||||
t.Fatalf("state=%v, want ended", payload["state"])
|
||||
}
|
||||
if payload["organizer_display_name"] != "张三" {
|
||||
t.Fatalf("organizer_display_name=%v", payload["organizer_display_name"])
|
||||
}
|
||||
names, ok := payload["participant_names"].([]string)
|
||||
if !ok || len(names) != 1 || names[0] != "李四" {
|
||||
t.Fatalf("participant_names=%#v", payload["participant_names"])
|
||||
}
|
||||
participants, ok := payload["participants"].([]map[string]any)
|
||||
if !ok || len(participants) != 1 || participants[0]["display_name"] != "李四" {
|
||||
t.Fatalf("participants=%#v", payload["participants"])
|
||||
}
|
||||
}
|
||||
|
||||
func assertNoNumericUserIDs(t *testing.T, value any) {
|
||||
t.Helper()
|
||||
switch typed := value.(type) {
|
||||
|
||||
Reference in New Issue
Block a user