feat: add a new command - monitor list
All checks were successful
continuous-integration/drone/pr Build is passing
All checks were successful
continuous-integration/drone/pr Build is passing
This commit is contained in:
parent
de19857b34
commit
6f20736671
1
go.mod
1
go.mod
|
@ -5,6 +5,7 @@ go 1.19
|
||||||
require (
|
require (
|
||||||
github.com/bwmarrin/discordgo v0.26.1
|
github.com/bwmarrin/discordgo v0.26.1
|
||||||
github.com/cenkalti/backoff/v4 v4.1.3
|
github.com/cenkalti/backoff/v4 v4.1.3
|
||||||
|
github.com/google/go-cmp v0.5.9
|
||||||
github.com/google/uuid v1.3.0
|
github.com/google/uuid v1.3.0
|
||||||
github.com/kelseyhightower/envconfig v1.4.0
|
github.com/kelseyhightower/envconfig v1.4.0
|
||||||
github.com/ory/dockertest/v3 v3.9.1
|
github.com/ory/dockertest/v3 v3.9.1
|
||||||
|
|
3
go.sum
3
go.sum
|
@ -49,7 +49,8 @@ github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw
|
||||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg=
|
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||||
|
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
|
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
|
||||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
|
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
|
||||||
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
||||||
|
|
|
@ -20,6 +20,7 @@ type GroupService interface {
|
||||||
|
|
||||||
type MonitorService interface {
|
type MonitorService interface {
|
||||||
Create(ctx context.Context, groupID, serverID, tribeTag string) (domain.Monitor, error)
|
Create(ctx context.Context, groupID, serverID, tribeTag string) (domain.Monitor, error)
|
||||||
|
List(ctx context.Context, groupID, serverID string) ([]domain.MonitorWithTribe, error)
|
||||||
Execute(ctx context.Context) ([]domain.EnnoblementNotification, error)
|
Execute(ctx context.Context) ([]domain.EnnoblementNotification, error)
|
||||||
Delete(ctx context.Context, id, serverID string) error
|
Delete(ctx context.Context, id, serverID string) error
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,9 @@ package discord
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"gitea.dwysokinski.me/twhelp/dcbot/internal/domain"
|
||||||
"github.com/bwmarrin/discordgo"
|
"github.com/bwmarrin/discordgo"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -57,6 +59,19 @@ func (c *monitorCommand) create(s *discordgo.Session) error {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Name: "list",
|
||||||
|
Description: "Lists all monitors associated with a particular group",
|
||||||
|
Type: discordgo.ApplicationCommandOptionSubCommand,
|
||||||
|
Options: []*discordgo.ApplicationCommandOption{
|
||||||
|
{
|
||||||
|
Name: "group",
|
||||||
|
Description: "Group ID",
|
||||||
|
Type: discordgo.ApplicationCommandOptionString,
|
||||||
|
Required: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
Name: "delete",
|
Name: "delete",
|
||||||
Description: "Deletes a monitor",
|
Description: "Deletes a monitor",
|
||||||
|
@ -90,6 +105,9 @@ func (c *monitorCommand) handle(s *discordgo.Session, i *discordgo.InteractionCr
|
||||||
case "create":
|
case "create":
|
||||||
c.handleCreate(s, i)
|
c.handleCreate(s, i)
|
||||||
return
|
return
|
||||||
|
case "list":
|
||||||
|
c.handleList(s, i)
|
||||||
|
return
|
||||||
case "delete":
|
case "delete":
|
||||||
c.handleDelete(s, i)
|
c.handleDelete(s, i)
|
||||||
return
|
return
|
||||||
|
@ -133,6 +151,36 @@ func (c *monitorCommand) handleCreate(s *discordgo.Session, i *discordgo.Interac
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *monitorCommand) handleList(s *discordgo.Session, i *discordgo.InteractionCreate) {
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
group := i.ApplicationCommandData().Options[0].Options[0].StringValue()
|
||||||
|
monitors, err := c.svc.List(ctx, group, i.GuildID)
|
||||||
|
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{
|
||||||
|
Embeds: []*discordgo.MessageEmbed{
|
||||||
|
{
|
||||||
|
Type: discordgo.EmbedTypeRich,
|
||||||
|
Title: "Monitor list",
|
||||||
|
Description: buildMonitorListDescription(monitors),
|
||||||
|
Timestamp: formatTimestamp(time.Now()),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func (c *monitorCommand) handleDelete(s *discordgo.Session, i *discordgo.InteractionCreate) {
|
func (c *monitorCommand) handleDelete(s *discordgo.Session, i *discordgo.InteractionCreate) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
|
||||||
|
@ -154,3 +202,11 @@ func (c *monitorCommand) handleDelete(s *discordgo.Session, i *discordgo.Interac
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func buildMonitorListDescription(monitors []domain.MonitorWithTribe) string {
|
||||||
|
description := "**ID** - **Tribe**"
|
||||||
|
for i, m := range monitors {
|
||||||
|
description += fmt.Sprintf("\n%d. %s - %s", i+1, m.ID, buildLink(m.Tribe.Tag, m.Tribe.ProfileURL))
|
||||||
|
}
|
||||||
|
return description
|
||||||
|
}
|
||||||
|
|
|
@ -16,6 +16,11 @@ type Monitor struct {
|
||||||
CreatedAt time.Time
|
CreatedAt time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type MonitorWithTribe struct {
|
||||||
|
Monitor
|
||||||
|
Tribe TribeMeta
|
||||||
|
}
|
||||||
|
|
||||||
type CreateMonitorParams struct {
|
type CreateMonitorParams struct {
|
||||||
tribeID int64
|
tribeID int64
|
||||||
groupID string
|
groupID string
|
||||||
|
|
|
@ -103,6 +103,74 @@ func (m *Monitor) Create(ctx context.Context, groupID, serverID, tribeTag string
|
||||||
return monitor, nil
|
return monitor, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type getTribeResult struct {
|
||||||
|
monitor domain.Monitor
|
||||||
|
tribe twhelp.Tribe
|
||||||
|
err error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Monitor) List(ctx context.Context, groupID, serverID string) ([]domain.MonitorWithTribe, error) {
|
||||||
|
group, err := m.groupSvc.Get(ctx, groupID, serverID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("GroupService.Get: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
monitors, err := m.repo.List(ctx, group.ID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("MonitorRepository.Delete: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
ch := make(chan getTribeResult)
|
||||||
|
|
||||||
|
for _, monitor := range monitors {
|
||||||
|
wg.Add(1)
|
||||||
|
go func(monitor domain.Monitor) {
|
||||||
|
res := getTribeResult{
|
||||||
|
monitor: monitor,
|
||||||
|
}
|
||||||
|
res.tribe, res.err = m.client.GetTribeByID(
|
||||||
|
ctx,
|
||||||
|
group.VersionCode,
|
||||||
|
group.ServerKey,
|
||||||
|
monitor.TribeID,
|
||||||
|
)
|
||||||
|
ch <- res
|
||||||
|
}(monitor)
|
||||||
|
}
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
wg.Wait()
|
||||||
|
close(ch)
|
||||||
|
}()
|
||||||
|
|
||||||
|
var firstErr error
|
||||||
|
results := make([]domain.MonitorWithTribe, 0, len(monitors))
|
||||||
|
for res := range ch {
|
||||||
|
wg.Done()
|
||||||
|
|
||||||
|
if res.err != nil && firstErr == nil {
|
||||||
|
firstErr = fmt.Errorf("couldn't load tribe (monitorID=%s): %w", res.monitor.ID, res.err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
results = append(results, domain.MonitorWithTribe{
|
||||||
|
Monitor: res.monitor,
|
||||||
|
Tribe: domain.TribeMeta{
|
||||||
|
ID: res.tribe.ID,
|
||||||
|
Name: res.tribe.Name,
|
||||||
|
Tag: res.tribe.Tag,
|
||||||
|
ProfileURL: res.tribe.ProfileURL,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if firstErr != nil {
|
||||||
|
return nil, firstErr
|
||||||
|
}
|
||||||
|
|
||||||
|
return results, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (m *Monitor) Delete(ctx context.Context, id, serverID string) error {
|
func (m *Monitor) Delete(ctx context.Context, id, serverID string) error {
|
||||||
monitor, err := m.repo.Get(ctx, id)
|
monitor, err := m.repo.Get(ctx, id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -10,6 +10,7 @@ import (
|
||||||
"gitea.dwysokinski.me/twhelp/dcbot/internal/service"
|
"gitea.dwysokinski.me/twhelp/dcbot/internal/service"
|
||||||
"gitea.dwysokinski.me/twhelp/dcbot/internal/service/internal/mock"
|
"gitea.dwysokinski.me/twhelp/dcbot/internal/service/internal/mock"
|
||||||
"gitea.dwysokinski.me/twhelp/dcbot/internal/twhelp"
|
"gitea.dwysokinski.me/twhelp/dcbot/internal/twhelp"
|
||||||
|
"github.com/google/go-cmp/cmp"
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
@ -195,6 +196,71 @@ func TestMonitor_Create(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestMonitor_List(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
t.Run("OK", func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
groupID := uuid.NewString()
|
||||||
|
groupSvc := &mock.FakeGroupReader{}
|
||||||
|
groupSvc.GetCalls(func(ctx context.Context, groupID, serverID string) (domain.Group, error) {
|
||||||
|
return domain.Group{
|
||||||
|
ID: groupID,
|
||||||
|
ServerID: serverID,
|
||||||
|
ChannelGains: "",
|
||||||
|
ChannelLosses: "",
|
||||||
|
ServerKey: "pl151",
|
||||||
|
VersionCode: "pl",
|
||||||
|
CreatedAt: time.Now(),
|
||||||
|
}, nil
|
||||||
|
})
|
||||||
|
|
||||||
|
repo := &mock.FakeMonitorRepository{}
|
||||||
|
monitors := []domain.Monitor{
|
||||||
|
{
|
||||||
|
ID: uuid.NewString(),
|
||||||
|
TribeID: 124,
|
||||||
|
GroupID: groupID,
|
||||||
|
CreatedAt: time.Now(),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: uuid.NewString(),
|
||||||
|
TribeID: 125,
|
||||||
|
GroupID: groupID,
|
||||||
|
CreatedAt: time.Now(),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
repo.ListReturns(monitors, nil)
|
||||||
|
|
||||||
|
client := &mock.FakeTWHelpClient{}
|
||||||
|
client.GetTribeByIDCalls(func(ctx context.Context, _ string, _ string, id int64) (twhelp.Tribe, error) {
|
||||||
|
return twhelp.Tribe{
|
||||||
|
ID: id,
|
||||||
|
Tag: uuid.NewString(),
|
||||||
|
Name: uuid.NewString(),
|
||||||
|
ProfileURL: uuid.NewString(),
|
||||||
|
DeletedAt: time.Time{},
|
||||||
|
}, nil
|
||||||
|
})
|
||||||
|
|
||||||
|
res, err := service.NewMonitor(repo, groupSvc, client, 10).
|
||||||
|
List(context.Background(), groupID, uuid.NewString())
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Len(t, res, len(monitors))
|
||||||
|
for _, m1 := range monitors {
|
||||||
|
var exist bool
|
||||||
|
for _, m2 := range res {
|
||||||
|
if cmp.Equal(m1, m2.Monitor) && m1.TribeID == m2.Tribe.ID {
|
||||||
|
exist = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert.True(t, exist)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func TestMonitor_Execute(t *testing.T) {
|
func TestMonitor_Execute(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,7 @@ import (
|
||||||
type TWHelpClient interface {
|
type TWHelpClient interface {
|
||||||
ListVersions(ctx context.Context) ([]twhelp.Version, error)
|
ListVersions(ctx context.Context) ([]twhelp.Version, error)
|
||||||
GetServer(ctx context.Context, version, server string) (twhelp.Server, error)
|
GetServer(ctx context.Context, version, server string) (twhelp.Server, error)
|
||||||
|
GetTribeByID(ctx context.Context, version, server string, id int64) (twhelp.Tribe, error)
|
||||||
GetTribeByTag(ctx context.Context, version, server, tag string) (twhelp.Tribe, error)
|
GetTribeByTag(ctx context.Context, version, server, tag string) (twhelp.Tribe, error)
|
||||||
ListEnnoblements(
|
ListEnnoblements(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
|
|
|
@ -17,6 +17,7 @@ const (
|
||||||
|
|
||||||
endpointListVersions = "/api/v1/versions"
|
endpointListVersions = "/api/v1/versions"
|
||||||
endpointGetServer = "/api/v1/versions/%s/servers/%s"
|
endpointGetServer = "/api/v1/versions/%s/servers/%s"
|
||||||
|
endpointGetTribeByID = "/api/v1/versions/%s/servers/%s/tribes/%d"
|
||||||
endpointGetTribeByTag = "/api/v1/versions/%s/servers/%s/tribes/tag/%s"
|
endpointGetTribeByTag = "/api/v1/versions/%s/servers/%s/tribes/tag/%s"
|
||||||
endpointListEnnoblements = "/api/v1/versions/%s/servers/%s/ennoblements"
|
endpointListEnnoblements = "/api/v1/versions/%s/servers/%s/ennoblements"
|
||||||
)
|
)
|
||||||
|
@ -71,6 +72,14 @@ func (c *Client) GetServer(ctx context.Context, version, server string) (Server,
|
||||||
return resp.Data, nil
|
return resp.Data, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Client) GetTribeByID(ctx context.Context, version, server string, id int64) (Tribe, error) {
|
||||||
|
var resp getTribeResp
|
||||||
|
if err := c.getJSON(ctx, fmt.Sprintf(endpointGetTribeByID, version, server, id), &resp); err != nil {
|
||||||
|
return Tribe{}, err
|
||||||
|
}
|
||||||
|
return resp.Data, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Client) GetTribeByTag(ctx context.Context, version, server, tag string) (Tribe, error) {
|
func (c *Client) GetTribeByTag(ctx context.Context, version, server, tag string) (Tribe, error) {
|
||||||
var resp getTribeResp
|
var resp getTribeResp
|
||||||
if err := c.getJSON(ctx, fmt.Sprintf(endpointGetTribeByTag, version, server, tag), &resp); err != nil {
|
if err := c.getJSON(ctx, fmt.Sprintf(endpointGetTribeByTag, version, server, tag), &resp); err != nil {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user