aboutsummaryrefslogtreecommitdiff
path: root/config/guild.go
blob: aec78ed61ebfcd71c1806c2ebc98e78864e1f8b9 (plain)
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
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
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
}

type RoleReactMessage struct {
	ID        uint   `gorm:"primarykey"`
	MessageID uint64 `gorm:"not null;unique"`
	ChannelID uint64
	GuildID   uint64
	Note      string
	Roles     []*RoleReact
}

type RoleReact struct {
	ID                 uint `gorm:"primarykey"`
	Reaction           string
	RoleID             uint64
	RoleReactMessageID uint
	CounterID          uint `gorm:"-"`
}

func GetGuild(ctx context.Context, guildID uint64) *Guild {
	cfg := Guild{ID: guildID}
	if err := cfg.Load(ctx); err != nil {
		panic(err)
	}
	return &cfg
}

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 (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 (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) (int, *XpRole) {
	for i, r := range g.XpRoles {
		if r.RoleID == roleID {
			return i, &r
		}
	}
	return 0, nil
}

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 roles, nil
}