diff --git a/internal/service/voiceroomrocket/ranking.go b/internal/service/voiceroomrocket/ranking.go index 48d809e..9d26566 100644 --- a/internal/service/voiceroomrocket/ranking.go +++ b/internal/service/voiceroomrocket/ranking.go @@ -117,18 +117,115 @@ func contributionUserIDs(rows []model.VoiceRoomRocketContribution) []int64 { func (s *Service) mapUserProfiles(ctx context.Context, userIDs []int64) map[int64]integration.UserProfile { result := make(map[int64]integration.UserProfile, len(userIDs)) + if len(userIDs) == 0 { + return result + } + if s.repo.DB != nil { + var rows []model.UserBaseInfo + if err := s.repo.DB.WithContext(ctx).Where("id IN ?", userIDs).Find(&rows).Error; err == nil { + for _, row := range rows { + if row.ID <= 0 { + continue + } + result[row.ID] = userBaseInfoToProfile(row) + } + } + } if s.userProfiles == nil { return result } for _, userID := range userIDs { - profile, err := s.userProfiles.GetUserProfile(ctx, userID) - if err == nil { - result[userID] = profile + current := result[userID] + if userProfileComplete(current) { + continue } + profile, err := s.userProfiles.GetUserProfile(ctx, userID) + if err != nil { + if int64(current.ID) == 0 { + current.ID = integration.Int64Value(userID) + result[userID] = current + } + continue + } + result[userID] = mergeUserProfile(current, profile, userID) } return result } +func userBaseInfoToProfile(row model.UserBaseInfo) integration.UserProfile { + return integration.UserProfile{ + ID: integration.Int64Value(row.ID), + Account: strings.TrimSpace(row.Account), + UserAvatar: strings.TrimSpace(row.UserAvatar), + UserNickname: strings.TrimSpace(row.UserNickname), + OriginSys: strings.TrimSpace(row.OriginSys), + CountryCode: strings.TrimSpace(row.CountryCode), + CountryName: strings.TrimSpace(row.CountryName), + } +} + +func userProfileComplete(profile integration.UserProfile) bool { + return int64(profile.ID) > 0 && + strings.TrimSpace(profile.Account) != "" && + strings.TrimSpace(profile.UserAvatar) != "" && + strings.TrimSpace(profile.UserNickname) != "" && + strings.TrimSpace(profile.CountryCode) != "" +} + +func mergeUserProfile(base integration.UserProfile, fallback integration.UserProfile, userID int64) integration.UserProfile { + if int64(base.ID) == 0 { + if int64(fallback.ID) > 0 { + base.ID = fallback.ID + } else { + base.ID = integration.Int64Value(userID) + } + } + if strings.TrimSpace(base.Account) == "" { + base.Account = strings.TrimSpace(fallback.Account) + } else { + base.Account = strings.TrimSpace(base.Account) + } + if strings.TrimSpace(base.UserAvatar) == "" { + base.UserAvatar = strings.TrimSpace(fallback.UserAvatar) + } else { + base.UserAvatar = strings.TrimSpace(base.UserAvatar) + } + if strings.TrimSpace(base.UserNickname) == "" { + base.UserNickname = strings.TrimSpace(fallback.UserNickname) + } else { + base.UserNickname = strings.TrimSpace(base.UserNickname) + } + if int64(base.CountryID) == 0 { + base.CountryID = fallback.CountryID + } + if strings.TrimSpace(base.CountryCode) == "" { + base.CountryCode = strings.TrimSpace(fallback.CountryCode) + } else { + base.CountryCode = strings.TrimSpace(base.CountryCode) + } + if strings.TrimSpace(base.CountryName) == "" { + base.CountryName = strings.TrimSpace(fallback.CountryName) + } else { + base.CountryName = strings.TrimSpace(base.CountryName) + } + if strings.TrimSpace(base.RegionCode) == "" { + base.RegionCode = strings.TrimSpace(fallback.RegionCode) + } else { + base.RegionCode = strings.TrimSpace(base.RegionCode) + } + if strings.TrimSpace(base.OriginSys) == "" { + base.OriginSys = strings.TrimSpace(fallback.OriginSys) + } else { + base.OriginSys = strings.TrimSpace(base.OriginSys) + } + if strings.TrimSpace(base.AccountStatus) == "" { + base.AccountStatus = strings.TrimSpace(fallback.AccountStatus) + } else { + base.AccountStatus = strings.TrimSpace(base.AccountStatus) + } + return base +} + func rankRedisKey(sysOrigin string, roomID int64, day string, roundNo int, level int) string { return "voice_room:rocket:rank:" + strings.ToUpper(strings.TrimSpace(sysOrigin)) + ":" + strconv.FormatInt(roomID, 10) + diff --git a/internal/service/voiceroomrocket/ranking_test.go b/internal/service/voiceroomrocket/ranking_test.go new file mode 100644 index 0000000..98c8a77 --- /dev/null +++ b/internal/service/voiceroomrocket/ranking_test.go @@ -0,0 +1,104 @@ +package voiceroomrocket + +import ( + "context" + "testing" + "time" + + "chatapp3-golang/internal/integration" + "chatapp3-golang/internal/model" +) + +func TestRankRecordsIncludesLocalUserAvatar(t *testing.T) { + service, db := newTestService(t) + ctx := context.Background() + if err := db.AutoMigrate(&model.UserBaseInfo{}); err != nil { + t.Fatalf("migrate user_base_info: %v", err) + } + service.userProfiles = &fakeRocketGateway{profiles: map[int64]integration.UserProfile{ + 1001: { + ID: integration.Int64Value(1001), + Account: "java-account", + UserNickname: "java-name", + CountryCode: "SA", + }, + }} + + if err := db.Create(&model.UserBaseInfo{ + ID: 1001, + Account: "223456", + UserAvatar: "https://cdn.example.com/avatar-1001.png", + UserNickname: "Rocket King", + CountryCode: "KSA", + CountryName: "Saudi Arabia", + CreateTime: time.Now(), + }).Error; err != nil { + t.Fatalf("create user_base_info: %v", err) + } + if err := db.Create(&model.VoiceRoomRocketContribution{ + SysOrigin: "LIKEI", + RoomID: 9001, + DayKey: "20260516", + RoundNo: 1, + Level: 2, + UserID: 1001, + ScoreEnergy: 500, + FirstContributeTime: time.Now(), + LastContributeTime: time.Now(), + CreateTime: time.Now(), + UpdateTime: time.Now(), + }).Error; err != nil { + t.Fatalf("create contribution: %v", err) + } + + records, err := service.rankRecords(ctx, "LIKEI", 9001, "20260516", 1, 2, 1, 10) + if err != nil { + t.Fatalf("rankRecords error = %v", err) + } + if len(records) != 1 { + t.Fatalf("records len = %d, want 1", len(records)) + } + if records[0].UserAvatar != "https://cdn.example.com/avatar-1001.png" { + t.Fatalf("userAvatar = %q, want local avatar", records[0].UserAvatar) + } + if records[0].UserNickname != "Rocket King" { + t.Fatalf("userNickname = %q, want local nickname", records[0].UserNickname) + } +} + +func TestMapUserProfilesFillsMissingLocalAvatarFromJava(t *testing.T) { + service, db := newTestService(t) + ctx := context.Background() + if err := db.AutoMigrate(&model.UserBaseInfo{}); err != nil { + t.Fatalf("migrate user_base_info: %v", err) + } + service.userProfiles = &fakeRocketGateway{profiles: map[int64]integration.UserProfile{ + 1002: { + ID: integration.Int64Value(1002), + Account: "java-1002", + UserAvatar: "https://cdn.example.com/java-avatar-1002.png", + UserNickname: "Java Name", + CountryCode: "SA", + }, + }} + if err := db.Create(&model.UserBaseInfo{ + ID: 1002, + Account: "local-1002", + UserNickname: "Local Name", + CreateTime: time.Now(), + }).Error; err != nil { + t.Fatalf("create user_base_info: %v", err) + } + + profiles := service.mapUserProfiles(ctx, []int64{1002}) + profile := profiles[1002] + if profile.UserAvatar != "https://cdn.example.com/java-avatar-1002.png" { + t.Fatalf("userAvatar = %q, want java avatar", profile.UserAvatar) + } + if profile.Account != "local-1002" { + t.Fatalf("account = %q, want local account", profile.Account) + } + if profile.UserNickname != "Local Name" { + t.Fatalf("userNickname = %q, want local nickname", profile.UserNickname) + } +}