diff --git a/pkg/adapter/fortress/fortress.go b/pkg/adapter/fortress/fortress.go index 10e245b..0d1d193 100644 --- a/pkg/adapter/fortress/fortress.go +++ b/pkg/adapter/fortress/fortress.go @@ -1074,3 +1074,32 @@ func (f *Fortress) GetOgifStats(discordID string, after time.Time) (*model.OgifS return &ogifStats, nil } + +func (f *Fortress) GetOgifLeaderboard(after time.Time, limit int) ([]model.OgifLeaderboardRecord, error) { + req, err := f.makeReq("/api/v1/ogif/leaderboard", http.MethodGet, nil) + if err != nil { + return nil, err + } + + q := req.URL.Query() + q.Add("after", after.Format(time.RFC3339)) + q.Add("limit", strconv.Itoa(limit)) + req.URL.RawQuery = q.Encode() + + resp, err := http.DefaultClient.Do(req) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + if resp.StatusCode != http.StatusOK { + return nil, fmt.Errorf("invalid call, code %v", resp.StatusCode) + } + + var leaderboardResp model.OgifLeaderboardResponse + if err := json.NewDecoder(resp.Body).Decode(&leaderboardResp); err != nil { + return nil, fmt.Errorf("invalid decoded, error %v", err.Error()) + } + + return leaderboardResp.Data, nil +} diff --git a/pkg/adapter/fortress/interface.go b/pkg/adapter/fortress/interface.go index 2d94871..072d894 100644 --- a/pkg/adapter/fortress/interface.go +++ b/pkg/adapter/fortress/interface.go @@ -74,4 +74,5 @@ type FortressAdapter interface { FetchNews(platform, topic string) ([]model.News, error) GetOgifStats(discordID string, after time.Time) (*model.OgifStatsResponse, error) + GetOgifLeaderboard(after time.Time, limit int) ([]model.OgifLeaderboardRecord, error) } diff --git a/pkg/discord/command/ogif/base.go b/pkg/discord/command/ogif/base.go index 9ce5831..bbd630b 100644 --- a/pkg/discord/command/ogif/base.go +++ b/pkg/discord/command/ogif/base.go @@ -15,34 +15,42 @@ func (c command) Prefix() []string { // Execute is where we handle logic for each command func (c command) Execute(message *model.DiscordMessage) error { now := time.Now() - userID := message.Author.ID timePeriod := "30d" - isUserOmitted := false + isLeaderboard := false if len(message.ContentArgs) > 1 { if message.ContentArgs[1] == "help" { return c.Help(message) } - extractedID := stringutils.ExtractDiscordID(message.ContentArgs[1]) - if extractedID != "" { - userID = extractedID + if message.ContentArgs[1] == "top" { + timePeriod = "10y" + isLeaderboard = true + if len(message.ContentArgs) > 2 { + timePeriod = strings.Join(message.ContentArgs[2:], "") + } } else { - isUserOmitted = true - timePeriod = strings.Join(message.ContentArgs[1:], "") + userID := stringutils.ExtractDiscordID(message.ContentArgs[1]) + if userID != "" { + if len(message.ContentArgs) > 2 { + timePeriod = strings.Join(message.ContentArgs[2:], "") + } + } else { + timePeriod = strings.Join(message.ContentArgs[1:], "") + } } } - if len(message.ContentArgs) > 2 && !isUserOmitted { - timePeriod = strings.Join(message.ContentArgs[2:], "") - } - after, timeAmount, timeUnit, err := stringutils.ParseTimePeriod(now, timePeriod) if err != nil { return err } - return c.FetchOgifStats(message, userID, *after, timeAmount, timeUnit) + if isLeaderboard { + return c.GetOgifLeaderboard(message, *after, timeAmount, timeUnit) + } + + return c.FetchOgifStats(message, message.Author.ID, *after, timeAmount, timeUnit) } func (c command) Name() string { diff --git a/pkg/discord/command/ogif/ogif.go b/pkg/discord/command/ogif/ogif.go index 2969011..a0bea09 100644 --- a/pkg/discord/command/ogif/ogif.go +++ b/pkg/discord/command/ogif/ogif.go @@ -16,3 +16,14 @@ func (c command) FetchOgifStats(msg *model.DiscordMessage, discordID string, aft return c.view.Ogif().RenderOgifStats(msg, discordID, stats, timeAmount, timeUnit) } + +func (c command) GetOgifLeaderboard(msg *model.DiscordMessage, after time.Time, timeAmount int, timeUnit string) error { + logger := c.L.AddField("after", after) + leaderboard, err := c.svc.Event().GetOgifLeaderboard(after, 10) + if err != nil { + logger.Error(err, "error when get ogif leaderboard") + return err + } + + return c.view.Ogif().RenderOgifLeaderboard(msg, leaderboard, timeAmount, timeUnit) +} diff --git a/pkg/discord/service/event/discord.go b/pkg/discord/service/event/discord.go index cd3dc6a..916adbe 100644 --- a/pkg/discord/service/event/discord.go +++ b/pkg/discord/service/event/discord.go @@ -116,3 +116,11 @@ func (e *Event) GetOgifStats(discordID string, after time.Time) (model.OgifStats } return resp.Data, err } + +func (e *Event) GetOgifLeaderboard(after time.Time, limit int) ([]model.OgifLeaderboardRecord, error) { + leaderboard, err := e.adapter.Fortress().GetOgifLeaderboard(after, limit) + if err != nil { + return nil, err + } + return leaderboard, nil +} diff --git a/pkg/discord/service/event/earn.go b/pkg/discord/service/event/event.go similarity index 100% rename from pkg/discord/service/event/earn.go rename to pkg/discord/service/event/event.go diff --git a/pkg/discord/service/event/interface.go b/pkg/discord/service/event/interface.go index 184843b..a67aeeb 100644 --- a/pkg/discord/service/event/interface.go +++ b/pkg/discord/service/event/interface.go @@ -12,4 +12,5 @@ type EventServicer interface { CreateGuildScheduledEvent(*model.DiscordEvent) error SetSpeakers(message *model.DiscordMessage) error GetOgifStats(discordID string, after time.Time) (model.OgifStats, error) + GetOgifLeaderboard(after time.Time, limit int) ([]model.OgifLeaderboardRecord, error) } diff --git a/pkg/discord/view/ogif/help.go b/pkg/discord/view/ogif/help.go index cbd121f..367f8e0 100644 --- a/pkg/discord/view/ogif/help.go +++ b/pkg/discord/view/ogif/help.go @@ -9,20 +9,20 @@ import ( func (e *Ogif) Help(message *model.DiscordMessage) error { embed := &discordgo.MessageEmbed{ Title: "OGIF Command Help", - Description: "The OGIF command allows you to fetch and display OGIF stats for a user.", + Description: "The OGIF command allows you to fetch and display OGIF stats for a user or view the leaderboard.", Color: 0x00ff00, // Green color Fields: []*discordgo.MessageEmbedField{ { Name: "Usage", - Value: "`ogif [user_mention] [time_period]`", + Value: "`ogif [user_mention|top] [time_period]`", }, { Name: "Parameters", - Value: "- `user_mention`: Optional. Mention the user to fetch stats for. If omitted, uses the command author.\n- `time_period`: Optional. Time period for stats (e.g., '7d', '30d', '3m'). Default is 30 days.", + Value: "- `user_mention`: Optional. Mention the user to fetch stats for. If omitted, uses the command author.\n- `top`: Optional. Use this to view the leaderboard instead of user stats.\n- `time_period`: Optional. Time period for stats (e.g., '7d', '30d', '3m'). Default is 30 days.", }, { Name: "Examples", - Value: "- `ogif`\n- `ogif @user`\n- `ogif @user 7d`\n- `ogif 14d`", + Value: "- `ogif`\n- `ogif @user`\n- `ogif @user 7d`\n- `ogif 14d`\n- `ogif top`\n- `ogif top 7d`", }, }, Footer: &discordgo.MessageEmbedFooter{ diff --git a/pkg/discord/view/ogif/interface.go b/pkg/discord/view/ogif/interface.go index 89c2886..3d92a5a 100644 --- a/pkg/discord/view/ogif/interface.go +++ b/pkg/discord/view/ogif/interface.go @@ -6,5 +6,6 @@ import ( type OgifViewer interface { RenderOgifStats(original *model.DiscordMessage, userID string, stats model.OgifStats, timeAmount int, timeUnit string) error + RenderOgifLeaderboard(msg *model.DiscordMessage, leaderboard []model.OgifLeaderboardRecord, timeAmount int, timeUnit string) error Help(message *model.DiscordMessage) error } diff --git a/pkg/discord/view/ogif/leaderboard.go b/pkg/discord/view/ogif/leaderboard.go new file mode 100644 index 0000000..0dbbffd --- /dev/null +++ b/pkg/discord/view/ogif/leaderboard.go @@ -0,0 +1,41 @@ +package ogif + +import ( + "fmt" + + "github.com/bwmarrin/discordgo" + + "github.com/dwarvesf/fortress-discord/pkg/discord/view/base" + "github.com/dwarvesf/fortress-discord/pkg/model" +) + +func (o *Ogif) RenderOgifLeaderboard(msg *model.DiscordMessage, leaderboard []model.OgifLeaderboardRecord, timeAmount int, timeUnit string) error { + content := "" + + // Title + title := "<:pepegod:819802587062468668> OGIF Leaderboard <:pepegod:819802587062468668>" + + // Leaderboard content + if len(leaderboard) == 0 { + content += fmt.Sprintf("No OGIF in the last %d %s.\n", timeAmount, timeUnit) + } else { + for i, ogif := range leaderboard { + if i >= 20 { + break + } + content += fmt.Sprintf("%d. <@%s> - %d OGIFs\n", i+1, ogif.DiscordID, ogif.SpeakCount) + } + + if len(leaderboard) > 20 { + content += "...\n" + } + } + + embed := &discordgo.MessageEmbed{ + Title: title, + Description: content, + Color: 0x00ff00, // Green color + } + + return base.SendEmbededMessage(o.ses, msg, embed) +} diff --git a/pkg/model/ogif.go b/pkg/model/ogif.go index 901bed4..de8e87a 100644 --- a/pkg/model/ogif.go +++ b/pkg/model/ogif.go @@ -31,3 +31,14 @@ type FortEvent struct { Date time.Time `json:"date"` IsOver bool `json:"isOver"` } + +// OgifLeaderboardRecord represents an element in the OGIF leaderboard +type OgifLeaderboardRecord struct { + DiscordID string `json:"discordID"` + SpeakCount int64 `json:"speakCount"` +} + +// OgifLeaderboardResponse returns get ogif leader board +type OgifLeaderboardResponse struct { + Data []OgifLeaderboardRecord `json:"data"` +} // @name OgifLeaderboardResponse