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 uint64 XpRoles []*XpRole DisabledChannels string FallbackChannel uint64 DaysXPRemains uint RrMessages []*RoleReactMessage } func GetGuild(ctx context.Context, guildID uint64) *Guild { cfg := Guild{ID: guildID} if err := cfg.load(ctx, common.GetDB(ctx)); err != nil { panic(err) } return &cfg } func (g *Guild) load(ctx context.Context, db *sql.DB) error { 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, db, g.ID) if err != nil { return err } g.RrMessages, err = getRoleReactMessages(ctx, db, g.ID) return err } func (g *Guild) Save(ctx context.Context, db *sql.DB) error { _, 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, db, 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, db) if err != nil { return err } } } for _, role := range savedRoles { if !slices.ContainsFunc(g.XpRoles, roleEqual(role)) { err = role.Delete(ctx, db) if err != nil { return err } } } return nil } func (g *Guild) IsDisabled(ctx context.Context, dg bot.Session, channelID uint64) bool { ok := true for channelID != 0 && ok { ok = !strings.Contains(g.DisabledChannels, fmt.Sprintf("%d", channelID)) c, err := dg.ChannelState().GetChannel(channelID) if err != nil { 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 } } channelID = c.ParentID } return !ok } func (g *Guild) FindXpRole(roleID uint64) *XpRole { for _, r := range g.XpRoles { if r.RoleID == roleID { return r } } return nil }