feat: enable/disable notifications of internal/barbarian conquers (#31)
All checks were successful
continuous-integration/drone/push Build is passing

Reviewed-on: #31
This commit is contained in:
Dawid Wysokiński 2022-10-28 11:59:20 +00:00
parent 3fcf38f5c7
commit 77c52c117e
14 changed files with 497 additions and 27 deletions

View File

@ -27,6 +27,8 @@ func (g *Group) Create(ctx context.Context, params domain.CreateGroupParams) (do
ChannelGains: params.ChannelGains(), ChannelGains: params.ChannelGains(),
ChannelLosses: params.ChannelLosses(), ChannelLosses: params.ChannelLosses(),
ServerKey: params.ServerKey(), ServerKey: params.ServerKey(),
Barbarians: params.Barbarians(),
Internals: params.Internals(),
} }
if _, err := g.db.NewInsert(). if _, err := g.db.NewInsert().
@ -149,6 +151,14 @@ func (u updateGroupsParamsApplier) apply(q *bun.UpdateQuery) *bun.UpdateQuery {
} }
} }
if u.params.Barbarians.Valid {
q = q.Set("barbarians = ?", u.params.Barbarians.Bool)
}
if u.params.Internals.Valid {
q = q.Set("internals = ?", u.params.Internals.Bool)
}
return q return q
} }

View File

