diff --git a/cmd/themis-server/main.go b/cmd/themis-server/main.go index 6a44196..dcf2dc0 100644 --- a/cmd/themis-server/main.go +++ b/cmd/themis-server/main.go @@ -104,6 +104,18 @@ func main() { }, }, }, + { + Name: "describe-claim", + Description: "Get details on a claim", + Type: discordgo.ChatApplicationCommand, + Options: []*discordgo.ApplicationCommandOption{ + { + Name: "id", + Description: "Numerical ID for the claim", + Type: discordgo.ApplicationCommandOptionInteger, + }, + }, + }, { Name: "delete-claim", Description: "Release one of your claims", @@ -246,6 +258,37 @@ func main() { log.Println("[error] failed to respond to command:", err) } }, + "describe-claim": func(s *discordgo.Session, i *discordgo.InteractionCreate) { + id := i.ApplicationCommandData().Options[0] + detail, err := store.DescribeClaim(ctx, int(id.IntValue())) + if err != nil { + err = s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{ + Type: discordgo.InteractionResponseChannelMessageWithSource, + Data: &discordgo.InteractionResponseData{ + Content: "woops, something went wrong :(", + }, + }) + if err != nil { + log.Println("[error] failed to respond to command:", err) + } + } + + sb := strings.Builder{} + sb.WriteString(fmt.Sprintf("#%d %s %s (%s)\n", detail.ID, detail.Name, detail.Type, detail.Player)) + for _, p := range detail.Provinces { + sb.WriteString(fmt.Sprintf(" - %s\n", p)) + } + + err = s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{ + Type: discordgo.InteractionResponseChannelMessageWithSource, + Data: &discordgo.InteractionResponseData{ + Content: sb.String(), + }, + }) + if err != nil { + log.Println("[error] failed to respond to command:", err) + } + }, "delete-claim": func(s *discordgo.Session, i *discordgo.InteractionCreate) { id := i.ApplicationCommandData().Options[0] userId := i.Member.User.ID @@ -253,7 +296,7 @@ func main() { if err != nil { msg := "Oops, something went wrong :( blame @wperron" if errors.Is(err, themis.ErrNoSuchClaim) { - msg = err.Error() + msg = fmt.Sprintf("Claim #%d not found for %s", id.IntValue(), i.Member.Nick) } log.Printf("[error]: %s\n", err) err = s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{ @@ -359,8 +402,10 @@ func formatClaimsTable(claims []themis.Claim) string { if len(c.Player) > maxLengths[1] { maxLengths[1] = len(c.Player) } - if len(c.Type) > maxLengths[2] { - maxLengths[2] = len(c.Type) + // The raw claim value is different from the formatted string + strType := c.Type.String() + if len(strType) > maxLengths[2] { + maxLengths[2] = len(strType) } if len(c.Name) > maxLengths[3] { maxLengths[3] = len(c.Name) diff --git a/store.go b/store.go index 703b005..1f88bb6 100644 --- a/store.go +++ b/store.go @@ -28,6 +28,18 @@ func ClaimTypeFromString(s string) (ClaimType, error) { return "", fmt.Errorf("no claim type matching '%s'", s) } +func (ct ClaimType) String() string { + switch ct { + case CLAIM_TYPE_AREA: + return "Area" + case CLAIM_TYPE_REGION: + return "Region" + case CLAIM_TYPE_TRADE: + return "Trade Node" + } + return "" +} + const ( CLAIM_TYPE_AREA = "area" CLAIM_TYPE_REGION = "region" @@ -240,6 +252,9 @@ func (s *Store) DescribeClaim(ctx context.Context, ID int) (ClaimDetail, error) c := Claim{} var rawType string err = row.Scan(&c.ID, &c.Player, &rawType, &c.Name) + if err == sql.ErrNoRows { + return ClaimDetail{}, ErrNoSuchClaim + } if err != nil { return ClaimDetail{}, fmt.Errorf("failed to scan row: %w", err) } @@ -275,7 +290,7 @@ func (s *Store) DescribeClaim(ctx context.Context, ID int) (ClaimDetail, error) }, nil } -var ErrNoSuchClaim = errors.New("no such claim found for player") +var ErrNoSuchClaim = errors.New("no such claim") func (s *Store) DeleteClaim(ctx context.Context, ID int, userId string) error { stmt, err := s.db.PrepareContext(ctx, "DELETE FROM claims WHERE id = ? AND userid = ?") diff --git a/store_test.go b/store_test.go index 18780aa..cf255c0 100644 --- a/store_test.go +++ b/store_test.go @@ -148,3 +148,19 @@ func TestDeleteClaim(t *testing.T) { assert.Error(t, err) assert.ErrorIs(t, err, ErrNoSuchClaim) } + +func TestDescribeClaim(t *testing.T) { + store, err := NewStore(TEST_CONN_STRING) + assert.NoError(t, err) + + id, err := store.Claim(context.TODO(), "000000000000000001", "foo", "Genoa", CLAIM_TYPE_TRADE) + assert.NoError(t, err) + + detail, err := store.DescribeClaim(context.TODO(), id) + assert.NoError(t, err) + assert.Equal(t, "Genoa", detail.Name) + assert.Contains(t, detail.Provinces, "Saluzzo") + + detail, err = store.DescribeClaim(context.TODO(), 9999) + assert.ErrorIs(t, err, ErrNoSuchClaim) +}