test: cover string user ids in workbench payloads
This commit is contained in:
@@ -0,0 +1,81 @@
|
|||||||
|
package httpapi
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"git.118im.com/im_team/im_workbench/internal/store"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestPayloadUserIDsAreStrings(t *testing.T) {
|
||||||
|
now := time.Date(2026, 9, 16, 9, 30, 0, 0, time.UTC)
|
||||||
|
userA, err := parseUserID("usrag7w9xJ6hto")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
userB, err := parseUserID("usr1RqTFgHSenM")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
payloads := []map[string]any{
|
||||||
|
organizationMemberPayload(store.OrganizationMember{UserID: userA}),
|
||||||
|
attendanceRecordPayload(&store.AttendanceRecord{RecordID: "att_1", UserID: userA, Date: now, CreatedAt: now, UpdatedAt: now}),
|
||||||
|
attendanceAppealPayload(&store.AttendanceAppeal{AppealID: "atta_1", UserID: userA, SubmittedAt: now, CreatedAt: now, UpdatedAt: now}),
|
||||||
|
meetingPayload(store.Meeting{
|
||||||
|
MeetingID: "mtg_1",
|
||||||
|
OrganizerID: userA,
|
||||||
|
RecorderID: userB,
|
||||||
|
StartAt: now,
|
||||||
|
EndAt: now.Add(time.Hour),
|
||||||
|
CreatedAt: now,
|
||||||
|
UpdatedAt: now,
|
||||||
|
Participants: []store.MeetingParticipant{
|
||||||
|
{UserID: userA, Response: "accepted"},
|
||||||
|
{UserID: userB, Response: "pending"},
|
||||||
|
},
|
||||||
|
}, userA),
|
||||||
|
meetingNoteFilePayload(store.MeetingNoteFile{NoteFileID: "mnote_1", UploaderID: userA, CreatedAt: now, UpdatedAt: now}, userA),
|
||||||
|
dailyReportPayload(store.DailyReport{ReportID: "dr_1", AuthorID: userA, ReportDate: now, CreatedAt: now, UpdatedAt: now}),
|
||||||
|
monthlyReportPayload(store.MonthlyReport{ReportID: "mr_1", AuthorID: userA, CreatedAt: now, UpdatedAt: now}),
|
||||||
|
mailboxSubmissionPayload(store.MailboxSubmission{SubmissionID: "mb_1", SenderID: userA, SubmittedAt: now}),
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, payload := range payloads {
|
||||||
|
assertNoNumericUserIDs(t, payload)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func assertNoNumericUserIDs(t *testing.T, value any) {
|
||||||
|
t.Helper()
|
||||||
|
switch typed := value.(type) {
|
||||||
|
case map[string]any:
|
||||||
|
for key, item := range typed {
|
||||||
|
if isUserIDKey(key) {
|
||||||
|
if _, ok := item.(string); !ok {
|
||||||
|
t.Fatalf("%s is %T, want string", key, item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assertNoNumericUserIDs(t, item)
|
||||||
|
}
|
||||||
|
case []map[string]any:
|
||||||
|
for _, item := range typed {
|
||||||
|
assertNoNumericUserIDs(t, item)
|
||||||
|
}
|
||||||
|
case []any:
|
||||||
|
for _, item := range typed {
|
||||||
|
assertNoNumericUserIDs(t, item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func isUserIDKey(key string) bool {
|
||||||
|
return key == "user_id" ||
|
||||||
|
key == "organizer_id" ||
|
||||||
|
key == "recorder_user_id" ||
|
||||||
|
key == "uploader_user_id" ||
|
||||||
|
key == "author_id" ||
|
||||||
|
key == "sender_id" ||
|
||||||
|
strings.HasSuffix(key, "_user_id")
|
||||||
|
}
|
||||||
@@ -27,8 +27,6 @@ type optionalUserID struct {
|
|||||||
|
|
||||||
func (id *optionalUserID) UnmarshalJSON(raw []byte) error {
|
func (id *optionalUserID) UnmarshalJSON(raw []byte) error {
|
||||||
if strings.TrimSpace(string(raw)) == "null" {
|
if strings.TrimSpace(string(raw)) == "null" {
|
||||||
id.set = true
|
|
||||||
id.value = 0
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
value, err := parseUserIDJSON(raw)
|
value, err := parseUserIDJSON(raw)
|
||||||
@@ -52,11 +50,7 @@ func parseUserIDJSON(raw []byte) (int64, error) {
|
|||||||
if err := json.Unmarshal(raw, &text); err == nil {
|
if err := json.Unmarshal(raw, &text); err == nil {
|
||||||
return parseUserID(text)
|
return parseUserID(text)
|
||||||
}
|
}
|
||||||
var number int64
|
return 0, fmt.Errorf("user id must be a string")
|
||||||
if err := json.Unmarshal(raw, &number); err == nil {
|
|
||||||
return number, nil
|
|
||||||
}
|
|
||||||
return 0, fmt.Errorf("invalid user id")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseUserID(value string) (int64, error) {
|
func parseUserID(value string) (int64, error) {
|
||||||
|
|||||||
@@ -22,12 +22,9 @@ func TestUserIDJSONAcceptsIMUserID(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestUserIDJSONStillAcceptsNumericID(t *testing.T) {
|
func TestUserIDJSONRejectsNumericID(t *testing.T) {
|
||||||
var id userID
|
var id userID
|
||||||
if err := json.Unmarshal([]byte(`1573862062872858624`), &id); err != nil {
|
if err := json.Unmarshal([]byte(`1573862062872858624`), &id); err == nil {
|
||||||
t.Fatalf("unmarshal numeric: %v", err)
|
t.Fatal("expected numeric user id to be rejected")
|
||||||
}
|
|
||||||
if id != 1573862062872858624 {
|
|
||||||
t.Fatalf("id=%d", id)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user