1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
|
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
}
|