From 6e92feaba23a4992e0ec4b529660921a6bcb492a Mon Sep 17 00:00:00 2001 From: Anhgelus Morhtuuzh Date: Sun, 8 Mar 2026 18:51:05 +0100 Subject: feat(config): leave gorm --- config/guild.go | 136 +++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 106 insertions(+), 30 deletions(-) (limited to 'config/guild.go') diff --git a/config/guild.go b/config/guild.go index dc8251f..aec78ed 100644 --- a/config/guild.go +++ b/config/guild.go @@ -2,31 +2,33 @@ package config import ( "context" + "database/sql" + "errors" "fmt" + "slices" "strings" + "git.anhgelus.world/anhgelus/les-copaings-bot/common" "github.com/nyttikord/gokord/bot" "github.com/nyttikord/gokord/channel" ) type Guild struct { - ID uint `gorm:"primarykey"` - GuildID uint64 `gorm:"not null;unique"` - XpRoles []XpRole `gorm:"foreignKey:GuildConfigID"` + ID uint64 + XpRoles []XpRole DisabledChannels string FallbackChannel uint64 - DaysXPRemains uint `gorm:"default:90"` // 30 * 3 = 90 (three months) + DaysXPRemains uint RrMessages []RoleReactMessage } type RoleReactMessage struct { - ID uint `gorm:"primarykey"` - MessageID uint64 `gorm:"not null;unique"` - ChannelID uint64 - GuildID uint64 - Note string - Roles []*RoleReact - GuildConfigID uint + ID uint `gorm:"primarykey"` + MessageID uint64 `gorm:"not null;unique"` + ChannelID uint64 + GuildID uint64 + Note string + Roles []*RoleReact } type RoleReact struct { @@ -37,45 +39,102 @@ type RoleReact struct { CounterID uint `gorm:"-"` } -func GetGuildConfig(ctx context.Context, guildID uint64) *Guild { - cfg := Guild{GuildID: guildID} +func GetGuild(ctx context.Context, guildID uint64) *Guild { + cfg := Guild{ID: guildID} if err := cfg.Load(ctx); err != nil { panic(err) } return &cfg } -func (cfg *Guild) Load(ctx context.Context) error { - return nil //common.GetDB(ctx).Where("guild_id = ?", cfg.GuildID).Preload("XpRoles").FirstOrCreate(cfg).Error +func (g *Guild) Load(ctx context.Context) error { + db := common.GetDB(ctx) + row := db.QueryRowContext( + ctx, + `SELECT disabled_channels, fallback_channel, days_xp_remains FROM guilds WHERE id = ?`, + g.ID, + ) + g.RrMessages = nil + g.XpRoles = nil + err := row.Err() + if err != nil { + if !errors.Is(err, sql.ErrNoRows) { + return err + } + _, err = db.ExecContext( + ctx, + `INSERT INTO guilds (id) VALUES (?)`, + g.ID, + ) + return err + } + err = row.Scan(&g.DisabledChannels, &g.FallbackChannel, &g.DaysXPRemains) + if err != nil { + return err + } + g.XpRoles, err = getXpRoles(ctx, g.ID) + return err } -func (cfg *Guild) Save(ctx context.Context) error { - return nil //common.GetDB(ctx).Save(cfg).Error +func (g *Guild) Save(ctx context.Context) error { + db := common.GetDB(ctx) + _, err := db.ExecContext( + ctx, + `UPDATE guilds SET disabled_channels = ?, fallback_channel = ?, days_xp_remains = ? WHERE id = ?`, + g.DisabledChannels, g.FallbackChannel, g.DaysXPRemains, g.ID, + ) + if err != nil { + return err + } + savedRoles, err := getXpRoles(ctx, g.ID) + if err != nil { + return err + } + roleEqual := func(base XpRole) func(XpRole) bool { + return func(v XpRole) bool { + return v.GuildID == base.GuildID && v.RoleID == base.RoleID && v.XP == base.XP + } + } + // super slow code, but I don't want to implement a data structure to optimize this + for _, role := range g.XpRoles { + if !slices.ContainsFunc(savedRoles, roleEqual(role)) { + err = role.Save(ctx) + if err != nil { + return err + } + } + } + for _, role := range savedRoles { + if !slices.ContainsFunc(g.XpRoles, roleEqual(role)) { + err = role.Delete(ctx) + if err != nil { + return err + } + } + } + return nil } -func (cfg *Guild) IsDisabled(ctx context.Context, dg bot.Session, channelID uint64) bool { +func (g *Guild) IsDisabled(ctx context.Context, dg bot.Session, channelID uint64) bool { ok := true for channelID != 0 && ok { - ok = !strings.Contains(cfg.DisabledChannels, fmt.Sprintf("%d", channelID)) + ok = !strings.Contains(g.DisabledChannels, fmt.Sprintf("%d", channelID)) c, err := dg.ChannelState().GetChannel(channelID) if err != nil { - bot.Logger(ctx).Error("unable to find channel %s in state", "error", err, "channel", c) + bot.Logger(ctx).Warn("unable to find channel %s in state", "error", err, "channel", c) c, err = channel.Get(channelID).Do(ctx) if err != nil { bot.Logger(ctx).Error("unable to fetch channel", "error", err, "channel", c) return false } } - if err != nil { - return false - } channelID = c.ParentID } return !ok } -func (cfg *Guild) FindXpRole(roleID uint64) (int, *XpRole) { - for i, r := range cfg.XpRoles { +func (g *Guild) FindXpRole(roleID uint64) (int, *XpRole) { + for i, r := range g.XpRoles { if r.RoleID == roleID { return i, &r } @@ -83,11 +142,28 @@ func (cfg *Guild) FindXpRole(roleID uint64) (int, *XpRole) { return 0, nil } -func (cfg *Guild) FindXpRoleID(ID uint) (int, *XpRole) { - for i, r := range cfg.XpRoles { - if r.ID == ID { - return i, &r +func getXpRoles(ctx context.Context, gID uint64) ([]XpRole, error) { + roles := make([]XpRole, 0) + rows, err := common.GetDB(ctx).QueryContext( + ctx, + `SELECT xp, role FROM xp_roles WHERE guild_id = ?`, + gID, + ) + if err == nil { + defer rows.Close() + for rows.Next() { + var role XpRole + err = rows.Scan(&role.XP, &role.RoleID) + if err != nil { + return roles, err + } + role.GuildID = gID + roles = append(roles, role) + } + } else { + if !errors.Is(err, sql.ErrNoRows) { + return roles, err } } - return -1, nil + return roles, nil } -- cgit v1.2.3