Skip to content

Commit

Permalink
feat: added platform specific giveaways
Browse files Browse the repository at this point in the history
  • Loading branch information
Kesuaheli committed Dec 24, 2024
1 parent cf5119d commit 9d104ac
Show file tree
Hide file tree
Showing 6 changed files with 97 additions and 56 deletions.
38 changes: 22 additions & 16 deletions database/giveaway.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ type GiveawayEntry struct {
Weight int
// The day of last entry. Useful to check when only one ticket per day is allowed.
LastEntry time.Time
// The platform the giveaway is for
Platform Platform
// The platform identifier e.g. the channel id for the platform
PlatformID string
}

// ToEmbedField formats the giveaway entry to an discord message embed field.
Expand All @@ -59,22 +63,22 @@ func (e GiveawayEntry) ToEmbedField(s *discordgo.Session, totalTickets int) (f *
// prefixed with prefix.
//
// If an error occours or it doesn't match prefix, an emtpy GiveawayEntry is returned instead.
func GetGiveawayEntry(prefix, userID string) GiveawayEntry {
func GetGiveawayEntry(prefix, userID string, platform Platform, platformID string) GiveawayEntry {
var (
weight int
lastEntryID string
)
err := QueryRow("SELECT weight,last_entry_id FROM giveaway WHERE id=?", userID).Scan(&weight, &lastEntryID)
err := QueryRow("SELECT weight,last_entry_id FROM giveaway WHERE id=? AND platform=? AND platform_id=?", userID, platform, platformID).Scan(&weight, &lastEntryID)
if err == sql.ErrNoRows {
return GiveawayEntry{UserID: userID, Weight: 0}
return GiveawayEntry{UserID: userID, Weight: 0, Platform: platform, PlatformID: platformID}
}
if err != nil {
log.Printf("Database failed to get giveaway entries for '%s': %v", userID, err)
return GiveawayEntry{}
}

if lastEntryID == "" {
return GiveawayEntry{UserID: userID, Weight: weight}
return GiveawayEntry{UserID: userID, Weight: weight, Platform: platform, PlatformID: platformID}
}

dateValue, ok := strings.CutPrefix(lastEntryID, prefix+"-")
Expand All @@ -87,16 +91,16 @@ func GetGiveawayEntry(prefix, userID string) GiveawayEntry {
log.Printf("could not convert last_entry_id '%s' to time: %v", lastEntryID, err)
return GiveawayEntry{}
}
return GiveawayEntry{userID, weight, lastEntry}
return GiveawayEntry{userID, weight, lastEntry, platform, platformID}
}

// DeleteGiveawayEntry deletes the giveaway entry for the given user identifier from the database.
//
// If an error occours it will be returned. However if no datbase entry matched it returns err ==
// nil, not err == sql.ErrNoRows. Because sql.ErrNoRows also results in the non-existence of the
// requested row and therefore is treated as a successful call.
func DeleteGiveawayEntry(userID string) error {
_, err := Exec("DELETE FROM giveaway WHERE id=?", userID)
func DeleteGiveawayEntry(userID string, platform Platform, platformID string) error {
_, err := Exec("DELETE FROM giveaway WHERE id=? AND platform=? AND platform_id=?", userID, platform, platformID)
if err == sql.ErrNoRows {
return nil
}
Expand All @@ -110,13 +114,13 @@ func DeleteGiveawayEntry(userID string) error {
//
// If there was no error the modified entry is returned. If there was an error, an emtpy
// GiveawayEntry is returned instead.
func AddGiveawayWeight(prefix, userID string, amount int) GiveawayEntry {
func AddGiveawayWeight(prefix, userID string, amount int, platform Platform, platformID string) GiveawayEntry {
var (
weight int
lastEntryID string
new bool
)
err := QueryRow("SELECT weight,last_entry_id FROM giveaway WHERE id=?", userID).Scan(&weight, &lastEntryID)
err := QueryRow("SELECT weight,last_entry_id FROM giveaway WHERE id=? AND platform=? AND platform_id=?", userID, platform, platformID).Scan(&weight, &lastEntryID)
if err == sql.ErrNoRows {
new = true
} else if err != nil {
Expand All @@ -140,20 +144,22 @@ func AddGiveawayWeight(prefix, userID string, amount int) GiveawayEntry {
log.Printf("Database failed to insert giveaway for '%s': %v", userID, err)
return GiveawayEntry{}
}
return GiveawayEntry{userID, weight, lastEntry}
return GiveawayEntry{userID, weight, lastEntry, platform, platformID}
}
_, err = Exec("UPDATE giveaway SET weight=?,last_entry_id=? WHERE id=?", weight, lastEntryID, userID)
if err != nil {
log.Printf("Database failed to update weight (new: %d) for '%s': %v", weight, userID, err)
return GiveawayEntry{}
}
return GiveawayEntry{userID, weight, lastEntry}
return GiveawayEntry{userID, weight, lastEntry, platform, platformID}
}

// GetAllGiveawayEntries gets all giveaway entries that matches prefix.
func GetAllGiveawayEntries(prefix string) []GiveawayEntry {
rows, err := Query("SELECT id,weight,last_entry_id FROM giveaway")
if err != nil {
func GetAllGiveawayEntries(prefix string, platform Platform, platformID string) []GiveawayEntry {
rows, err := Query("SELECT id,weight,last_entry_id FROM giveaway WHERE platform=? AND platform_id=?", platform, platformID)
if err == sql.ErrNoRows {
return []GiveawayEntry{}
} else if err != nil {
log.Printf("ERROR: could not get entries from database: %v", err)
return []GiveawayEntry{}
}
Expand All @@ -173,7 +179,7 @@ func GetAllGiveawayEntries(prefix string) []GiveawayEntry {
}

if lastEntryID == "" {
entries = append(entries, GiveawayEntry{UserID: userID, Weight: weight})
entries = append(entries, GiveawayEntry{UserID: userID, Weight: weight, Platform: platform, PlatformID: platformID})
continue
}

Expand All @@ -187,7 +193,7 @@ func GetAllGiveawayEntries(prefix string) []GiveawayEntry {
log.Printf("ERROR: could not convert last_entry_id '%s' to time: %v", lastEntryID, err)
continue
}
entries = append(entries, GiveawayEntry{userID, weight, lastEntry})
entries = append(entries, GiveawayEntry{userID, weight, lastEntry, platform, platformID})
}
return entries
}
Expand Down
10 changes: 5 additions & 5 deletions event/twitch/messageHandler.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ func HandleCmdJoin(t *twitchgo.Session, channel string, user *twitchgo.IRCUser,
t.SendMessagef(channel, lang.GetDefault(tp+"msg.won"), user.Nickname)
return
}
entry := database.GetGiveawayEntry("tw11", user.Nickname)
entry := database.GetGiveawayEntry("tw11", user.Nickname, database.AnnouncementPlatformTwitch, channel) // FIXME: use channel ID instead of name
if entry.UserID == "" {
log.Printf("Error getting database giveaway entry: %v", err)
t.SendMessage(channel, lang.GetDefault("twitch.command.generic.error"))
Expand Down Expand Up @@ -123,7 +123,7 @@ func HandleCmdJoin(t *twitchgo.Session, channel string, user *twitchgo.IRCUser,
t.SendMessagef(channel, lang.GetDefault(tp+"msg.too_few_points"), user.Nickname, sePoints.Points, joinCost-sePoints.Points, joinCost)
return
}
entry = database.AddGiveawayWeight("tw11", user.Nickname, 1)
entry = database.AddGiveawayWeight("tw11", user.Nickname, 1, database.AnnouncementPlatformTwitch, channel) // FIXME: use channel ID instead of name
if entry.UserID == "" {
log.Printf("Error getting database giveaway entry: %v", err)
t.SendMessage(channel, lang.GetDefault("twitch.command.generic.error"))
Expand Down Expand Up @@ -181,7 +181,7 @@ func HandleCmdTickets(t *twitchgo.Session, channel string, source *twitchgo.IRCU
return
}

entry := database.GetGiveawayEntry("tw11", userID)
entry := database.GetGiveawayEntry("tw11", userID, database.AnnouncementPlatformTwitch, channel) // FIXME: use channel ID instead of name
if entry.Weight >= 10 {
if source.Nickname == userID {
t.SendMessagef(channel, lang.GetDefault(tp+"msg.max_tickets"), source.Nickname)
Expand Down Expand Up @@ -275,15 +275,15 @@ func HandleCmdDraw(t *twitchgo.Session, channel string, user *twitchgo.IRCUser,
return
}

winner, totalTickets := database.DrawGiveawayWinner(database.GetAllGiveawayEntries("tw11"))
winner, totalTickets := database.DrawGiveawayWinner(database.GetAllGiveawayEntries("tw11", database.AnnouncementPlatformTwitch, channel)) // FIXME: use channel ID instead of name
if totalTickets == 0 {
t.SendMessagef(channel, lang.GetDefault(tp+"msg.no_entries"), user.Nickname)
return
}

t.SendMessagef(channel, lang.GetDefault(tp+"msg.winner"), winner.UserID, prize.Name, winner.Weight, float64(winner.Weight*100)/float64(totalTickets))

err = database.DeleteGiveawayEntry(winner.UserID)
err = database.DeleteGiveawayEntry(winner.UserID, database.AnnouncementPlatformTwitch, channel) // FIXME: use channel ID instead of name
if err != nil {
log.Printf("Error deleting database giveaway entry: %v", err)
t.SendMessage(channel, lang.GetDefault("twitch.command.generic.error"))
Expand Down
4 changes: 2 additions & 2 deletions modules/adventcalendar/component.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ func (c *Component) handlePost(s *discordgo.Session, ids []string) {
return
}

entry := database.GetGiveawayEntry("xmas", c.user.ID)
entry := database.GetGiveawayEntry("xmas", c.user.ID, database.AnnouncementPlatformDiscord, c.Interaction.GuildID)
if entry.UserID != c.user.ID {
log.Printf("ERROR: getEntry() returned with userID '%s' but want '%s'", entry.UserID, c.user.ID)
c.ReplyError()
Expand All @@ -93,7 +93,7 @@ func (c *Component) handlePost(s *discordgo.Session, ids []string) {
return
}

entry = database.AddGiveawayWeight("xmas", c.user.ID, 1)
entry = database.AddGiveawayWeight("xmas", c.user.ID, 1, database.AnnouncementPlatformDiscord, c.Interaction.GuildID)

c.ReplyHiddenSimpleEmbedf(0x00FF00, lang.GetDefault("module.adventcalendar.enter.success"), entry.Weight)
}
2 changes: 1 addition & 1 deletion modules/adventcalendar/handlerSubcommandDraw.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import (
)

func (cmd Chat) handleSubcommandDraw() {
winner, totalTickets := database.DrawGiveawayWinner(database.GetAllGiveawayEntries("xmas"))
winner, totalTickets := database.DrawGiveawayWinner(database.GetAllGiveawayEntries("xmas", database.AnnouncementPlatformDiscord, cmd.Interaction.GuildID))
if totalTickets == 0 {
cmd.ReplyHidden(lang.GetDefault(tp + "msg.no_entries.draw"))
return
Expand Down
79 changes: 50 additions & 29 deletions modules/adventcalendar/midnight.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,47 +32,68 @@ func Midnight(s *discordgo.Session) {
}
log.Printf("Summary for %s", t.Add(-1*time.Hour).Format("_2. Jan"))

entries := database.GetAllGiveawayEntries("xmas")
slices.SortFunc(entries, func(a, b database.GiveawayEntry) int {
if a.Weight < b.Weight {
return -1
} else if a.Weight > b.Weight {
return 1
adventChannels, err := util.GetChannelsFromDatabase(s, "adventcalendar_channel")
if err != nil {
log.Printf("ERROR: Could not get advent calendar channel: %+v", err)
return
} else if len(adventChannels) == 0 {
log.Printf("No advent calendar channels found")
return
}

guildIDs := make([]string, 0, len(adventChannels))
for k := range adventChannels {
guildIDs = append(guildIDs, k)
}
logChannels, err := util.GetChannelsFromDatabase(s, "log_channel", guildIDs...)
if err != nil {
log.Printf("ERROR: Could not get log channel: %+v", err)
return
}

for guild := range adventChannels {
var logChannel string
var ok bool
if logChannel, ok = logChannels[guild]; !ok {
log.Printf("Warning: No log channel found for guild '%s'. Skipping", guild)
continue
}
if a.LastEntry.Before(b.LastEntry) {
return -1
} else if a.LastEntry.After(b.LastEntry) {
return 1

entries := database.GetAllGiveawayEntries("xmas", database.AnnouncementPlatformDiscord, guild)
if len(entries) == 0 {
log.Printf("No entries for guild '%s'", guild)
continue
}
slices.SortFunc(entries, func(a, b database.GiveawayEntry) int {
if a.Weight < b.Weight {
return -1
} else if a.Weight > b.Weight {
return 1
}
if a.LastEntry.Before(b.LastEntry) {
return -1
} else if a.LastEntry.After(b.LastEntry) {
return 1
}
return 0
})
slices.Reverse(entries)
data := &discordgo.MessageSend{
Embeds: splitEntriesToEmbeds(s, entries),
}
return 0
})
slices.Reverse(entries)
data := &discordgo.MessageSend{
Embeds: splitEntriesToEmbeds(s, entries),
}
if len(data.Embeds) == 0 {
data.Content = "Ticket Summary: *No Tickets!*"
} else {
data.Embeds[0].Title = "Current Tickets"

if len(entries) > 1 {
var totalTickets int
for _, e := range entries {
totalTickets += e.Weight
}
data.Embeds[0].Description = fmt.Sprintf("__Total: %d Tickets (%d users)__\nProbability per Ticket: %.2f%%\n%s", totalTickets, len(entries), 100.0/float64(totalTickets), data.Embeds[0].Description)
}
}

channels, err := util.GetChannelsFromDatabase(s, "log_channel")
if err != nil {
log.Printf("ERROR: Could not get advent calendar channel: %+v", err)
return
}

for _, channelID := range channels {
_, err = s.ChannelMessageSendComplex(channelID, data)
_, err = s.ChannelMessageSendComplex(logChannel, data)
if err != nil {
log.Printf("ERROR: could not send log message to channel '%s': %+v", channelID, err)
log.Printf("ERROR: could not send log message to channel '%s': %+v", logChannel, err)
continue
}
}
Expand Down
20 changes: 17 additions & 3 deletions util/discord.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@
package util

import (
"database/sql"
"fmt"
"strings"

"cake4everybot/data/lang"
"cake4everybot/database"
Expand Down Expand Up @@ -115,8 +117,20 @@ func MentionCommand(base string, subcommand ...string) string {
}

// GetChannelsFromDatabase returns a map from guild IDs to channel IDs
func GetChannelsFromDatabase(s *discordgo.Session, channelName string) (map[string]string, error) {
rows, err := database.Query("SELECT id," + channelName + " FROM guilds")
func GetChannelsFromDatabase(s *discordgo.Session, channelName string, guildIDs ...string) (map[string]string, error) {
var rows *sql.Rows
var err error
if len(guildIDs) == 0 {
rows, err = database.Query("SELECT id," + channelName + " FROM guilds")
} else {
placeholders := strings.Repeat("?,", len(guildIDs))
query := fmt.Sprintf("SELECT id,%s FROM guilds WHERE id IN (%s)", channelName, placeholders[:len(placeholders)-1])
args := make([]interface{}, len(guildIDs))
for i, guildID := range guildIDs {
args[i] = guildID
}
rows, err = database.Query(query, args...)
}
if err != nil {
return nil, err
}
Expand All @@ -138,7 +152,7 @@ func GetChannelsFromDatabase(s *discordgo.Session, channelName string) (map[stri
// validate channel
channel, err := s.Channel(channelID)
if err != nil {
log.Printf("Warning: could not get %s channel for id '%s: %+v\n", channelName, channelID, err)
log.Printf("Warning: could not get %s channel for id '%s/%s: %+v\n", channelName, guildID, channelID, err)
continue
}
if channel.GuildID != guildID {
Expand Down

0 comments on commit 9d104ac

Please sign in to comment.