diff --git a/src/leaderboard/leaderboard_slashcmd.go b/src/leaderboard/leaderboard_slashcmd.go index 16767300..6d0b2da3 100644 --- a/src/leaderboard/leaderboard_slashcmd.go +++ b/src/leaderboard/leaderboard_slashcmd.go @@ -323,6 +323,17 @@ func handlePlayerOptIn(s *discordgo.Session, i *discordgo.InteractionCreate, opt AddPlayerOptInTypes(i.GuildID, userID, types) + guildID := i.GuildID + go func() { + log.Printf("leaderboard: pulling stats for newly opted-in user %s in guild %s", userID, guildID) + if err := CollectSinglePlayer(s, userID, SnapDateNow()); err != nil { + log.Printf("leaderboard: failed to collect stats for user %s on opt-in: %v", userID, err) + return + } + log.Printf("leaderboard: refreshing leaderboard messages for guild %s", guildID) + PostLeaderboards(s, SnapDateNow(), guildID, "", "update", nil) + }() + if len(types) == 1 && types[0] == OptInAll { respondEphemeral(s, i, "✅ You are now opted into **all** leaderboards.") return diff --git a/src/leaderboard/leaderboard_task.go b/src/leaderboard/leaderboard_task.go index be4d6ee9..1f67839e 100644 --- a/src/leaderboard/leaderboard_task.go +++ b/src/leaderboard/leaderboard_task.go @@ -354,3 +354,67 @@ func ScheduleWeeklyCollection(s *discordgo.Session) { RunLeaderboardCollection(s, false, "", "", "update", nil) }) } + +// CollectSinglePlayer fetches API data and saves leaderboard entries for a single Discord user. +func CollectSinglePlayer(s *discordgo.Session, userID string, snapDate string) error { + enc := farmerstate.GetMiscSettingString(userID, "encrypted_ei_id") + if enc == "" { + return fmt.Errorf("no encrypted Egg Inc ID found for user %s", userID) + } + dec := ei.DecryptEID(enc) + if dec == "" { + return fmt.Errorf("failed to decrypt Egg Inc ID for user %s", userID) + } + + optRows, err := farmerstate.GetLeaderboardOptInsForUser(userID) + if err != nil { + return fmt.Errorf("failed to get opt-ins for user %s: %w", userID, err) + } + if len(optRows) == 0 { + return fmt.Errorf("user %s has no leaderboard opt-ins", userID) + } + + var keys []string + for _, o := range optRows { + if o.LbType == OptInAll { + for _, def := range AllLeaderboards { + if def.Key == LBEggDaySEGain || def.Key == LBEggDaySEPct { + continue + } + keys = append(keys, def.Key) + } + } else { + for _, k := range ExpandConfigKey(o.LbType) { + if k == LBEggDaySEGain || k == LBEggDaySEPct { + continue + } + keys = append(keys, k) + } + } + } + + if len(keys) == 0 { + return fmt.Errorf("user %s has no active leaderboard keys", userID) + } + + // Unique keys + keysSet := make(map[string]struct{}) + for _, k := range keys { + keysSet[k] = struct{}{} + } + var uniqueKeys []string + for k := range keysSet { + uniqueKeys = append(uniqueKeys, k) + } + + g := &playerGroup{ + eiUserID: dec, + encryptedEIID: enc, + discordIDs: []string{userID}, + optedInTypes: uniqueKeys, + } + + collectPlayerGroup(s, g, snapDate) + return nil +} +