Phase 28 (Step 3a): /sent returns full message detail per recipient
Phase 28's in-game mail UI threads sent messages by the recipient race name, so the bulk `/sent` endpoint now returns the same `UserMailMessageDetail` shape as `/inbox` — single sends contribute one row per message, broadcasts contribute one row per addressee and the UI collapses them by `message_id` into a stand-alone item. - `Store.ListSent` / `Service.ListSent` switched from `[]Message` to `[]InboxEntry`. SQL grows an INNER JOIN with `diplomail_recipients`. - Handler emits `userMailMessageDetailWire` items; the deprecated `userMailSentSummaryWire` is removed. - `openapi.yaml`: `UserMailSentList.items` now reference `UserMailMessageDetail`; the standalone `UserMailSentSummary` schema is dropped. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -194,9 +194,9 @@ func (h *UserMailHandlers) Sent() gin.HandlerFunc {
|
||||
respondDiplomailError(c, h.logger, "user mail sent", ctx, err)
|
||||
return
|
||||
}
|
||||
out := userMailSentListWire{Items: make([]userMailSentSummaryWire, 0, len(items))}
|
||||
for _, m := range items {
|
||||
out.Items = append(out.Items, mailMessageSummaryToWire(m))
|
||||
out := userMailSentListWire{Items: make([]userMailMessageDetailWire, 0, len(items))}
|
||||
for _, entry := range items {
|
||||
out.Items = append(out.Items, mailMessageDetailToWire(entry, false))
|
||||
}
|
||||
c.JSON(http.StatusOK, out)
|
||||
}
|
||||
@@ -555,27 +555,18 @@ type userMailMessageDetailWire struct {
|
||||
Translator *string `json:"translator,omitempty"`
|
||||
}
|
||||
|
||||
// userMailSentSummaryWire mirrors the response shape for the
|
||||
// sender-side listing. Recipient state is intentionally omitted (one
|
||||
// author may have N recipients per broadcast in later stages).
|
||||
type userMailSentSummaryWire struct {
|
||||
MessageID string `json:"message_id"`
|
||||
GameID string `json:"game_id"`
|
||||
GameName string `json:"game_name,omitempty"`
|
||||
Kind string `json:"kind"`
|
||||
Subject string `json:"subject,omitempty"`
|
||||
Body string `json:"body"`
|
||||
BodyLang string `json:"body_lang"`
|
||||
BroadcastScope string `json:"broadcast_scope"`
|
||||
CreatedAt string `json:"created_at"`
|
||||
}
|
||||
|
||||
type userMailInboxListWire struct {
|
||||
Items []userMailMessageDetailWire `json:"items"`
|
||||
}
|
||||
|
||||
// userMailSentListWire mirrors the response shape for the
|
||||
// sender-side listing. Phase 28's in-game UI threads sent messages
|
||||
// by the recipient's race name, so the wire carries the full
|
||||
// message detail (including the recipient snapshot) — single sends
|
||||
// contribute one row per message, broadcasts contribute one row per
|
||||
// addressee and the UI collapses them by `message_id`.
|
||||
type userMailSentListWire struct {
|
||||
Items []userMailSentSummaryWire `json:"items"`
|
||||
Items []userMailMessageDetailWire `json:"items"`
|
||||
}
|
||||
|
||||
type userMailUnreadCountWire struct {
|
||||
@@ -643,20 +634,6 @@ func mailMessageDetailToWire(entry diplomail.InboxEntry, justCreated bool) userM
|
||||
return out
|
||||
}
|
||||
|
||||
func mailMessageSummaryToWire(m diplomail.Message) userMailSentSummaryWire {
|
||||
return userMailSentSummaryWire{
|
||||
MessageID: m.MessageID.String(),
|
||||
GameID: m.GameID.String(),
|
||||
GameName: m.GameName,
|
||||
Kind: m.Kind,
|
||||
Subject: m.Subject,
|
||||
Body: m.Body,
|
||||
BodyLang: m.BodyLang,
|
||||
BroadcastScope: m.BroadcastScope,
|
||||
CreatedAt: m.CreatedAt.UTC().Format(timestampLayout),
|
||||
}
|
||||
}
|
||||
|
||||
// mailRecipientStateToWire renders the recipient row after a
|
||||
// mark-read or soft-delete call. The caller only needs the per-user
|
||||
// state, not the full message body again.
|
||||
|
||||
Reference in New Issue
Block a user