Reviewed-on: #108
This commit is contained in:
parent
5de9348f67
commit
09ffc7644a
2
go.mod
2
go.mod
|
@ -8,6 +8,7 @@ require (
|
|||
github.com/google/uuid v1.3.0
|
||||
github.com/jackc/pgerrcode v0.0.0-20220416144525-469b46aa5efa
|
||||
github.com/kelseyhightower/envconfig v1.4.0
|
||||
github.com/nicksnyder/go-i18n/v2 v2.2.1
|
||||
github.com/ory/dockertest/v3 v3.10.0
|
||||
github.com/pressly/goose/v3 v3.11.2
|
||||
github.com/robfig/cron/v3 v3.0.1
|
||||
|
@ -18,6 +19,7 @@ require (
|
|||
github.com/uptrace/bun/driver/pgdriver v1.1.14
|
||||
github.com/urfave/cli/v2 v2.25.5
|
||||
go.uber.org/zap v1.24.0
|
||||
golang.org/x/text v0.9.0
|
||||
golang.org/x/time v0.3.0
|
||||
)
|
||||
|
||||
|
|
19
go.sum
19
go.sum
|
@ -1,5 +1,7 @@
|
|||
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0=
|
||||
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
|
||||
github.com/BurntSushi/toml v1.0.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
|
||||
github.com/BurntSushi/toml v1.2.1 h1:9F2/+DoOYIOksmaJFPw1tGFy1eDnIJXg+UHjuD8lTak=
|
||||
github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow=
|
||||
github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM=
|
||||
github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw=
|
||||
|
@ -55,6 +57,8 @@ github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyua
|
|||
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0=
|
||||
github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y=
|
||||
github.com/nicksnyder/go-i18n/v2 v2.2.1 h1:aOzRCdwsJuoExfZhoiXHy4bjruwCMdt5otbYojM/PaA=
|
||||
github.com/nicksnyder/go-i18n/v2 v2.2.1/go.mod h1:fF2++lPHlo+/kPaj3nB0uxtPwzlPm+BlgwGX7MkeGj0=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
|
||||
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
|
||||
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
|
||||
|
@ -110,6 +114,7 @@ github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRT
|
|||
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8=
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
|
||||
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||
go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI=
|
||||
|
@ -121,10 +126,12 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk
|
|||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g=
|
||||
golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0=
|
||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk=
|
||||
golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
|
@ -132,27 +139,38 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL
|
|||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU=
|
||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
|
||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
|
||||
golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/tools v0.8.0 h1:vSDcovVPld282ceKgDimkRSC8kpaH1dgyc9UMzlt84Y=
|
||||
golang.org/x/tools v0.8.0/go.mod h1:JxBZ99ISMI5ViVkT1tr6tdNmXeTrcpVSD3vZ1RsRdN4=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
|
@ -161,6 +179,7 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T
|
|||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
|
||||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
|
|
|
@ -5,16 +5,18 @@ import (
|
|||
"fmt"
|
||||
"time"
|
||||
|
||||
"gitea.dwysokinski.me/twhelp/dcbot/internal/discord/internal/discordi18n"
|
||||
"gitea.dwysokinski.me/twhelp/dcbot/internal/domain"
|
||||
"github.com/bwmarrin/discordgo"
|
||||
"github.com/robfig/cron/v3"
|
||||
"go.uber.org/zap"
|
||||
"golang.org/x/text/language"
|
||||
)
|
||||
|
||||
type GroupService interface {
|
||||
Create(ctx context.Context, params domain.CreateGroupParams) (domain.GroupWithMonitors, error)
|
||||
AddMonitor(ctx context.Context, id, serverID, tribeTag string) (domain.GroupWithMonitors, error)
|
||||
DeleteMonitor(ctx context.Context, id, serverID, tribeTag string) (domain.GroupWithMonitors, error)
|
||||
AddTribe(ctx context.Context, id, serverID, tribeTag string) (domain.GroupWithMonitors, error)
|
||||
RemoveTribe(ctx context.Context, id, serverID, tribeTag string) (domain.GroupWithMonitors, error)
|
||||
SetChannelGains(ctx context.Context, id, serverID, channel string) (domain.GroupWithMonitors, error)
|
||||
SetChannelLosses(ctx context.Context, id, serverID, channel string) (domain.GroupWithMonitors, error)
|
||||
SetInternals(ctx context.Context, id, serverID string, internals bool) (domain.GroupWithMonitors, error)
|
||||
|
@ -31,11 +33,12 @@ type ChoiceService interface {
|
|||
}
|
||||
|
||||
type Bot struct {
|
||||
s *discordgo.Session
|
||||
c *cron.Cron
|
||||
session *discordgo.Session
|
||||
cron *cron.Cron
|
||||
groupSvc GroupService
|
||||
choiceSvc ChoiceService
|
||||
logger *zap.Logger
|
||||
localizer *discordi18n.Localizer
|
||||
}
|
||||
|
||||
func NewBot(
|
||||
|
@ -44,16 +47,20 @@ func NewBot(
|
|||
client ChoiceService,
|
||||
logger *zap.Logger,
|
||||
) (*Bot, error) {
|
||||
localizer, err := discordi18n.NewLocalizer(language.English)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
s, err := discordgo.New("Bot " + token)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("discordgo.New: %w", err)
|
||||
}
|
||||
|
||||
s.Identify.Intents = discordgo.IntentsNone
|
||||
|
||||
b := &Bot{
|
||||
s: s,
|
||||
c: cron.New(
|
||||
session: s,
|
||||
cron: cron.New(
|
||||
cron.WithLocation(time.UTC),
|
||||
cron.WithChain(
|
||||
cron.SkipIfStillRunning(cron.DiscardLogger),
|
||||
|
@ -62,29 +69,30 @@ func NewBot(
|
|||
groupSvc: groupSvc,
|
||||
choiceSvc: client,
|
||||
logger: logger,
|
||||
localizer: localizer,
|
||||
}
|
||||
|
||||
b.s.AddHandler(b.handleSessionReady)
|
||||
b.s.AddHandler(b.logCommands)
|
||||
b.session.AddHandler(b.handleSessionReady)
|
||||
b.session.AddHandler(b.logCommands)
|
||||
|
||||
return b, nil
|
||||
}
|
||||
|
||||
func (b *Bot) Run() error {
|
||||
if err := b.initCron(); err != nil {
|
||||
if err := b.registerCronJobs(); err != nil {
|
||||
return fmt.Errorf("initCron: %w", err)
|
||||
}
|
||||
|
||||
if err := b.s.Open(); err != nil {
|
||||
if err := b.session.Open(); err != nil {
|
||||
return fmt.Errorf("s.Open: %w", err)
|
||||
}
|
||||
|
||||
if err := b.registerCommands(); err != nil {
|
||||
_ = b.s.Close()
|
||||
_ = b.session.Close()
|
||||
return fmt.Errorf("couldn't register commands: %w", err)
|
||||
}
|
||||
|
||||
b.c.Run()
|
||||
b.cron.Run()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -96,33 +104,26 @@ type command interface {
|
|||
|
||||
func (b *Bot) registerCommands() error {
|
||||
commands := []command{
|
||||
&groupCommand{groupSvc: b.groupSvc, choiceSvc: b.choiceSvc},
|
||||
&groupCommand{localizer: b.localizer, logger: b.logger, groupSvc: b.groupSvc, choiceSvc: b.choiceSvc},
|
||||
}
|
||||
|
||||
for _, c := range commands {
|
||||
if err := b.registerCommand(c); err != nil {
|
||||
return err
|
||||
for _, cmd := range commands {
|
||||
if err := cmd.register(b.session); err != nil {
|
||||
return fmt.Errorf("couldn't register command '%s': %w", cmd.name(), err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *Bot) registerCommand(cmd command) error {
|
||||
if err := cmd.register(b.s); err != nil {
|
||||
return fmt.Errorf("couldn't register command '%s': %w", cmd.name(), err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *Bot) initCron() error {
|
||||
func (b *Bot) registerCronJobs() error {
|
||||
jobs := []struct {
|
||||
spec string
|
||||
job cron.Job
|
||||
}{
|
||||
{
|
||||
spec: "@every 1m",
|
||||
job: &executeMonitorsJob{svc: b.groupSvc, s: b.s, logger: b.logger},
|
||||
job: &executeMonitorsJob{svc: b.groupSvc, s: b.session, logger: b.logger},
|
||||
},
|
||||
{
|
||||
spec: "0 */8 * * *",
|
||||
|
@ -131,8 +132,7 @@ func (b *Bot) initCron() error {
|
|||
}
|
||||
|
||||
for _, j := range jobs {
|
||||
_, err := b.c.AddJob(j.spec, j.job)
|
||||
if err != nil {
|
||||
if _, err := b.cron.AddJob(j.spec, j.job); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
@ -175,6 +175,6 @@ func (b *Bot) logCommands(_ *discordgo.Session, i *discordgo.InteractionCreate)
|
|||
}
|
||||
|
||||
func (b *Bot) Close() error {
|
||||
<-b.c.Stop().Done()
|
||||
return b.s.Close()
|
||||
<-b.cron.Stop().Done()
|
||||
return b.session.Close()
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,35 @@
|
|||
package discordi18n
|
||||
|
||||
import (
|
||||
"embed"
|
||||
"encoding/json"
|
||||
"io/fs"
|
||||
|
||||
"github.com/nicksnyder/go-i18n/v2/i18n"
|
||||
"golang.org/x/text/language"
|
||||
)
|
||||
|
||||
//go:embed locale.*.json
|
||||
var localeFS embed.FS
|
||||
|
||||
func newBundle(defaultLanguage language.Tag) (*i18n.Bundle, error) {
|
||||
b := i18n.NewBundle(defaultLanguage)
|
||||
b.RegisterUnmarshalFunc("json", json.Unmarshal)
|
||||
|
||||
err := fs.WalkDir(localeFS, ".", func(path string, d fs.DirEntry, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if d.IsDir() {
|
||||
return nil
|
||||
}
|
||||
|
||||
_, err = b.LoadMessageFileFS(localeFS, path)
|
||||
return err
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return b, nil
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
{
|
||||
"cmd.group.description": "Manages groups on this server",
|
||||
|
||||
"cmd.group.create.description": "Creates a new monitor group",
|
||||
"cmd.group.create.option.version.description": "e.g. www.tribalwars.net, www.plemiona.pl",
|
||||
"cmd.group.create.option.server.description": "Tribal Wars server (e.g. en115, pl170)",
|
||||
"cmd.group.create.option.internals.description": "Show conquers in the same group",
|
||||
"cmd.group.create.option.barbarians.description": "Show barbarian conquers",
|
||||
"cmd.group.create.option.channel-gains.description": "Channel where notifications of gained villages will appear",
|
||||
"cmd.group.create.option.channel-losses.description": "Channel where notifications of lost villages will appear",
|
||||
"cmd.group.create.success": "The group has been successfully created (id={{ .GroupID }}).",
|
||||
|
||||
"cmd.group.list.description": "Lists all created groups on this server",
|
||||
"cmd.group.list.embed.title": "Group list",
|
||||
"cmd.group.list.embed.field.value": "**Server**: {{ .ServerKey }}\n**Channel gains**: {{ .ChannelGains }}\n**Channel losses**: {{ .ChannelLosses }}\n**Internals**: {{ .Internals }}\n **Barbarians**: {{ .Barbarians }}\n **Number of monitored tribes**: {{ .NumTribes }}",
|
||||
|
||||
"cmd.group.details.description": "Displays group details (including added tribes)",
|
||||
"cmd.group.details.embed.description": "**Server**: {{ .ServerKey }}\n**Channel gains**: {{ .ChannelGains }}\n**Channel losses**: {{ .ChannelLosses }}\n**Internals**: {{ .Internals }}\n **Barbarians**: {{ .Barbarians }}\n **Tribes**: {{ .Tribes }}",
|
||||
|
||||
"cmd.group.tribe.description": "Manages tribes in a group",
|
||||
|
||||
"cmd.group.tribe.add.description": "Adds a tribe to a group",
|
||||
"cmd.group.tribe.add.option.group.description": "Group ID",
|
||||
"cmd.group.tribe.add.option.tag.description": "Tribe tag",
|
||||
"cmd.group.tribe.add.success": "The tribe has been successfully added to the group.",
|
||||
|
||||
"cmd.group.tribe.remove.description": "Removes a tribe from a group",
|
||||
"cmd.group.tribe.remove.option.group.description": "Group ID",
|
||||
"cmd.group.tribe.remove.option.tag.description": "Tribe tag",
|
||||
"cmd.group.tribe.remove.success": "The tribe has been successfully removed from the group.",
|
||||
|
||||
"cmd.group.set.description": "Sets various properties in group configuration",
|
||||
|
||||
"cmd.group.set.channel-gains.description": "Enables/disables notifications of gained villages",
|
||||
"cmd.group.set.channel-gains.option.group.description": "Group ID",
|
||||
"cmd.group.set.channel-gains.option.channel.description": "Channel where notifications of gained villages will appear",
|
||||
"cmd.group.set.channel-gains.success": "The group has been successfully updated.",
|
||||
|
||||
"cmd.group.set.channel-losses.description": "Enables/disables notifications of lost villages",
|
||||
"cmd.group.set.channel-losses.option.group.description": "Group ID",
|
||||
"cmd.group.set.channel-losses.option.channel.description": "Channel where notifications of lost villages will appear",
|
||||
"cmd.group.set.channel-losses.success": "The group has been successfully updated.",
|
||||
|
||||
"cmd.group.set.internals.description": "Enables/disables notifications of internal conquers",
|
||||
"cmd.group.set.internals.option.group.description": "Group ID",
|
||||
"cmd.group.set.internals.option.internals.description": "Show conquers in the same group",
|
||||
"cmd.group.set.internals.success": "The group has been successfully updated.",
|
||||
|
||||
"cmd.group.set.barbarians.description": "Enables/disables notifications of barbarian conquers",
|
||||
"cmd.group.set.barbarians.option.group.description": "Group ID",
|
||||
"cmd.group.set.barbarians.option.barbarians.description": "Show barbarian conquers",
|
||||
"cmd.group.set.barbarians.success": "The group has been successfully updated.",
|
||||
|
||||
"cmd.group.delete.description": "Deletes a group",
|
||||
"cmd.group.delete.option.group.description": "Group ID",
|
||||
"cmd.group.delete.success": "The group has been successfully deleted."
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
{
|
||||
"cmd.group.description": "Umożliwia zarządzanie grupami na tym serwerze",
|
||||
|
||||
"cmd.group.create.description": "Tworzy nową grupę",
|
||||
"cmd.group.create.option.version.description": "np. www.tribalwars.net, www.plemiona.pl",
|
||||
"cmd.group.create.option.server.description": "Serwer (np. en115, pl170)",
|
||||
"cmd.group.create.option.internals.description": "Informuj o przejęciach wewnętrznych",
|
||||
"cmd.group.create.option.barbarians.description": "Informuj o przejęciach wiosek barbarzyńskich",
|
||||
"cmd.group.create.option.channel-gains.description": "Kanał na którym będą pojawiać się powiadomienia o zdobytych wioskach",
|
||||
"cmd.group.create.option.channel-losses.description": "Kanał na którym będą pojawiać się powiadomienia o straconych wioskach",
|
||||
"cmd.group.create.success": "Grupa została pomyślnie utworzona (id={{ .GroupID }})",
|
||||
|
||||
"cmd.group.list.description": "Wyświetla wszystkie utworzone grupy na tym serwerze",
|
||||
"cmd.group.list.embed.title": "Grupy",
|
||||
"cmd.group.list.embed.field.value": "**Serwer**: {{ .ServerKey }}\n**Kanał zdobyte wioski**: {{ .ChannelGains }}\n**Kanał stracone wioski**: {{ .ChannelLosses }}\n**Przejęcia wewnętrzne**: {{ .Internals }}\n **Przejęcia barbarek**: {{ .Barbarians }}\n **Liczba monitorowanych plemion**: {{ .NumTribes }}",
|
||||
|
||||
"cmd.group.details.description": "Wyświetla szczegóły grupy (w tym dodane plemiona)",
|
||||
"cmd.group.details.embed.description": "**Serwer**: {{ .ServerKey }}\n**Kanał zdobyte wioski**: {{ .ChannelGains }}\n**Kanał stracone wioski**: {{ .ChannelLosses }}\n**Przejęcia wewnętrzne**: {{ .Internals }}\n **Przejęcia barbarek**: {{ .Barbarians }}\n **Plemiona**: {{ .Tribes }}",
|
||||
|
||||
"cmd.group.tribe.description": "Zarządza plemionami w grupie",
|
||||
|
||||
"cmd.group.tribe.add.description": "Dodaje plemię do grupy",
|
||||
"cmd.group.tribe.add.option.group.description": "ID grupy",
|
||||
"cmd.group.tribe.add.option.tag.description": "Skrót plemienia",
|
||||
"cmd.group.tribe.add.success": "Plemię zostało dodane do grupy.",
|
||||
|
||||
"cmd.group.tribe.remove.description": "Usuwa plemię z grupy",
|
||||
"cmd.group.tribe.remove.option.group.description": "ID grupy",
|
||||
"cmd.group.tribe.remove.option.tag.description": "Skrót plemienia",
|
||||
"cmd.group.tribe.remove.success": "Plemię zostało usunięte z grupy.",
|
||||
|
||||
"cmd.group.set.description": "Ustawia różne właściwości w konfiguracji grupy",
|
||||
|
||||
"cmd.group.set.channel-gains.description": "Włącza/wyłącza powiadomienia o podbitych wioskach",
|
||||
"cmd.group.set.channel-gains.option.group.description": "ID grupy",
|
||||
"cmd.group.set.channel-gains.option.channel.description": "Kanał na którym będą pojawiać się powiadomienia o zdobytych wioskach",
|
||||
"cmd.group.set.channel-gains.success": "Grupa została pomyślnie zaaktualizowana.",
|
||||
|
||||
"cmd.group.set.channel-losses.description": "Włącza/wyłącza powiadomienia o straconych wioskach",
|
||||
"cmd.group.set.channel-losses.option.group.description": "ID grupy",
|
||||
"cmd.group.set.channel-losses.option.channel.description": "Kanał na którym będą pojawiać się powiadomienia o straconych wioskach",
|
||||
"cmd.group.set.channel-losses.success": "Grupa została pomyślnie zaaktualizowana.",
|
||||
|
||||
"cmd.group.set.internals.description": "Włącza/wyłącza powiadomienia o wewnętrznych przejęciach",
|
||||
"cmd.group.set.internals.option.group.description": "ID grupy",
|
||||
"cmd.group.set.internals.option.internals.description": "Informuj o przejęciach wewnętrznych",
|
||||
"cmd.group.set.internals.success": "Grupa została pomyślnie zaaktualizowana.",
|
||||
|
||||
"cmd.group.set.barbarians.description": "Włącza/wyłącza powiadomienia o przejęciach wiosek barbarzyńskich",
|
||||
"cmd.group.set.barbarians.option.group.description": "ID grupy",
|
||||
"cmd.group.set.barbarians.option.barbarians.description": "Informuj o przejęciach wiosek barbarzyńskich",
|
||||
"cmd.group.set.barbarians.success": "Grupa została pomyślnie zaaktualizowana.",
|
||||
|
||||
"cmd.group.delete.description": "Usuwa grupę",
|
||||
"cmd.group.delete.option.group.description": "ID grupy",
|
||||
"cmd.group.delete.success": "Grupa została pomyślnie usunięta."
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
package discordi18n
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/bwmarrin/discordgo"
|
||||
"github.com/nicksnyder/go-i18n/v2/i18n"
|
||||
"golang.org/x/text/language"
|
||||
)
|
||||
|
||||
type Localizer struct {
|
||||
bundle *i18n.Bundle
|
||||
defaultLanguage language.Tag
|
||||
}
|
||||
|
||||
func NewLocalizer(defaultLanguage language.Tag) (*Localizer, error) {
|
||||
b, err := newBundle(defaultLanguage)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Localizer{
|
||||
bundle: b,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (l *Localizer) Localize(lang string, lc *i18n.LocalizeConfig) (string, error) {
|
||||
return i18n.NewLocalizer(l.bundle, lang, l.defaultLanguage.String()).Localize(lc)
|
||||
}
|
||||
|
||||
func (l *Localizer) LocalizeWithTag(lang string, lc *i18n.LocalizeConfig) (string, language.Tag, error) {
|
||||
return i18n.NewLocalizer(l.bundle, lang, l.defaultLanguage.String()).LocalizeWithTag(lc)
|
||||
}
|
||||
|
||||
func (l *Localizer) LocalizeDiscord(messageID string) (string, map[discordgo.Locale]string, error) {
|
||||
return l.LocalizeDiscordWithConfig(&i18n.LocalizeConfig{
|
||||
MessageID: messageID,
|
||||
})
|
||||
}
|
||||
|
||||
func (l *Localizer) LocalizeDiscordWithConfig(lc *i18n.LocalizeConfig) (string, map[discordgo.Locale]string, error) {
|
||||
m := make(map[discordgo.Locale]string)
|
||||
|
||||
for _, tag := range l.bundle.LanguageTags() {
|
||||
locale := discordgo.Locale(tag.String())
|
||||
|
||||
if discordgo.Locales[locale] == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
msg, msgLang, err := l.LocalizeWithTag(tag.String(), lc)
|
||||
if err != nil {
|
||||
return "", nil, fmt.Errorf("couldn't lookup message in locale '%s': %w", locale, err)
|
||||
}
|
||||
|
||||
if msgLang == l.defaultLanguage {
|
||||
continue
|
||||
}
|
||||
|
||||
m[locale] = msg
|
||||
}
|
||||
|
||||
defaultMsg, err := l.Localize(l.defaultLanguage.String(), lc)
|
||||
if err != nil {
|
||||
return "", nil, fmt.Errorf("couldn't lookup message in default language: %w", err)
|
||||
}
|
||||
|
||||
return defaultMsg, m, nil
|
||||
}
|
|
@ -45,19 +45,3 @@ func (e ValidationError) Code() ErrorCode {
|
|||
func (e ValidationError) Unwrap() error {
|
||||
return e.Err
|
||||
}
|
||||
|
||||
type MinError struct {
|
||||
Min int
|
||||
}
|
||||
|
||||
func (e MinError) Error() string {
|
||||
return fmt.Sprintf("must be no less than %d", e.Min)
|
||||
}
|
||||
|
||||
func (e MinError) UserError() string {
|
||||
return e.Error()
|
||||
}
|
||||
|
||||
func (e MinError) Code() ErrorCode {
|
||||
return ErrorCodeValidationError
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package domain_test
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
|
@ -13,9 +14,7 @@ func TestValidationError(t *testing.T) {
|
|||
|
||||
err := domain.ValidationError{
|
||||
Field: "test",
|
||||
Err: domain.MinError{
|
||||
Min: 25,
|
||||
},
|
||||
Err: errors.New("err"),
|
||||
}
|
||||
var _ domain.Error = err
|
||||
assert.Equal(t, fmt.Sprintf("%s: %s", err.Field, err.Err.Error()), err.Error())
|
||||
|
@ -23,15 +22,3 @@ func TestValidationError(t *testing.T) {
|
|||
assert.ErrorIs(t, err, err.Err)
|
||||
assert.Equal(t, domain.ErrorCodeValidationError, err.Code())
|
||||
}
|
||||
|
||||
func TestMinError(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
err := domain.MinError{
|
||||
Min: 25,
|
||||
}
|
||||
var _ domain.Error = err
|
||||
assert.Equal(t, "must be no less than 25", err.Error())
|
||||
assert.Equal(t, err.Error(), err.UserError())
|
||||
assert.Equal(t, domain.ErrorCodeValidationError, err.Code())
|
||||
}
|
||||
|
|
|
@ -94,7 +94,7 @@ func (g *Group) checkTWServer(ctx context.Context, versionCode, serverKey string
|
|||
return nil
|
||||
}
|
||||
|
||||
func (g *Group) AddMonitor(ctx context.Context, id, serverID, tribeTag string) (domain.GroupWithMonitors, error) {
|
||||
func (g *Group) AddTribe(ctx context.Context, id, serverID, tribeTag string) (domain.GroupWithMonitors, error) {
|
||||
// check if group exists
|
||||
groupBeforeUpdate, err := g.Get(ctx, id, serverID)
|
||||
if err != nil {
|
||||
|
@ -137,7 +137,7 @@ func (g *Group) AddMonitor(ctx context.Context, id, serverID, tribeTag string) (
|
|||
return group, nil
|
||||
}
|
||||
|
||||
func (g *Group) DeleteMonitor(ctx context.Context, id, serverID, tribeTag string) (domain.GroupWithMonitors, error) {
|
||||
func (g *Group) RemoveTribe(ctx context.Context, id, serverID, tribeTag string) (domain.GroupWithMonitors, error) {
|
||||
// check if group exists
|
||||
groupBeforeUpdate, err := g.Get(ctx, id, serverID)
|
||||
if err != nil {
|
||||
|
|
|
@ -143,7 +143,7 @@ func TestGroup_Create(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
func TestGroup_AddMonitor(t *testing.T) {
|
||||
func TestGroup_AddTribe(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
t.Run("OK", func(t *testing.T) {
|
||||
|
@ -178,7 +178,7 @@ func TestGroup_AddMonitor(t *testing.T) {
|
|||
|
||||
g, err := service.
|
||||
NewGroup(repo, client, zap.NewNop(), 1, 1).
|
||||
AddMonitor(context.Background(), group.ID, group.ServerID, tribe.Tag)
|
||||
AddTribe(context.Background(), group.ID, group.ServerID, tribe.Tag)
|
||||
assert.NoError(t, err)
|
||||
require.Len(t, g.Monitors, 1)
|
||||
assert.NotZero(t, g.Monitors[0].ID)
|
||||
|
@ -227,7 +227,7 @@ func TestGroup_AddMonitor(t *testing.T) {
|
|||
|
||||
g, err := service.
|
||||
NewGroup(repo, nil, zap.NewNop(), 1, 1).
|
||||
AddMonitor(context.Background(), group.ID, uuid.NewString(), "*TAG*")
|
||||
AddTribe(context.Background(), group.ID, uuid.NewString(), "*TAG*")
|
||||
assert.ErrorIs(t, err, domain.GroupDoesNotExistError{
|
||||
ID: group.ID,
|
||||
})
|
||||
|
@ -253,7 +253,7 @@ func TestGroup_AddMonitor(t *testing.T) {
|
|||
|
||||
g, err := service.
|
||||
NewGroup(repo, nil, zap.NewNop(), 1, maxMonitorsPerGroup).
|
||||
AddMonitor(context.Background(), group.ID, group.ServerID, "*TAG*")
|
||||
AddTribe(context.Background(), group.ID, group.ServerID, "*TAG*")
|
||||
assert.ErrorIs(t, err, domain.MonitorLimitReachedError{
|
||||
Current: len(group.Monitors),
|
||||
Limit: maxMonitorsPerGroup,
|
||||
|
@ -279,7 +279,7 @@ func TestGroup_AddMonitor(t *testing.T) {
|
|||
tribeTag := "*TAG*"
|
||||
g, err := service.
|
||||
NewGroup(repo, client, zap.NewNop(), 1, 1).
|
||||
AddMonitor(context.Background(), group.ID, group.ServerID, tribeTag)
|
||||
AddTribe(context.Background(), group.ID, group.ServerID, tribeTag)
|
||||
assert.ErrorIs(t, err, domain.TribeDoesNotExistError{
|
||||
Tag: tribeTag,
|
||||
})
|
||||
|
@ -287,7 +287,7 @@ func TestGroup_AddMonitor(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
func TestGroup_DeleteMonitor(t *testing.T) {
|
||||
func TestGroup_RemoveTribe(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
t.Run("OK", func(t *testing.T) {
|
||||
|
@ -341,7 +341,7 @@ func TestGroup_DeleteMonitor(t *testing.T) {
|
|||
|
||||
g, err := service.
|
||||
NewGroup(repo, client, zap.NewNop(), 1, 1).
|
||||
DeleteMonitor(context.Background(), group.ID, group.ServerID, tribe.Tag)
|
||||
RemoveTribe(context.Background(), group.ID, group.ServerID, tribe.Tag)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, g.Monitors, len(group.Monitors)-1)
|
||||
assert.NotContains(t, g.Monitors, group.Monitors[0])
|
||||
|
@ -393,7 +393,7 @@ func TestGroup_DeleteMonitor(t *testing.T) {
|
|||
|
||||
g, err := service.
|
||||
NewGroup(repo, nil, zap.NewNop(), 1, 1).
|
||||
DeleteMonitor(context.Background(), group.ID, tt.serverID, group.Monitors[0].ID)
|
||||
RemoveTribe(context.Background(), group.ID, tt.serverID, group.Monitors[0].ID)
|
||||
assert.ErrorIs(t, err, domain.GroupNotFoundError{
|
||||
ID: group.ID,
|
||||
})
|
||||
|
@ -449,7 +449,7 @@ func TestGroup_DeleteMonitor(t *testing.T) {
|
|||
tag := "*X*"
|
||||
g, err := service.
|
||||
NewGroup(repo, client, zap.NewNop(), 1, 1).
|
||||
DeleteMonitor(context.Background(), group.ID, group.ServerID, tag)
|
||||
RemoveTribe(context.Background(), group.ID, group.ServerID, tag)
|
||||
assert.ErrorIs(t, err, domain.TribeNotFoundError{
|
||||
Tag: tag,
|
||||
})
|
||||
|
|
Loading…
Reference in New Issue