2024-11-05 00:19:36 -06:00
|
|
|
package lib
|
|
|
|
|
|
|
|
import (
|
|
|
|
"database/sql"
|
|
|
|
"fmt"
|
2024-11-05 00:28:33 -06:00
|
|
|
"log"
|
2024-11-05 00:19:36 -06:00
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/bwmarrin/discordgo"
|
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
HimbucksPerReward = 10
|
|
|
|
MessageCountThreshold = 5
|
|
|
|
CooldownPeriod = time.Minute
|
|
|
|
)
|
|
|
|
|
|
|
|
type HimbucksEntry struct {
|
|
|
|
Username string
|
|
|
|
Balance int
|
|
|
|
MessageCount int
|
|
|
|
}
|
|
|
|
|
|
|
|
func GetOrCreateHimbucksEntry(userID int, guildID string) error {
|
|
|
|
_, err := DBClient.Exec(`
|
|
|
|
INSERT INTO himbucks (user_id, guild_id, balance, message_count)
|
|
|
|
VALUES (?, ?, 0, 0)
|
|
|
|
ON CONFLICT (user_id, guild_id) DO NOTHING`,
|
|
|
|
userID, guildID)
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
func ProcessMessage(s *discordgo.Session, m *discordgo.MessageCreate) error {
|
|
|
|
// Ignore bot messages
|
|
|
|
if m.Author.Bot {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get user from database
|
|
|
|
var userID int
|
|
|
|
err := DBClient.QueryRow("SELECT id FROM users WHERE discord_id = ?", m.Author.ID).Scan(&userID)
|
|
|
|
if err != nil {
|
2024-11-05 00:28:33 -06:00
|
|
|
// Store user in database
|
|
|
|
dbErr := StoreUser(m.Author.ID, m.Author.Username)
|
|
|
|
if dbErr != nil {
|
|
|
|
// Log the error but don't stop command execution
|
|
|
|
log.Printf("Error storing user: %v", dbErr)
|
|
|
|
}
|
|
|
|
|
2024-11-05 00:19:36 -06:00
|
|
|
return fmt.Errorf("failed to get user: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Ensure himbucks entry exists
|
|
|
|
err = GetOrCreateHimbucksEntry(userID, m.GuildID)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("failed to create himbucks entry: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Update message count and check for rewards
|
|
|
|
tx, err := DBClient.Begin()
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("failed to start transaction: %w", err)
|
|
|
|
}
|
|
|
|
defer tx.Rollback()
|
|
|
|
|
|
|
|
var messageCount int
|
|
|
|
var lastEarnedAt sql.NullTime
|
|
|
|
|
|
|
|
err = tx.QueryRow(`
|
|
|
|
SELECT message_count, last_earned_at
|
|
|
|
FROM himbucks
|
|
|
|
WHERE user_id = ? AND guild_id = ?`,
|
|
|
|
userID, m.GuildID).Scan(&messageCount, &lastEarnedAt)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("failed to get message count: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
messageCount++
|
|
|
|
shouldReward := messageCount >= MessageCountThreshold &&
|
|
|
|
(!lastEarnedAt.Valid || time.Since(lastEarnedAt.Time) >= CooldownPeriod)
|
|
|
|
|
|
|
|
if shouldReward {
|
|
|
|
_, err = tx.Exec(`
|
|
|
|
UPDATE himbucks
|
|
|
|
SET balance = balance + ?, message_count = 0, last_earned_at = CURRENT_TIMESTAMP
|
|
|
|
WHERE user_id = ? AND guild_id = ?`,
|
|
|
|
HimbucksPerReward, userID, m.GuildID)
|
|
|
|
} else {
|
|
|
|
_, err = tx.Exec(`
|
|
|
|
UPDATE himbucks
|
|
|
|
SET message_count = ?
|
|
|
|
WHERE user_id = ? AND guild_id = ?`,
|
|
|
|
messageCount, userID, m.GuildID)
|
|
|
|
}
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("failed to update himbucks: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return tx.Commit()
|
|
|
|
}
|
|
|
|
|
|
|
|
func GetBalance(discordID, guildID string) (int, error) {
|
|
|
|
var balance int
|
|
|
|
err := DBClient.QueryRow(`
|
|
|
|
SELECT h.balance
|
|
|
|
FROM himbucks h
|
|
|
|
JOIN users u ON h.user_id = u.id
|
|
|
|
WHERE u.discord_id = ? AND h.guild_id = ?`,
|
|
|
|
discordID, guildID).Scan(&balance)
|
|
|
|
if err == sql.ErrNoRows {
|
|
|
|
return 0, nil
|
|
|
|
}
|
|
|
|
if err != nil {
|
|
|
|
return 0, fmt.Errorf("failed to get balance: %w", err)
|
|
|
|
}
|
|
|
|
return balance, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func GetLeaderboard(guildID string, limit int) ([]HimbucksEntry, error) {
|
|
|
|
rows, err := DBClient.Query(`
|
|
|
|
SELECT u.username, h.balance, h.message_count
|
|
|
|
FROM himbucks h
|
|
|
|
JOIN users u ON h.user_id = u.id
|
|
|
|
WHERE h.guild_id = ?
|
|
|
|
ORDER BY h.balance DESC
|
|
|
|
LIMIT ?`,
|
|
|
|
guildID, limit)
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("failed to get leaderboard: %w", err)
|
|
|
|
}
|
|
|
|
defer rows.Close()
|
|
|
|
|
|
|
|
var entries []HimbucksEntry
|
|
|
|
for rows.Next() {
|
|
|
|
var entry HimbucksEntry
|
|
|
|
err := rows.Scan(&entry.Username, &entry.Balance, &entry.MessageCount)
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("failed to scan leaderboard entry: %w", err)
|
|
|
|
}
|
|
|
|
entries = append(entries, entry)
|
|
|
|
}
|
|
|
|
return entries, nil
|
|
|
|
}
|