diff --git a/bot.go b/bot.go index 5f6fa8a..6e3f1e4 100644 --- a/bot.go +++ b/bot.go @@ -36,6 +36,7 @@ type Bot struct { url string token string + username string pollTimeout time.Duration skipGetMe bool webhookSecretToken string @@ -92,10 +93,11 @@ func New(token string, options ...Option) (*Bot, error) { defer cancel() if !b.skipGetMe { - _, err := b.GetMe(ctx) + botInfo, err := b.GetMe(ctx) if err != nil { return nil, fmt.Errorf("error call getMe, %w", err) } + b.username = botInfo.Username } return b, nil @@ -121,6 +123,13 @@ func (b *Bot) Token() string { return b.token } +// Username returns the bot username without `@` prefix +// +// Return empty string if bot with the `bot.WithSkipGetMe()` option +func (b *Bot) Username() string { + return b.username +} + // StartWebhook starts the Bot with webhook mode func (b *Bot) StartWebhook(ctx context.Context) { wg := sync.WaitGroup{} diff --git a/bot_test.go b/bot_test.go index 3831eca..b3dc7e0 100644 --- a/bot_test.go +++ b/bot_test.go @@ -396,3 +396,13 @@ func TestBot_SetToken(t *testing.T) { t.Errorf("SetToken() = %s, want %s", b.token, "123456:xxx") } } + +func TestBot_Username(t *testing.T) { + b := &Bot{username: "example_bot"} + + username := b.Username() + + if username != "example_bot" { + t.Errorf("Username() = %s, want %s", username, "example_bot") + } +} diff --git a/handlers.go b/handlers.go index 8545781..f41abb5 100644 --- a/handlers.go +++ b/handlers.go @@ -24,6 +24,7 @@ const ( MatchTypeContains MatchTypeCommand MatchTypeCommandStartOnly + MatchTypeCommandStartMaybeWithBotUsernameSuffix // example `/command@example_bot`, can't match username suffix if bot with the `bot.WithSkipGetMe()` option matchTypeRegexp matchTypeFunc @@ -36,6 +37,7 @@ type handler struct { handler HandlerFunc pattern string + username string re *regexp.Regexp matchFunc MatchFunc } @@ -100,6 +102,15 @@ func (h handler) match(update *models.Update) bool { } } } + if h.matchType == MatchTypeCommandStartMaybeWithBotUsernameSuffix { + for _, e := range entities { + if e.Type == models.MessageEntityTypeBotCommand { + if e.Offset == 0 && (data[e.Offset+1:e.Offset+e.Length] == h.pattern || data[e.Offset+1:e.Offset+e.Length] == h.pattern+"@"+h.username) { + return true + } + } + } + } if h.matchType == matchTypeRegexp { return h.re.Match([]byte(data)) } @@ -154,6 +165,7 @@ func (b *Bot) RegisterHandler(handlerType HandlerType, pattern string, matchType handlerType: handlerType, matchType: matchType, pattern: pattern, + username: b.username, handler: applyMiddlewares(f, m...), } diff --git a/handlers_test.go b/handlers_test.go index 4a48df3..e45fa01 100644 --- a/handlers_test.go +++ b/handlers_test.go @@ -318,6 +318,256 @@ func Test_match_command_start(t *testing.T) { ID: 42, Message: &models.Message{ Text: "/bar", + Entities: []models.MessageEntity{ + {Type: models.MessageEntityTypeBotCommand, Offset: 0, Length: 4}, + }, + }, + } + + res := h.match(&u) + if res { + t.Error("unexpected result") + } + }) + + // correct command + t.Run("start maybe with username suffix 1, yes", func(t *testing.T) { + b := &Bot{ + username: "foo_bot", + } + + id := b.RegisterHandler(HandlerTypeMessageText, "foo", MatchTypeCommandStartMaybeWithBotUsernameSuffix, nil) + + h := findHandler(b, id) + u := models.Update{ + ID: 42, + Message: &models.Message{ + Text: "/foo", + Entities: []models.MessageEntity{ + {Type: models.MessageEntityTypeBotCommand, Offset: 0, Length: 4}, + }, + }, + } + + res := h.match(&u) + if !res { + t.Error("unexpected result") + } + }) + + // correct command, correct username + t.Run("start maybe with username suffix 2, yes", func(t *testing.T) { + b := &Bot{ + username: "foo_bot", + } + + id := b.RegisterHandler(HandlerTypeMessageText, "foo", MatchTypeCommandStartMaybeWithBotUsernameSuffix, nil) + + h := findHandler(b, id) + u := models.Update{ + ID: 42, + Message: &models.Message{ + Text: "/foo@foo_bot", + Entities: []models.MessageEntity{ + {Type: models.MessageEntityTypeBotCommand, Offset: 0, Length: 12}, + }, + }, + } + + res := h.match(&u) + if !res { + t.Error("unexpected result") + } + }) + + // correct command, wrong username + t.Run("start maybe with username suffix 3, no", func(t *testing.T) { + b := &Bot{ + username: "foo_bot", + } + + id := b.RegisterHandler(HandlerTypeMessageText, "foo", MatchTypeCommandStartMaybeWithBotUsernameSuffix, nil) + + h := findHandler(b, id) + u := models.Update{ + ID: 42, + Message: &models.Message{ + Text: "/foo@other_bot", + Entities: []models.MessageEntity{ + {Type: models.MessageEntityTypeBotCommand, Offset: 0, Length: 14}, + }, + }, + } + + res := h.match(&u) + if res { + t.Error("unexpected result") + } + }) + + // correct command, with prefix + t.Run("start maybe with username suffix 4, no", func(t *testing.T) { + b := &Bot{ + username: "foo_bot", + } + + id := b.RegisterHandler(HandlerTypeMessageText, "foo", MatchTypeCommandStartMaybeWithBotUsernameSuffix, nil) + + h := findHandler(b, id) + u := models.Update{ + ID: 42, + Message: &models.Message{ + Text: "a /foo", + Entities: []models.MessageEntity{ + {Type: models.MessageEntityTypeBotCommand, Offset: 2, Length: 4}, + }, + }, + } + + res := h.match(&u) + if res { + t.Error("unexpected result") + } + }) + + // correct command, with prefix, correct username + t.Run("start maybe with username suffix 5, no", func(t *testing.T) { + b := &Bot{ + username: "foo_bot", + } + + id := b.RegisterHandler(HandlerTypeMessageText, "foo", MatchTypeCommandStartMaybeWithBotUsernameSuffix, nil) + + h := findHandler(b, id) + u := models.Update{ + ID: 42, + Message: &models.Message{ + Text: "a /foo@foo_bot", + Entities: []models.MessageEntity{ + {Type: models.MessageEntityTypeBotCommand, Offset: 2, Length: 12}, + }, + }, + } + + res := h.match(&u) + if res { + t.Error("unexpected result") + } + }) + + // correct command, with prefix, wrong username + t.Run("start maybe with username suffix 6, no", func(t *testing.T) { + b := &Bot{ + username: "foo_bot", + } + + id := b.RegisterHandler(HandlerTypeMessageText, "foo", MatchTypeCommandStartMaybeWithBotUsernameSuffix, nil) + + h := findHandler(b, id) + u := models.Update{ + ID: 42, + Message: &models.Message{ + Text: "a /foo@other_bot", + Entities: []models.MessageEntity{ + {Type: models.MessageEntityTypeBotCommand, Offset: 2, Length: 14}, + }, + }, + } + + res := h.match(&u) + if res { + t.Error("unexpected result") + } + }) + + // wrong command + t.Run("start maybe with username suffix 7, no", func(t *testing.T) { + b := &Bot{ + username: "foo_bot", + } + + id := b.RegisterHandler(HandlerTypeMessageText, "foo", MatchTypeCommandStartMaybeWithBotUsernameSuffix, nil) + + h := findHandler(b, id) + u := models.Update{ + ID: 42, + Message: &models.Message{ + Text: "/bar", + Entities: []models.MessageEntity{ + {Type: models.MessageEntityTypeBotCommand, Offset: 0, Length: 4}, + }, + }, + } + + res := h.match(&u) + if res { + t.Error("unexpected result") + } + }) + + // wrong command, correct username + t.Run("start maybe with username suffix 8, no", func(t *testing.T) { + b := &Bot{ + username: "foo_bot", + } + + id := b.RegisterHandler(HandlerTypeMessageText, "foo", MatchTypeCommandStartMaybeWithBotUsernameSuffix, nil) + + h := findHandler(b, id) + u := models.Update{ + ID: 42, + Message: &models.Message{ + Text: "/bar@foo_bot", + Entities: []models.MessageEntity{ + {Type: models.MessageEntityTypeBotCommand, Offset: 0, Length: 12}, + }, + }, + } + + res := h.match(&u) + if res { + t.Error("unexpected result") + } + }) + + // wrong command, wrong username + t.Run("start maybe with username suffix 9, no", func(t *testing.T) { + b := &Bot{ + username: "foo_bot", + } + + id := b.RegisterHandler(HandlerTypeMessageText, "foo", MatchTypeCommandStartMaybeWithBotUsernameSuffix, nil) + + h := findHandler(b, id) + u := models.Update{ + ID: 42, + Message: &models.Message{ + Text: "/bar@other_bot", + Entities: []models.MessageEntity{ + {Type: models.MessageEntityTypeBotCommand, Offset: 0, Length: 14}, + }, + }, + } + + res := h.match(&u) + if res { + t.Error("unexpected result") + } + }) + + // wrong command, with prefix + t.Run("start maybe with username suffix 10, no", func(t *testing.T) { + b := &Bot{ + username: "foo_bot", + } + + id := b.RegisterHandler(HandlerTypeMessageText, "foo", MatchTypeCommandStartMaybeWithBotUsernameSuffix, nil) + + h := findHandler(b, id) + u := models.Update{ + ID: 42, + Message: &models.Message{ + Text: "a /bar", Entities: []models.MessageEntity{ {Type: models.MessageEntityTypeBotCommand, Offset: 2, Length: 4}, }, @@ -329,4 +579,104 @@ func Test_match_command_start(t *testing.T) { t.Error("unexpected result") } }) + + // wrong command, with prefix, correct username + t.Run("start maybe with username suffix 11, no", func(t *testing.T) { + b := &Bot{ + username: "foo_bot", + } + + id := b.RegisterHandler(HandlerTypeMessageText, "foo", MatchTypeCommandStartMaybeWithBotUsernameSuffix, nil) + + h := findHandler(b, id) + u := models.Update{ + ID: 42, + Message: &models.Message{ + Text: "a /bar@foo_bot", + Entities: []models.MessageEntity{ + {Type: models.MessageEntityTypeBotCommand, Offset: 2, Length: 12}, + }, + }, + } + + res := h.match(&u) + if res { + t.Error("unexpected result") + } + }) + + // wrong command, with prefix, wrong username + t.Run("start maybe with username suffix 12, no", func(t *testing.T) { + b := &Bot{ + username: "foo_bot", + } + + id := b.RegisterHandler(HandlerTypeMessageText, "foo", MatchTypeCommandStartMaybeWithBotUsernameSuffix, nil) + + h := findHandler(b, id) + u := models.Update{ + ID: 42, + Message: &models.Message{ + Text: "a /bar@other_bot", + Entities: []models.MessageEntity{ + {Type: models.MessageEntityTypeBotCommand, Offset: 2, Length: 14}, + }, + }, + } + + res := h.match(&u) + if res { + t.Error("unexpected result") + } + }) + + // correct command, no username, correct username + t.Run("start maybe with username suffix 13, no", func(t *testing.T) { + b := &Bot{ + // username: "foo_bot", // no username + } + + id := b.RegisterHandler(HandlerTypeMessageText, "foo", MatchTypeCommandStartMaybeWithBotUsernameSuffix, nil) + + h := findHandler(b, id) + u := models.Update{ + ID: 42, + Message: &models.Message{ + Text: "/foo@foo_bot", + Entities: []models.MessageEntity{ + {Type: models.MessageEntityTypeBotCommand, Offset: 0, Length: 12}, + }, + }, + } + + res := h.match(&u) + if res { + t.Error("unexpected result") + } + }) + + // correct command, no username, wrong username + t.Run("start maybe with username suffix 14, no", func(t *testing.T) { + b := &Bot{ + // username: "foo_bot", // no username + } + + id := b.RegisterHandler(HandlerTypeMessageText, "foo", MatchTypeCommandStartMaybeWithBotUsernameSuffix, nil) + + h := findHandler(b, id) + u := models.Update{ + ID: 42, + Message: &models.Message{ + Text: "/foo@other_bot", + Entities: []models.MessageEntity{ + {Type: models.MessageEntityTypeBotCommand, Offset: 0, Length: 14}, + }, + }, + } + + res := h.match(&u) + if res { + t.Error("unexpected result") + } + }) }