fix: preserve meeting note file metadata
This commit is contained in:
+31
-5
@@ -557,12 +557,25 @@ func (a *API) meetingNoteFiles(w http.ResponseWriter, r *http.Request, p *auth.P
|
||||
return
|
||||
}
|
||||
var body struct {
|
||||
FileID string `json:"file_id"`
|
||||
FileID string `json:"file_id"`
|
||||
FileName string `json:"file_name"`
|
||||
Name string `json:"name"`
|
||||
MIMEType string `json:"mime_type"`
|
||||
MIME string `json:"mime"`
|
||||
FileSize *int64 `json:"file_size"`
|
||||
Size *int64 `json:"size"`
|
||||
}
|
||||
if !decodeBody(w, r, &body) {
|
||||
return
|
||||
}
|
||||
file, err := st.CreateMeetingNoteFile(r.Context(), p.UserID, meetingID, "mnote_"+randomToken(12), strings.TrimSpace(body.FileID), idempotencyKey)
|
||||
fileID := strings.TrimSpace(body.FileID)
|
||||
if fileID == "" {
|
||||
writeError(w, r, http.StatusBadRequest, 30000, reasonMalformedRequest, "malformed request", map[string]any{"field": "file_id"})
|
||||
return
|
||||
}
|
||||
file, err := st.CreateMeetingNoteFile(r.Context(), p.UserID, meetingID, "mnote_"+randomToken(12), store.MeetingNoteFileInput{
|
||||
FileID: fileID, FileName: firstNonEmpty(body.FileName, body.Name), MIMEType: firstNonEmpty(body.MIMEType, body.MIME), FileSize: firstNonNilInt64(body.FileSize, body.Size),
|
||||
}, idempotencyKey)
|
||||
if err != nil {
|
||||
writeStoreError(w, r, err)
|
||||
return
|
||||
@@ -583,13 +596,26 @@ func (a *API) meetingNoteFileResource(w http.ResponseWriter, r *http.Request, p
|
||||
switch r.Method {
|
||||
case http.MethodPut:
|
||||
var body struct {
|
||||
FileID string `json:"file_id"`
|
||||
Version int `json:"version"`
|
||||
FileID string `json:"file_id"`
|
||||
FileName string `json:"file_name"`
|
||||
Name string `json:"name"`
|
||||
MIMEType string `json:"mime_type"`
|
||||
MIME string `json:"mime"`
|
||||
FileSize *int64 `json:"file_size"`
|
||||
Size *int64 `json:"size"`
|
||||
Version int `json:"version"`
|
||||
}
|
||||
if !decodeBody(w, r, &body) {
|
||||
return
|
||||
}
|
||||
file, err := st.ReplaceMeetingNoteFile(r.Context(), p.UserID, meetingID, noteFileID, strings.TrimSpace(body.FileID), idempotencyKey, body.Version)
|
||||
fileID := strings.TrimSpace(body.FileID)
|
||||
if fileID == "" {
|
||||
writeError(w, r, http.StatusBadRequest, 30000, reasonMalformedRequest, "malformed request", map[string]any{"field": "file_id"})
|
||||
return
|
||||
}
|
||||
file, err := st.ReplaceMeetingNoteFile(r.Context(), p.UserID, meetingID, noteFileID, store.MeetingNoteFileInput{
|
||||
FileID: fileID, FileName: firstNonEmpty(body.FileName, body.Name), MIMEType: firstNonEmpty(body.MIMEType, body.MIME), FileSize: firstNonNilInt64(body.FileSize, body.Size),
|
||||
}, idempotencyKey, body.Version)
|
||||
if err != nil {
|
||||
writeStoreError(w, r, err)
|
||||
return
|
||||
|
||||
@@ -2,6 +2,8 @@ package httpapi
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"mime"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -315,13 +317,18 @@ func meetingNotesDetailPayload(meeting store.Meeting, files []store.MeetingNoteF
|
||||
}
|
||||
|
||||
func meetingNoteFilePayload(file store.MeetingNoteFile, viewer int64) map[string]any {
|
||||
extension := meetingNoteFileExtension(file.FileName, file.MIMEType)
|
||||
return map[string]any{
|
||||
"note_file_id": file.NoteFileID,
|
||||
"meeting_id": file.MeetingID,
|
||||
"file_id": file.FileID,
|
||||
"name": file.FileName,
|
||||
"file_name": file.FileName,
|
||||
"mime": file.MIMEType,
|
||||
"mime_type": file.MIMEType,
|
||||
"size": file.FileSize,
|
||||
"file_size": file.FileSize,
|
||||
"file_extension": extension,
|
||||
"file_etag": file.FileETag,
|
||||
"status": file.Status,
|
||||
"preview_status": file.PreviewStatus,
|
||||
@@ -341,6 +348,17 @@ func meetingNoteFilePayload(file store.MeetingNoteFile, viewer int64) map[string
|
||||
}
|
||||
}
|
||||
|
||||
func meetingNoteFileExtension(fileName, mimeType string) string {
|
||||
if ext := strings.ToLower(strings.TrimPrefix(filepath.Ext(strings.TrimSpace(fileName)), ".")); ext != "" {
|
||||
return ext
|
||||
}
|
||||
exts, _ := mime.ExtensionsByType(strings.TrimSpace(mimeType))
|
||||
if len(exts) == 0 {
|
||||
return ""
|
||||
}
|
||||
return strings.ToLower(strings.TrimPrefix(exts[0], "."))
|
||||
}
|
||||
|
||||
func dailyReportPayloads(reports []store.DailyReport) []map[string]any {
|
||||
items := make([]map[string]any, 0, len(reports))
|
||||
for _, report := range reports {
|
||||
|
||||
@@ -91,6 +91,30 @@ func TestMeetingPayloadIncludesNamesAndDerivedEndedState(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestMeetingNoteFilePayloadKeepsOriginalNameAndExtension(t *testing.T) {
|
||||
now := time.Date(2026, 9, 17, 12, 0, 0, 0, time.UTC)
|
||||
payload := meetingNoteFilePayload(store.MeetingNoteFile{
|
||||
NoteFileID: "mnote_1",
|
||||
FileID: "file_1",
|
||||
FileName: "会议纪要.pdf",
|
||||
MIMEType: "application/pdf",
|
||||
FileSize: 2048,
|
||||
UploaderID: 1,
|
||||
Status: "active",
|
||||
CreatedAt: now,
|
||||
UpdatedAt: now,
|
||||
}, 1)
|
||||
if payload["file_name"] != "会议纪要.pdf" || payload["name"] != "会议纪要.pdf" {
|
||||
t.Fatalf("payload names = file_name:%v name:%v", payload["file_name"], payload["name"])
|
||||
}
|
||||
if payload["file_extension"] != "pdf" {
|
||||
t.Fatalf("file_extension = %v, want pdf", payload["file_extension"])
|
||||
}
|
||||
if payload["mime"] != "application/pdf" || payload["size"] != int64(2048) {
|
||||
t.Fatalf("payload aliases = mime:%v size:%v", payload["mime"], payload["size"])
|
||||
}
|
||||
}
|
||||
|
||||
func assertNoNumericUserIDs(t *testing.T, value any) {
|
||||
t.Helper()
|
||||
switch typed := value.(type) {
|
||||
|
||||
@@ -87,3 +87,12 @@ func firstNonEmpty(values ...string) string {
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func firstNonNilInt64(values ...*int64) *int64 {
|
||||
for _, value := range values {
|
||||
if value != nil {
|
||||
return value
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user