@ -28,6 +28,8 @@ func TestGroup_Create(t *testing.T) {
"en113", "en113",
"1234", "1234",
"1235", "1235",
true,
true,
) )
require.NoError(t, err) require.NoError(t, err)
@ -40,6 +42,8 @@ func TestGroup_Create(t *testing.T) {
assert.Equal(t, params.VersionCode(), group.VersionCode) assert.Equal(t, params.VersionCode(), group.VersionCode)
assert.Equal(t, params.ChannelGains(), group.ChannelGains) assert.Equal(t, params.ChannelGains(), group.ChannelGains)
assert.Equal(t, params.ChannelLosses(), group.ChannelLosses) assert.Equal(t, params.ChannelLosses(), group.ChannelLosses)
assert.Equal(t, params.Barbarians(), group.Barbarians)
assert.Equal(t, params.Internals(), group.Internals)
assert.WithinDuration(t, time.Now(), group.CreatedAt, 1*time.Second) assert.WithinDuration(t, time.Now(), group.CreatedAt, 1*time.Second)
}) })
} }
@ -64,12 +68,22 @@ func TestGroup_Update(t *testing.T) {
String: group.ChannelLosses + "update", String: group.ChannelLosses + "update",
Valid: true, Valid: true,
}, },
Barbarians: domain.NullBool{
Bool: !group.Barbarians,
Valid: true,
},
Internals: domain.NullBool{
Bool: !group.Internals,
Valid: true,
},
} }
updatedGroup, err := repo.Update(context.Background(), group.ID.String(), group.ServerID, params) updatedGroup, err := repo.Update(context.Background(), group.ID.String(), group.ServerID, params)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, params.ChannelGains.String, updatedGroup.ChannelGains) assert.Equal(t, params.ChannelGains.String, updatedGroup.ChannelGains)
assert.Equal(t, params.ChannelLosses.String, updatedGroup.ChannelLosses) assert.Equal(t, params.ChannelLosses.String, updatedGroup.ChannelLosses)
assert.Equal(t, params.Barbarians.Bool, updatedGroup.Barbarians)
assert.Equal(t, params.Internals.Bool, updatedGroup.Internals)
}) })
t.Run("ERR: nothing to update", func(t *testing.T) { t.Run("ERR: nothing to update", func(t *testing.T) {

View File

@ -15,6 +15,8 @@ type Group struct {
ServerID string `bun:"server_id,type:varchar(100),notnull"` ServerID string `bun:"server_id,type:varchar(100),notnull"`
ChannelGains string `bun:"channel_gains,type:varchar(100),nullzero"` ChannelGains string `bun:"channel_gains,type:varchar(100),nullzero"`
ChannelLosses string `bun:"channel_losses,type:varchar(100),nullzero"` ChannelLosses string `bun:"channel_losses,type:varchar(100),nullzero"`
Internals bool `bun:"internals,default:false"`
Barbarians bool `bun:"barbarians,default:false"`
ServerKey string `bun:"server_key,type:varchar(50),notnull"` ServerKey string `bun:"server_key,type:varchar(50),notnull"`
VersionCode string `bun:"version_code,type:varchar(6),notnull"` VersionCode string `bun:"version_code,type:varchar(6),notnull"`
CreatedAt time.Time `bun:"created_at,nullzero,notnull,default:current_timestamp"` CreatedAt time.Time `bun:"created_at,nullzero,notnull,default:current_timestamp"`
@ -26,6 +28,8 @@ func (g Group) ToDomain() domain.Group {
ServerID: g.ServerID, ServerID: g.ServerID,
ChannelGains: g.ChannelGains, ChannelGains: g.ChannelGains,
ChannelLosses: g.ChannelLosses, ChannelLosses: g.ChannelLosses,
Internals: g.Internals,
Barbarians: g.Barbarians,
ServerKey: g.ServerKey, ServerKey: g.ServerKey,
VersionCode: g.VersionCode, VersionCode: g.VersionCode,
CreatedAt: g.CreatedAt, CreatedAt: g.CreatedAt,

View File

@ -0,0 +1,47 @@
package migrations
import (
"context"
"database/sql"
"fmt"
"gitea.dwysokinski.me/twhelp/dcbot/internal/bundb/internal/model"
"github.com/uptrace/bun"
)
func init() {
Migrations.MustRegister(func(ctx context.Context, db *bun.DB) error {
return db.RunInTx(ctx, &sql.TxOptions{}, func(ctx context.Context, tx bun.Tx) error {
columns := []string{
"internals",
"barbarians",
}
for _, c := range columns {
if _, err := tx.NewAddColumn().
Model(&model.Group{}).
ColumnExpr("? boolean default false", bun.Safe(c)).
IfNotExists().
Exec(ctx); err != nil {
return fmt.Errorf("couldn't add the %s column: %w", c, err)
}
}
return nil
})
}, func(ctx context.Context, db *bun.DB) error {
return db.RunInTx(ctx, &sql.TxOptions{}, func(ctx context.Context, tx bun.Tx) error {
columns := []string{
"internals",
"barbarians",
}
for _, c := range columns {
if _, err := tx.NewDropColumn().
Model(&model.Group{}).
Column(c).
Exec(ctx); err != nil {
return fmt.Errorf("couldn't drop the %s column: %w", c, err)
}
}
return nil
})
})
}

View File

@ -14,6 +14,8 @@ type GroupService interface {
Create(ctx context.Context, params domain.CreateGroupParams) (domain.Group, error) Create(ctx context.Context, params domain.CreateGroupParams) (domain.Group, error)
SetChannelGains(ctx context.Context, id, serverID, channel string) (domain.Group, error) SetChannelGains(ctx context.Context, id, serverID, channel string) (domain.Group, error)
SetChannelLosses(ctx context.Context, id, serverID, channel string) (domain.Group, error) SetChannelLosses(ctx context.Context, id, serverID, channel string) (domain.Group, error)
SetInternals(ctx context.Context, id, serverID string, internals bool) (domain.Group, error)
SetBarbarians(ctx context.Context, id, serverID string, barbarians bool) (domain.Group, error)
List(ctx context.Context, params domain.ListGroupsParams) ([]domain.Group, error) List(ctx context.Context, params domain.ListGroupsParams) ([]domain.Group, error)
Delete(ctx context.Context, id, serverID string) error Delete(ctx context.Context, id, serverID string) error
} }

View File

@ -61,6 +61,18 @@ func (c *groupCommand) create(s *discordgo.Session) error {
Type: discordgo.ApplicationCommandOptionString, Type: discordgo.ApplicationCommandOptionString,
Required: true, Required: true,
}, },
{
Name: "internals",
Description: "Show conquers in the same group",
Type: discordgo.ApplicationCommandOptionBoolean,
Required: true,
},
{
Name: "barbarians",
Description: "Show barbarian conquers",
Type: discordgo.ApplicationCommandOptionBoolean,
Required: true,
},
{ {
Name: "channel-gains", Name: "channel-gains",
Description: "Specifies on which channel notifications of gained villages will appear", Description: "Specifies on which channel notifications of gained villages will appear",
@ -135,6 +147,44 @@ func (c *groupCommand) create(s *discordgo.Session) error {
}, },
}, },
}, },
{
Name: "internals",
Description: "Enables/disables notifications of internal conquers",
Type: discordgo.ApplicationCommandOptionSubCommand,
Options: []*discordgo.ApplicationCommandOption{
{
Name: "group",
Description: "Group ID",
Type: discordgo.ApplicationCommandOptionString,
Required: true,
},
{
Name: "internals",
Description: "Show conquers in the same group",
Type: discordgo.ApplicationCommandOptionBoolean,
Required: true,
},
},
},
{
Name: "barbarians",
Description: "Enables/disables notifications of barbarian conquers",
Type: discordgo.ApplicationCommandOptionSubCommand,
Options: []*discordgo.ApplicationCommandOption{
{
Name: "group",
Description: "Group ID",
Type: discordgo.ApplicationCommandOptionString,
Required: true,
},
{
Name: "barbarians",
Description: "Show barbarian conquers",
Type: discordgo.ApplicationCommandOptionBoolean,
Required: true,
},
},
},
}, },
}, },
{ {
@ -243,10 +293,9 @@ func (c *groupCommand) handleCreate(s *discordgo.Session, i *discordgo.Interacti
server := "" server := ""
channelGains := "" channelGains := ""
channelLosses := "" channelLosses := ""
internals := false
barbarians := false
for _, opt := range i.ApplicationCommandData().Options[0].Options { for _, opt := range i.ApplicationCommandData().Options[0].Options {
if opt == nil {
continue
}
switch opt.Name { switch opt.Name {
case "version": case "version":
version = opt.StringValue() version = opt.StringValue()
@ -256,6 +305,10 @@ func (c *groupCommand) handleCreate(s *discordgo.Session, i *discordgo.Interacti
channelGains = opt.ChannelValue(s).ID channelGains = opt.ChannelValue(s).ID
case "channel-losses": case "channel-losses":
channelLosses = opt.ChannelValue(s).ID channelLosses = opt.ChannelValue(s).ID
case "internals":
internals = opt.BoolValue()
case "barbarians":
barbarians = opt.BoolValue()
} }
} }
@ -265,6 +318,8 @@ func (c *groupCommand) handleCreate(s *discordgo.Session, i *discordgo.Interacti
server, server,
channelGains, channelGains,
channelLosses, channelLosses,
barbarians,
internals,
) )
if err != nil { if err != nil {
_ = s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{ _ = s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
@ -334,6 +389,12 @@ func (c *groupCommand) handleSet(s *discordgo.Session, i *discordgo.InteractionC
case "channel-losses": case "channel-losses":
c.handleSetChannelLosses(s, i) c.handleSetChannelLosses(s, i)
return return
case "internals":
c.handleSetInternals(s, i)
return
case "barbarians":
c.handleSetBarbarians(s, i)
return
default: default:
} }
} }
@ -410,6 +471,78 @@ func (c *groupCommand) handleSetChannelLosses(s *discordgo.Session, i *discordgo
}) })
} }
func (c *groupCommand) handleSetInternals(s *discordgo.Session, i *discordgo.InteractionCreate) {
ctx := context.Background()
group := ""
internals := false
for _, opt := range i.ApplicationCommandData().Options[0].Options[0].Options {
if opt == nil {
continue
}
switch opt.Name {
case "group":
group = opt.StringValue()
case "internals":
internals = opt.BoolValue()
}
}
_, err := c.groupSvc.SetInternals(ctx, group, i.GuildID, internals)
if err != nil {
_ = s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
Type: discordgo.InteractionResponseChannelMessageWithSource,
Data: &discordgo.InteractionResponseData{
Content: messageFromError(err),
},
})
return
}
_ = s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
Type: discordgo.InteractionResponseChannelMessageWithSource,
Data: &discordgo.InteractionResponseData{
Content: "group has been successfully updated",
},
})
}
func (c *groupCommand) handleSetBarbarians(s *discordgo.Session, i *discordgo.InteractionCreate) {
ctx := context.Background()
group := ""
barbarians := false
for _, opt := range i.ApplicationCommandData().Options[0].Options[0].Options {
if opt == nil {
continue
}
switch opt.Name {
case "group":
group = opt.StringValue()
case "barbarians":
barbarians = opt.BoolValue()
}
}
_, err := c.groupSvc.SetBarbarians(ctx, group, i.GuildID, barbarians)
if err != nil {
_ = s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
Type: discordgo.InteractionResponseChannelMessageWithSource,
Data: &discordgo.InteractionResponseData{
Content: messageFromError(err),
},
})
return
}
_ = s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
Type: discordgo.InteractionResponseChannelMessageWithSource,
Data: &discordgo.InteractionResponseData{
Content: "group has been successfully updated",
},
})
}
func (c *groupCommand) handleUnset(s *discordgo.Session, i *discordgo.InteractionCreate) { func (c *groupCommand) handleUnset(s *discordgo.Session, i *discordgo.InteractionCreate) {
switch i.ApplicationCommandData().Options[0].Options[0].Name { switch i.ApplicationCommandData().Options[0].Options[0].Name {
case "channel-gains": case "channel-gains":
@ -491,7 +624,7 @@ func (c *groupCommand) handleDelete(s *discordgo.Session, i *discordgo.Interacti
} }
func buildGroupListDescription(groups []domain.Group) string { func buildGroupListDescription(groups []domain.Group) string {
description := "**ID** - **Server** - **Channel gains** - **Channel losses**" description := "**ID** - **Server** - **Channel gains** - **Channel losses** - **Internals** - **Barbarians**"
for i, g := range groups { for i, g := range groups {
channelGains := "Not set" channelGains := "Not set"
if g.ChannelGains != "" { if g.ChannelGains != "" {
@ -502,12 +635,14 @@ func buildGroupListDescription(groups []domain.Group) string {
channelLosses = "<#" + g.ChannelLosses + ">" channelLosses = "<#" + g.ChannelLosses + ">"
} }
description += fmt.Sprintf( description += fmt.Sprintf(
"\n%d. %s - %s - %s - %s", "\n%d. %s - %s - %s - %s - %s - %s",
i+1, i+1,
g.ID, g.ID,
g.ServerKey, g.ServerKey,
channelGains, channelGains,
channelLosses, channelLosses,
boolToEmoji(g.Internals),
boolToEmoji(g.Barbarians),
) )
} }
return description return description

View File

@ -30,3 +30,10 @@ func buildLink(text string, url string) string {
} }
return fmt.Sprintf("[`%s`](%s)", text, url) return fmt.Sprintf("[`%s`](%s)", text, url)
} }
func boolToEmoji(val bool) string {
if val {
return ":white_check_mark:"
}
return ":x:"
}

View File

@ -4,3 +4,8 @@ type NullString struct {
String string String string
Valid bool // Valid is true if String is not NULL Valid bool // Valid is true if String is not NULL
} }
type NullBool struct {
Bool bool
Valid bool // Valid is true if Bool is not NULL
}

View File

@ -10,6 +10,8 @@ type Group struct {
ServerID string // Discord server ID ServerID string // Discord server ID
ChannelGains string ChannelGains string
ChannelLosses string ChannelLosses string
Internals bool // Show conquers in the same group
Barbarians bool // Show barbarian conquers
ServerKey string // Tribal Wars server key ServerKey string // Tribal Wars server key
VersionCode string VersionCode string
CreatedAt time.Time CreatedAt time.Time
@ -21,9 +23,14 @@ type CreateGroupParams struct {
versionCode string versionCode string
channelGains string channelGains string
channelLosses string channelLosses string
barbarians bool
internals bool
} }
func NewCreateGroupParams(serverID, versionCode, serverKey, channelGains, channelLosses string) (CreateGroupParams, error) { func NewCreateGroupParams(
serverID, versionCode, serverKey, channelGains, channelLosses string,
barbarians, internals bool,
) (CreateGroupParams, error) {
if serverID == "" { if serverID == "" {
return CreateGroupParams{}, ValidationError{ return CreateGroupParams{}, ValidationError{
Field: "ServerID", Field: "ServerID",
@ -51,6 +58,8 @@ func NewCreateGroupParams(serverID, versionCode, serverKey, channelGains, channe
versionCode: versionCode, versionCode: versionCode,
channelGains: channelGains, channelGains: channelGains,
channelLosses: channelLosses, channelLosses: channelLosses,
barbarians: barbarians,
internals: internals,
}, nil }, nil
} }
@ -74,14 +83,26 @@ func (c CreateGroupParams) ChannelLosses() string {
return c.channelLosses return c.channelLosses
} }
func (c CreateGroupParams) Barbarians() bool {
return c.barbarians
}
func (c CreateGroupParams) Internals() bool {
return c.internals
}
type UpdateGroupParams struct { type UpdateGroupParams struct {
ChannelGains NullString ChannelGains NullString
ChannelLosses NullString ChannelLosses NullString
Internals NullBool
Barbarians NullBool
} }
func (u UpdateGroupParams) IsZero() bool { func (u UpdateGroupParams) IsZero() bool {
return !u.ChannelGains.Valid && return !u.ChannelGains.Valid &&
!u.ChannelLosses.Valid !u.ChannelLosses.Valid &&
!u.Internals.Valid &&
!u.Barbarians.Valid
} }
type ListGroupsParams struct { type ListGroupsParams struct {

View File

@ -19,6 +19,8 @@ func TestNewCreateGroupParams(t *testing.T) {
serverKey string serverKey string
channelGains string channelGains string
channelLosses string channelLosses string
barbarians bool
internals bool
err error err error
}{ }{
{ {
@ -28,6 +30,8 @@ func TestNewCreateGroupParams(t *testing.T) {
serverKey: "en113", serverKey: "en113",
channelGains: "1234", channelGains: "1234",
channelLosses: "1234", channelLosses: "1234",
barbarians: true,
internals: true,
err: nil, err: nil,
}, },
{ {
@ -72,6 +76,8 @@ func TestNewCreateGroupParams(t *testing.T) {
tt.serverKey, tt.serverKey,
tt.channelGains, tt.channelGains,
tt.channelLosses, tt.channelLosses,
tt.barbarians,
tt.internals,
) )
if tt.err != nil { if tt.err != nil {
assert.ErrorIs(t, err, tt.err) assert.ErrorIs(t, err, tt.err)
@ -84,6 +90,8 @@ func TestNewCreateGroupParams(t *testing.T) {
assert.Equal(t, tt.versionCode, res.VersionCode()) assert.Equal(t, tt.versionCode, res.VersionCode())
assert.Equal(t, tt.channelGains, res.ChannelGains()) assert.Equal(t, tt.channelGains, res.ChannelGains())
assert.Equal(t, tt.channelLosses, res.ChannelLosses()) assert.Equal(t, tt.channelLosses, res.ChannelLosses())
assert.Equal(t, tt.barbarians, res.Barbarians())
assert.Equal(t, tt.internals, res.Internals())
}) })
} }
} }
@ -107,6 +115,14 @@ func TestUpdateGroupParams_IsZero(t *testing.T) {
String: "123", String: "123",
Valid: true, Valid: true,
}, },
Barbarians: domain.NullBool{
Bool: false,
Valid: true,
},
Internals: domain.NullBool{
Bool: false,
Valid: true,
},
}, },
output: false, output: false,
}, },
@ -130,6 +146,26 @@ func TestUpdateGroupParams_IsZero(t *testing.T) {
}, },
output: false, output: false,
}, },
{
name: "OK: Barbarians",
params: domain.UpdateGroupParams{
Barbarians: domain.NullBool{
Bool: false,
Valid: true,
},
},
output: false,
},
{
name: "OK: Internals",
params: domain.UpdateGroupParams{
Internals: domain.NullBool{
Bool: false,
Valid: true,
},
},
output: false,
},
{ {
name: "OK: empty struct", name: "OK: empty struct",
params: domain.UpdateGroupParams{}, params: domain.UpdateGroupParams{},

View File

@ -85,6 +85,32 @@ func (g *Group) SetChannelLosses(ctx context.Context, id, serverID, channel stri
return group, nil return group, nil
} }
func (g *Group) SetInternals(ctx context.Context, id, serverID string, internals bool) (domain.Group, error) {
group, err := g.repo.Update(ctx, id, serverID, domain.UpdateGroupParams{
Internals: domain.NullBool{
Bool: internals,
Valid: true,
},
})
if err != nil {
return domain.Group{}, fmt.Errorf("GroupRepository.Update: %w", err)
}
return group, nil
}
func (g *Group) SetBarbarians(ctx context.Context, id, serverID string, barbarians bool) (domain.Group, error) {
group, err := g.repo.Update(ctx, id, serverID, domain.UpdateGroupParams{
Barbarians: domain.NullBool{
Bool: barbarians,
Valid: true,
},
})
if err != nil {
return domain.Group{}, fmt.Errorf("GroupRepository.Update: %w", err)
}
return group, nil
}
func (g *Group) List(ctx context.Context, params domain.ListGroupsParams) ([]domain.Group, error) { func (g *Group) List(ctx context.Context, params domain.ListGroupsParams) ([]domain.Group, error) {
groups, err := g.repo.List(ctx, params) groups, err := g.repo.List(ctx, params)
if err != nil { if err != nil {

View File

@ -24,6 +24,8 @@ func TestGroup_Create(t *testing.T) {
"en113", "en113",
"1234", "1234",
"1235", "1235",
true,
true,
) )
require.NoError(t, err) require.NoError(t, err)
@ -37,6 +39,8 @@ func TestGroup_Create(t *testing.T) {
ServerID: p.ServerID(), ServerID: p.ServerID(),
ChannelGains: p.ChannelGains(), ChannelGains: p.ChannelGains(),
ChannelLosses: p.ChannelLosses(), ChannelLosses: p.ChannelLosses(),
Barbarians: p.Barbarians(),
Internals: p.Internals(),
ServerKey: p.ServerKey(), ServerKey: p.ServerKey(),
VersionCode: p.VersionCode(), VersionCode: p.VersionCode(),
CreatedAt: time.Now(), CreatedAt: time.Now(),
@ -61,6 +65,8 @@ func TestGroup_Create(t *testing.T) {
assert.Equal(t, params.VersionCode(), g.VersionCode) assert.Equal(t, params.VersionCode(), g.VersionCode)
assert.Equal(t, params.ChannelGains(), g.ChannelGains) assert.Equal(t, params.ChannelGains(), g.ChannelGains)
assert.Equal(t, params.ChannelLosses(), g.ChannelLosses) assert.Equal(t, params.ChannelLosses(), g.ChannelLosses)
assert.Equal(t, params.Barbarians(), g.Barbarians)
assert.Equal(t, params.Internals(), g.Barbarians)
assert.NotEmpty(t, g.CreatedAt) assert.NotEmpty(t, g.CreatedAt)
}) })

View File

@ -202,16 +202,12 @@ func (m *Monitor) Execute(ctx context.Context) ([]domain.EnnoblementNotification
//nolint:prealloc //nolint:prealloc
var notifications []domain.EnnoblementNotification var notifications []domain.EnnoblementNotification
for _, r := range res { for _, g := range groups {
for _, g := range groups { for _, r := range res {
if g.ServerKey != r.serverKey || g.VersionCode != r.versionCode { if g.ServerKey != r.serverKey || g.VersionCode != r.versionCode {
continue continue
} }
if g.ChannelGains == "" && g.ChannelLosses == "" {
continue
}
ns, err := m.executeGroup(ctx, g, r.ennoblements) ns, err := m.executeGroup(ctx, g, r.ennoblements)
if err != nil { if err != nil {
// TODO: log this error // TODO: log this error
@ -237,11 +233,7 @@ func (m *Monitor) executeGroup(
//nolint:prealloc //nolint:prealloc
var notifications []domain.EnnoblementNotification var notifications []domain.EnnoblementNotification
for _, e := range ennoblements { for _, e := range ennoblements {
if isInternal(e, monitors) { if canSendEnnoblementNotificationTypeGain(g, e, monitors) {
continue
}
if g.ChannelGains != "" && isGain(e, monitors) {
notifications = append(notifications, domain.EnnoblementNotification{ notifications = append(notifications, domain.EnnoblementNotification{
Type: domain.EnnoblementNotificationTypeGain, Type: domain.EnnoblementNotificationTypeGain,
ServerID: g.ServerID, ServerID: g.ServerID,
@ -250,7 +242,7 @@ func (m *Monitor) executeGroup(
}) })
} }
if g.ChannelLosses != "" && isLoss(e, monitors) { if canSendEnnoblementNotificationTypeLoss(g, e, monitors) {
notifications = append(notifications, domain.EnnoblementNotification{ notifications = append(notifications, domain.EnnoblementNotification{
Type: domain.EnnoblementNotificationTypeLoss, Type: domain.EnnoblementNotificationTypeLoss,
ServerID: g.ServerID, ServerID: g.ServerID,
@ -286,10 +278,6 @@ func (m *Monitor) fetchEnnoblements(ctx context.Context, groups []domain.Group)
skip := make(map[string]struct{}, len(ennoblementsSince)) skip := make(map[string]struct{}, len(ennoblementsSince))
for _, g := range groups { for _, g := range groups {
if g.ChannelGains == "" && g.ChannelLosses == "" {
continue
}
key := g.VersionCode + ":" + g.ServerKey key := g.VersionCode + ":" + g.ServerKey
if _, ok := skip[key]; ok { if _, ok := skip[key]; ok {
@ -356,6 +344,34 @@ func (m *Monitor) fetchEnnoblements(ctx context.Context, groups []domain.Group)
return results, nil return results, nil
} }
func canSendEnnoblementNotificationTypeGain(g domain.Group, e twhelp.Ennoblement, monitors []domain.Monitor) bool {
if g.ChannelGains == "" {
return false
}
if !g.Barbarians && isBarbarian(e) {
return false
}
if !g.Internals && isInternal(e, monitors) {
return false
}
return isGain(e, monitors)
}
func canSendEnnoblementNotificationTypeLoss(g domain.Group, e twhelp.Ennoblement, monitors []domain.Monitor) bool {
if g.ChannelLosses == "" {
return false
}
if isInternal(e, monitors) {
return false
}
return isLoss(e, monitors)
}
func isInternal(e twhelp.Ennoblement, monitors []domain.Monitor) bool { func isInternal(e twhelp.Ennoblement, monitors []domain.Monitor) bool {
var n, o bool var n, o bool
for _, m := range monitors { for _, m := range monitors {
@ -369,6 +385,10 @@ func isInternal(e twhelp.Ennoblement, monitors []domain.Monitor) bool {
return n && o return n && o
} }
func isBarbarian(e twhelp.Ennoblement) bool {
return !e.OldOwner.Valid
}
func isGain(e twhelp.Ennoblement, monitors []domain.Monitor) bool { func isGain(e twhelp.Ennoblement, monitors []domain.Monitor) bool {
var n bool var n bool
for _, m := range monitors { for _, m := range monitors {
@ -377,7 +397,7 @@ func isGain(e twhelp.Ennoblement, monitors []domain.Monitor) bool {
break break
} }
} }
return n && e.NewOwner.Player.Tribe.Tribe.ID != e.OldOwner.Player.Tribe.Tribe.ID return n && e.NewOwner.Player.ID != e.OldOwner.Player.ID
} }
func isLoss(e twhelp.Ennoblement, monitors []domain.Monitor) bool { func isLoss(e twhelp.Ennoblement, monitors []domain.Monitor) bool {
@ -388,7 +408,7 @@ func isLoss(e twhelp.Ennoblement, monitors []domain.Monitor) bool {
break break
} }
} }
return o && e.NewOwner.Player.Tribe.Tribe.ID != e.OldOwner.Player.Tribe.Tribe.ID return o && e.NewOwner.Player.ID != e.OldOwner.Player.ID
} }
func ennoblementToDomainModel(e twhelp.Ennoblement) domain.Ennoblement { func ennoblementToDomainModel(e twhelp.Ennoblement) domain.Ennoblement {

View File

@ -310,6 +310,23 @@ func TestMonitor_Execute(t *testing.T) {
ProfileURL: uuid.NewString(), ProfileURL: uuid.NewString(),
}, },
}, },
"de:de200": {
{
ID: 300,
FullName: uuid.NewString(),
ProfileURL: uuid.NewString(),
},
{
ID: 301,
FullName: uuid.NewString(),
ProfileURL: uuid.NewString(),
},
{
ID: 302,
FullName: uuid.NewString(),
ProfileURL: uuid.NewString(),
},
},
} }
tribes := map[string][]twhelp.TribeMeta{ tribes := map[string][]twhelp.TribeMeta{
"pl:pl181": { "pl:pl181": {
@ -354,6 +371,20 @@ func TestMonitor_Execute(t *testing.T) {
ProfileURL: uuid.NewString(), ProfileURL: uuid.NewString(),
}, },
}, },
"de:de200": {
{
ID: 300,
Name: uuid.NewString(),
Tag: uuid.NewString(),
ProfileURL: uuid.NewString(),
},
{
ID: 301,
Name: uuid.NewString(),
Tag: uuid.NewString(),
ProfileURL: uuid.NewString(),
},
},
} }
players := map[string][]twhelp.PlayerMeta{ players := map[string][]twhelp.PlayerMeta{
"pl:pl181": { "pl:pl181": {
@ -428,6 +459,35 @@ func TestMonitor_Execute(t *testing.T) {
}, },
}, },
}, },
"de:de200": {
{
ID: 300,
Name: uuid.NewString(),
ProfileURL: uuid.NewString(),
Tribe: twhelp.NullTribeMeta{
Tribe: tribes["de:de200"][0],
Valid: true,
},
},
{
ID: 301,
Name: uuid.NewString(),
ProfileURL: uuid.NewString(),
Tribe: twhelp.NullTribeMeta{
Tribe: tribes["de:de200"][0],
Valid: true,
},
},
{
ID: 302,
Name: uuid.NewString(),
ProfileURL: uuid.NewString(),
Tribe: twhelp.NullTribeMeta{
Tribe: tribes["de:de200"][1],
Valid: true,
},
},
},
} }
ennoblements := map[string][]twhelp.Ennoblement{ ennoblements := map[string][]twhelp.Ennoblement{
"pl:pl181": { "pl:pl181": {
@ -458,7 +518,7 @@ func TestMonitor_Execute(t *testing.T) {
CreatedAt: time.Now().Add(-4 * time.Minute), CreatedAt: time.Now().Add(-4 * time.Minute),
}, },
{ {
ID: 3, // internal conquer, should be skipped ID: 3, // internal, should be skipped (internals disabled)
Village: villages["pl:pl181"][1], Village: villages["pl:pl181"][1],
NewOwner: twhelp.NullPlayerMeta{ NewOwner: twhelp.NullPlayerMeta{
Player: players["pl:pl181"][0], Player: players["pl:pl181"][0],
@ -471,7 +531,7 @@ func TestMonitor_Execute(t *testing.T) {
CreatedAt: time.Now().Add(-3 * time.Minute), CreatedAt: time.Now().Add(-3 * time.Minute),
}, },
{ {
ID: 4, // barbarian ID: 4, // barbarian, shouldn't be skipped (barbarians enabled)
Village: villages["pl:pl181"][2], Village: villages["pl:pl181"][2],
NewOwner: twhelp.NullPlayerMeta{ NewOwner: twhelp.NullPlayerMeta{
Player: players["pl:pl181"][0], Player: players["pl:pl181"][0],
@ -554,6 +614,44 @@ func TestMonitor_Execute(t *testing.T) {
CreatedAt: time.Now().Add(-5 * time.Minute), CreatedAt: time.Now().Add(-5 * time.Minute),
}, },
}, },
"de:de200": {
{
ID: 300, // barbarian, should be skipped (barbarians disabled)
Village: villages["de:de200"][0],
NewOwner: twhelp.NullPlayerMeta{
Player: players["de:de200"][0],
Valid: true,
},
OldOwner: twhelp.NullPlayerMeta{},
CreatedAt: time.Now().Add(-5 * time.Minute),
},
{
ID: 301, // internal, shouldn't be skipped (internals enabled)
Village: villages["de:de200"][1],
NewOwner: twhelp.NullPlayerMeta{
Player: players["de:de200"][0],
Valid: true,
},
OldOwner: twhelp.NullPlayerMeta{
Player: players["de:de200"][1],
Valid: true,
},
CreatedAt: time.Now().Add(-5 * time.Minute),
},
{
ID: 302, // internal, shouldn't be skipped (internals enabled)
Village: villages["de:de200"][2],
NewOwner: twhelp.NullPlayerMeta{
Player: players["de:de200"][0],
Valid: true,
},
OldOwner: twhelp.NullPlayerMeta{
Player: players["de:de200"][2],
Valid: true,
},
CreatedAt: time.Now().Add(-5 * time.Minute),
},
},
} }
client.ListEnnoblementsCalls( client.ListEnnoblementsCalls(
func( func(
@ -585,6 +683,7 @@ func TestMonitor_Execute(t *testing.T) {
ServerID: uuid.NewString(), ServerID: uuid.NewString(),
ChannelGains: uuid.NewString(), ChannelGains: uuid.NewString(),
ChannelLosses: "", ChannelLosses: "",
Barbarians: true,
ServerKey: "pl181", ServerKey: "pl181",
VersionCode: "pl", VersionCode: "pl",
CreatedAt: time.Now(), CreatedAt: time.Now(),
@ -612,10 +711,22 @@ func TestMonitor_Execute(t *testing.T) {
ServerID: uuid.NewString(), ServerID: uuid.NewString(),
ChannelGains: uuid.NewString(), ChannelGains: uuid.NewString(),
ChannelLosses: uuid.NewString(), ChannelLosses: uuid.NewString(),
Barbarians: true,
ServerKey: "pl180", ServerKey: "pl180",
VersionCode: "pl", VersionCode: "pl",
CreatedAt: time.Now(), CreatedAt: time.Now(),
}, },
{
ID: uuid.NewString(),
ServerID: uuid.NewString(),
ChannelGains: uuid.NewString(),
ChannelLosses: uuid.NewString(),
Barbarians: false,
Internals: true,
ServerKey: "de200",
VersionCode: "de",
CreatedAt: time.Now(),
},
} }
groupSvc.ListReturns(groups, nil) groupSvc.ListReturns(groups, nil)
@ -659,6 +770,20 @@ func TestMonitor_Execute(t *testing.T) {
CreatedAt: time.Now(), CreatedAt: time.Now(),
}, },
}, },
groups[5].ID: {
{
ID: uuid.NewString(),
TribeID: tribes["de:de200"][0].ID,
GroupID: groups[5].ID,
CreatedAt: time.Now(),
},
{
ID: uuid.NewString(),
TribeID: tribes["de:de200"][1].ID,
GroupID: groups[5].ID,
CreatedAt: time.Now(),
},
},
} }
repo.ListCalls(func(ctx context.Context, groupID string) ([]domain.Monitor, error) { repo.ListCalls(func(ctx context.Context, groupID string) ([]domain.Monitor, error) {
return monitors[groupID], nil return monitors[groupID], nil
@ -692,6 +817,18 @@ func TestMonitor_Execute(t *testing.T) {
ChannelID: groups[3].ChannelGains, ChannelID: groups[3].ChannelGains,
Ennoblement: ennoblementToDomainModel(ennoblements["en:en130"][2]), Ennoblement: ennoblementToDomainModel(ennoblements["en:en130"][2]),
}, },
{
Type: domain.EnnoblementNotificationTypeGain,
ServerID: groups[5].ServerID,
ChannelID: groups[5].ChannelGains,
Ennoblement: ennoblementToDomainModel(ennoblements["de:de200"][1]),
},
{
Type: domain.EnnoblementNotificationTypeGain,
ServerID: groups[5].ServerID,
ChannelID: groups[5].ChannelGains,
Ennoblement: ennoblementToDomainModel(ennoblements["de:de200"][2]),
},
} }
assert.Len(t, notifications, len(expectedNotifications)) assert.Len(t, notifications, len(expectedNotifications))
for _, n := range expectedNotifications { for _, n := range expectedNotifications {