aboutsummaryrefslogtreecommitdiff
path: root/config/guild.go
blob: 10e30ff4ff442935f2bc98e922a86df74eea666b (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
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
}