diff --git a/internal/bundb/group.go b/internal/bundb/group.go index 8de511a..a7efdf4 100644 --- a/internal/bundb/group.go +++ b/internal/bundb/group.go @@ -58,7 +58,7 @@ func (g *Group) Update(ctx context.Context, id, serverID string, params domain.U Apply(updateGroupsParamsApplier{params}.apply). Exec(ctx) if err != nil && !errors.Is(err, sql.ErrNoRows) { - return domain.Group{}, fmt.Errorf("couldn't update group (id=%s): %w", id, err) + return domain.Group{}, fmt.Errorf("couldn't update group (id=%s,serverID=%s): %w", id, serverID, err) } if affected, _ := res.RowsAffected(); affected == 0 { return domain.Group{}, domain.GroupNotFoundError{ID: id} @@ -85,6 +85,26 @@ func (g *Group) List(ctx context.Context, params domain.ListGroupsParams) ([]dom return result, nil } +func (g *Group) Delete(ctx context.Context, id, serverID string) error { + if _, err := uuid.Parse(id); err != nil { + return domain.GroupNotFoundError{ID: id} + } + + res, err := g.db.NewDelete(). + Model(&model.Group{}). + Returning("NULL"). + Where("id = ?", id). + Where("server_id = ?", serverID). + Exec(ctx) + if err != nil && !errors.Is(err, sql.ErrNoRows) { + return fmt.Errorf("couldn't delete group (id=%s,serverID=%s): %w", id, serverID, err) + } + if affected, _ := res.RowsAffected(); affected == 0 { + return domain.GroupNotFoundError{ID: id} + } + return nil +} + type updateGroupsParamsApplier struct { params domain.UpdateGroupParams } diff --git a/internal/bundb/group_test.go b/internal/bundb/group_test.go index 22878b7..bff391c 100644 --- a/internal/bundb/group_test.go +++ b/internal/bundb/group_test.go @@ -190,6 +190,55 @@ func TestGroup_List(t *testing.T) { } } +func TestGroup_Delete(t *testing.T) { + t.Parallel() + + db := newDB(t) + fixture := loadFixtures(t, db) + repo := bundb.NewGroup(db) + group := getGroupFromFixture(t, fixture, "group-server-1-1") + + t.Run("OK", func(t *testing.T) { + t.Parallel() + + assert.NoError(t, repo.Delete(context.Background(), group.ID.String(), group.ServerID)) + + groups, err := repo.List(context.Background(), domain.ListGroupsParams{ + ServerIDs: []string{group.ID.String()}, + }) + assert.NoError(t, err) + assert.Len(t, groups, 0) + }) + + t.Run("ERR: invalid UUID", func(t *testing.T) { + t.Parallel() + + id := "12345" + assert.ErrorIs(t, repo.Delete(context.Background(), id, ""), domain.GroupNotFoundError{ID: id}) + }) + + t.Run("ERR: group not found (unknown ID)", func(t *testing.T) { + t.Parallel() + + id := uuid.NewString() + assert.ErrorIs( + t, + repo.Delete(context.Background(), id, group.ServerID), + domain.GroupNotFoundError{ID: id}, + ) + }) + + t.Run("ERR: group not found (unknown ServerID)", func(t *testing.T) { + t.Parallel() + + assert.ErrorIs( + t, + repo.Delete(context.Background(), group.ID.String(), uuid.NewString()), + domain.GroupNotFoundError{ID: group.ID.String()}, + ) + }) +} + func getAllGroupsFromFixture(tb testing.TB, fixture *dbfixture.Fixture) []model.Group { tb.Helper() diff --git a/internal/discord/bot.go b/internal/discord/bot.go index 5de12ae..a878db9 100644 --- a/internal/discord/bot.go +++ b/internal/discord/bot.go @@ -15,6 +15,7 @@ type GroupService interface { SetChannelGains(ctx context.Context, id, serverID, channel string) (domain.Group, error) SetChannelLosses(ctx context.Context, id, serverID, channel string) (domain.Group, error) List(ctx context.Context, params domain.ListGroupsParams) ([]domain.Group, error) + Delete(ctx context.Context, id, serverID string) error } type TWHelpClient interface { diff --git a/internal/discord/command_group.go b/internal/discord/command_group.go index e29634b..0502294 100644 --- a/internal/discord/command_group.go +++ b/internal/discord/command_group.go @@ -193,6 +193,19 @@ func (c *groupCommand) create(s *discordgo.Session) error { }, }, }, + { + Name: "delete", + Description: "Deletes a group", + Type: discordgo.ApplicationCommandOptionSubCommand, + Options: []*discordgo.ApplicationCommandOption{ + { + Name: "group", + Description: "Group ID", + Type: discordgo.ApplicationCommandOptionString, + Required: true, + }, + }, + }, }, }) if err != nil { @@ -237,6 +250,9 @@ func (c *groupCommand) handle(s *discordgo.Session, i *discordgo.InteractionCrea case "unset": c.handleUnset(s, i) return + case "delete": + c.handleDelete(s, i) + return default: } } @@ -515,6 +531,28 @@ func (c *groupCommand) handleUnsetChannelLosses(s *discordgo.Session, i *discord }) } +func (c *groupCommand) handleDelete(s *discordgo.Session, i *discordgo.InteractionCreate) { + ctx := context.Background() + + group := i.ApplicationCommandData().Options[0].Options[0].StringValue() + if err := c.svc.Delete(ctx, group, 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: "group has been successfully deleted", + }, + }) +} + func buildGroupListDescription(groups []domain.Group) string { description := "**ID** - **Version** - **Server**" for i, g := range groups { diff --git a/internal/service/group.go b/internal/service/group.go index 09a8dae..16e41ac 100644 --- a/internal/service/group.go +++ b/internal/service/group.go @@ -18,6 +18,7 @@ type GroupRepository interface { Create(ctx context.Context, params domain.CreateGroupParams) (domain.Group, error) Update(ctx context.Context, id, serverID string, params domain.UpdateGroupParams) (domain.Group, error) List(ctx context.Context, params domain.ListGroupsParams) ([]domain.Group, error) + Delete(ctx context.Context, id, serverID string) error } type Group struct { @@ -112,6 +113,13 @@ func (g *Group) List(ctx context.Context, params domain.ListGroupsParams) ([]dom return groups, nil } +func (g *Group) Delete(ctx context.Context, id, serverID string) error { + if err := g.repo.Delete(ctx, id, serverID); err != nil { + return fmt.Errorf("GroupRepository.Delete: %w", err) + } + return nil +} + func (g *Group) checkTWServer(ctx context.Context, versionCode, serverKey string) error { server, err := g.client.GetServer(ctx, versionCode, serverKey) if err != nil {