feat: add a new command - /monitor delete (#23)
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #23
This commit is contained in:
parent
d983f5ae08
commit
db2026c6e4
|
@ -193,6 +193,9 @@ func TestGroup_Get(t *testing.T) {
|
||||||
t.Run("OK", func(t *testing.T) {
|
t.Run("OK", func(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
|
g, err := repo.Get(context.Background(), group.ID.String(), group.ServerID)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, group.ToDomain(), g)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("ERR: group not found (unknown ID)", func(t *testing.T) {
|
t.Run("ERR: group not found (unknown ID)", func(t *testing.T) {
|
||||||
|
@ -239,19 +242,30 @@ func TestGroup_Delete(t *testing.T) {
|
||||||
|
|
||||||
db := newDB(t)
|
db := newDB(t)
|
||||||
fixture := loadFixtures(t, db)
|
fixture := loadFixtures(t, db)
|
||||||
repo := bundb.NewGroup(db)
|
groupRepo := bundb.NewGroup(db)
|
||||||
|
monitorRepo := bundb.NewMonitor(db)
|
||||||
group := getGroupFromFixture(t, fixture, "group-1-server-1")
|
group := getGroupFromFixture(t, fixture, "group-1-server-1")
|
||||||
|
|
||||||
t.Run("OK", func(t *testing.T) {
|
t.Run("OK", func(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
assert.NoError(t, repo.Delete(context.Background(), group.ID.String(), group.ServerID))
|
beforeDelete, err := groupRepo.List(context.Background(), domain.ListGroupsParams{
|
||||||
|
ServerIDs: []string{group.ServerID},
|
||||||
groups, err := repo.List(context.Background(), domain.ListGroupsParams{
|
|
||||||
ServerIDs: []string{group.ID.String()},
|
|
||||||
})
|
})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Len(t, groups, 0)
|
|
||||||
|
assert.NoError(t, groupRepo.Delete(context.Background(), group.ID.String(), group.ServerID))
|
||||||
|
|
||||||
|
afterDelete, err := groupRepo.List(context.Background(), domain.ListGroupsParams{
|
||||||
|
ServerIDs: []string{group.ServerID},
|
||||||
|
})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Len(t, afterDelete, len(beforeDelete)-1)
|
||||||
|
|
||||||
|
// monitors should also be deleted
|
||||||
|
monitors, err := monitorRepo.List(context.Background(), group.ID.String())
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Len(t, monitors, 0)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("ERR: group not found", func(t *testing.T) {
|
t.Run("ERR: group not found", func(t *testing.T) {
|
||||||
|
@ -287,7 +301,7 @@ func TestGroup_Delete(t *testing.T) {
|
||||||
|
|
||||||
assert.ErrorIs(
|
assert.ErrorIs(
|
||||||
t,
|
t,
|
||||||
repo.Delete(context.Background(), tt.id, tt.serverID),
|
groupRepo.Delete(context.Background(), tt.id, tt.serverID),
|
||||||
domain.GroupNotFoundError{ID: tt.id},
|
domain.GroupNotFoundError{ID: tt.id},
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
|
@ -71,6 +71,47 @@ func (m *Monitor) List(ctx context.Context, groupID string) ([]domain.Monitor, e
|
||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *Monitor) Get(ctx context.Context, id string) (domain.Monitor, error) {
|
||||||
|
if _, err := uuid.Parse(id); err != nil {
|
||||||
|
return domain.Monitor{}, domain.MonitorNotFoundError{ID: id}
|
||||||
|
}
|
||||||
|
|
||||||
|
var monitor model.Monitor
|
||||||
|
|
||||||
|
err := m.db.NewSelect().
|
||||||
|
Model(&monitor).
|
||||||
|
Where("id = ?", id).
|
||||||
|
Scan(ctx)
|
||||||
|
if err != nil {
|
||||||
|
if errors.Is(err, sql.ErrNoRows) {
|
||||||
|
return domain.Monitor{}, domain.MonitorNotFoundError{ID: id}
|
||||||
|
}
|
||||||
|
return domain.Monitor{}, fmt.Errorf("couldn't select monitor from the db (id=%s): %w", id, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return monitor.ToDomain(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Monitor) Delete(ctx context.Context, id string) error {
|
||||||
|
if _, err := uuid.Parse(id); err != nil {
|
||||||
|
return domain.MonitorNotFoundError{ID: id}
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err := m.db.NewDelete().
|
||||||
|
Model(&model.Monitor{}).
|
||||||
|
Returning("NULL").
|
||||||
|
Where("id = ?", id).
|
||||||
|
Exec(ctx)
|
||||||
|
if err != nil && !errors.Is(err, sql.ErrNoRows) {
|
||||||
|
return fmt.Errorf("couldn't delete monitor (id=%s): %w", id, err)
|
||||||
|
}
|
||||||
|
if affected, _ := res.RowsAffected(); affected == 0 {
|
||||||
|
return domain.MonitorNotFoundError{ID: id}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func mapCreateMonitorError(err error, params domain.CreateMonitorParams) error {
|
func mapCreateMonitorError(err error, params domain.CreateMonitorParams) error {
|
||||||
var pgError pgdriver.Error
|
var pgError pgdriver.Error
|
||||||
if !errors.As(err, &pgError) {
|
if !errors.As(err, &pgError) {
|
||||||
|
|
|
@ -138,3 +138,111 @@ func TestMonitor_List(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestMonitor_Get(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
db := newDB(t)
|
||||||
|
fixture := loadFixtures(t, db)
|
||||||
|
repo := bundb.NewMonitor(db)
|
||||||
|
group := getGroupFromFixture(t, fixture, "group-1-server-1")
|
||||||
|
|
||||||
|
t.Run("OK", func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
monitors, err := repo.List(context.Background(), group.ID.String())
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Greater(t, len(monitors), 0)
|
||||||
|
|
||||||
|
m, err := repo.Get(context.Background(), monitors[0].ID)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, monitors[0], m)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("ERR: monitor not found", func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
id string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "ID - not UUID",
|
||||||
|
id: "test",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ID - random UUID",
|
||||||
|
id: uuid.NewString(),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
tt := tt
|
||||||
|
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
assert.ErrorIs(
|
||||||
|
t,
|
||||||
|
repo.Delete(context.Background(), tt.id),
|
||||||
|
domain.MonitorNotFoundError{ID: tt.id},
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMonitor_Delete(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
db := newDB(t)
|
||||||
|
fixture := loadFixtures(t, db)
|
||||||
|
repo := bundb.NewMonitor(db)
|
||||||
|
group := getGroupFromFixture(t, fixture, "group-1-server-1")
|
||||||
|
|
||||||
|
t.Run("OK", func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
beforeDelete, err := repo.List(context.Background(), group.ID.String())
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Greater(t, len(beforeDelete), 0)
|
||||||
|
|
||||||
|
assert.NoError(t, repo.Delete(context.Background(), beforeDelete[0].ID))
|
||||||
|
|
||||||
|
afterDelete, err := repo.List(context.Background(), group.ID.String())
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Len(t, afterDelete, len(beforeDelete)-1)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("ERR: monitor not found", func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
id string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "ID - not UUID",
|
||||||
|
id: "test",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ID - random UUID",
|
||||||
|
id: uuid.NewString(),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
tt := tt
|
||||||
|
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
assert.ErrorIs(
|
||||||
|
t,
|
||||||
|
repo.Delete(context.Background(), tt.id),
|
||||||
|
domain.MonitorNotFoundError{ID: tt.id},
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
|
@ -18,6 +18,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)
|
||||||
|
Delete(ctx context.Context, id, serverID string) error
|
||||||
}
|
}
|
||||||
|
|
||||||
type ChoiceService interface {
|
type ChoiceService interface {
|
||||||
|
|
|
@ -57,6 +57,19 @@ func (c *monitorCommand) create(s *discordgo.Session) error {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Name: "delete",
|
||||||
|
Description: "Deletes a monitor",
|
||||||
|
Type: discordgo.ApplicationCommandOptionSubCommand,
|
||||||
|
Options: []*discordgo.ApplicationCommandOption{
|
||||||
|
{
|
||||||
|
Name: "monitor",
|
||||||
|
Description: "Monitor ID",
|
||||||
|
Type: discordgo.ApplicationCommandOptionString,
|
||||||
|
Required: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -77,6 +90,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 "delete":
|
||||||
|
c.handleDelete(s, i)
|
||||||
|
return
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -116,3 +132,25 @@ func (c *monitorCommand) handleCreate(s *discordgo.Session, i *discordgo.Interac
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *monitorCommand) handleDelete(s *discordgo.Session, i *discordgo.InteractionCreate) {
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
monitor := i.ApplicationCommandData().Options[0].Options[0].StringValue()
|
||||||
|
if err := c.svc.Delete(ctx, monitor, i.GuildID); 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: "monitor has been successfully deleted",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
|
@ -82,3 +82,19 @@ func (e MonitorLimitReachedError) UserError() string {
|
||||||
func (e MonitorLimitReachedError) Code() ErrorCode {
|
func (e MonitorLimitReachedError) Code() ErrorCode {
|
||||||
return ErrorCodeValidationError
|
return ErrorCodeValidationError
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type MonitorNotFoundError struct {
|
||||||
|
ID string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e MonitorNotFoundError) Error() string {
|
||||||
|
return fmt.Sprintf("monitor (ID=%s) not found", e.ID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e MonitorNotFoundError) UserError() string {
|
||||||
|
return e.Error()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e MonitorNotFoundError) Code() ErrorCode {
|
||||||
|
return ErrorCodeEntityNotFound
|
||||||
|
}
|
||||||
|
|
|
@ -91,3 +91,15 @@ func TestMonitorLimitReachedError(t *testing.T) {
|
||||||
assert.Equal(t, err.Error(), err.UserError())
|
assert.Equal(t, err.Error(), err.UserError())
|
||||||
assert.Equal(t, domain.ErrorCodeValidationError, err.Code())
|
assert.Equal(t, domain.ErrorCodeValidationError, err.Code())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestMonitorNotFoundError(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
err := domain.MonitorNotFoundError{
|
||||||
|
ID: uuid.NewString(),
|
||||||
|
}
|
||||||
|
var _ domain.UserError = err
|
||||||
|
assert.Equal(t, fmt.Sprintf("monitor (ID=%s) not found", err.ID), err.Error())
|
||||||
|
assert.Equal(t, err.Error(), err.UserError())
|
||||||
|
assert.Equal(t, domain.ErrorCodeEntityNotFound, err.Code())
|
||||||
|
}
|
||||||
|
|
|
@ -17,6 +17,8 @@ const (
|
||||||
type MonitorRepository interface {
|
type MonitorRepository interface {
|
||||||
Create(ctx context.Context, params domain.CreateMonitorParams) (domain.Monitor, error)
|
Create(ctx context.Context, params domain.CreateMonitorParams) (domain.Monitor, error)
|
||||||
List(ctx context.Context, groupID string) ([]domain.Monitor, error)
|
List(ctx context.Context, groupID string) ([]domain.Monitor, error)
|
||||||
|
Get(ctx context.Context, id string) (domain.Monitor, error)
|
||||||
|
Delete(ctx context.Context, id string) error
|
||||||
}
|
}
|
||||||
|
|
||||||
//counterfeiter:generate -o internal/mock/group_getter.gen.go . GroupGetter
|
//counterfeiter:generate -o internal/mock/group_getter.gen.go . GroupGetter
|
||||||
|
@ -87,3 +89,21 @@ func (m *Monitor) Create(ctx context.Context, groupID, serverID, tribeTag string
|
||||||
|
|
||||||
return monitor, nil
|
return monitor, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *Monitor) Delete(ctx context.Context, id, serverID string) error {
|
||||||
|
monitor, err := m.repo.Get(ctx, id)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("MonitorRepository.Get: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = m.groupSvc.Get(ctx, monitor.GroupID, serverID)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("GroupService.Get: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = m.repo.Delete(ctx, id); err != nil {
|
||||||
|
return fmt.Errorf("MonitorRepository.Delete: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user