Compare commits
2 commits
236e9ed25a
...
e927d4d18a
| Author | SHA1 | Date | |
|---|---|---|---|
| e927d4d18a | |||
| 86f9b61336 |
2 changed files with 89 additions and 0 deletions
|
|
@ -274,6 +274,13 @@ func (s *Service) handleBotFather(ctx context.Context, userID int64, msg domain.
|
||||||
if cmd, ok := parseBotCommand(text); ok {
|
if cmd, ok := parseBotCommand(text); ok {
|
||||||
inValueStep := found && state.Step == botFatherStepValue
|
inValueStep := found && state.Step == botFatherStepValue
|
||||||
if !inValueStep || botFatherGlobalCommands[cmd] {
|
if !inValueStep || botFatherGlobalCommands[cmd] {
|
||||||
|
// "/start <bot>" (the "Manage Bot" deep link) jumps straight to that
|
||||||
|
// bot's menu, like /mybots then tapping the bot.
|
||||||
|
if cmd == "start" {
|
||||||
|
if arg := botCommandArg(text); arg != "" {
|
||||||
|
return s.handleBotFatherStart(ctx, userID, arg)
|
||||||
|
}
|
||||||
|
}
|
||||||
return s.handleBotFatherCommand(ctx, userID, cmd)
|
return s.handleBotFatherCommand(ctx, userID, cmd)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -368,6 +375,41 @@ func (s *Service) stepPrompt(state domain.BotChatState) botReply {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// handleBotFatherStart answers "/start <arg>". When <arg> names one of the
|
||||||
|
// user's own bots (by username or numeric id) it opens that bot's menu - the
|
||||||
|
// same "What do you want to do?" screen as /mybots then tapping the bot, which
|
||||||
|
// is what the "Manage Bot" button on a bot's profile links to. An empty or
|
||||||
|
// unknown arg falls back to the plain greeting.
|
||||||
|
func (s *Service) handleBotFatherStart(ctx context.Context, userID int64, arg string) botReply {
|
||||||
|
_ = s.bots.DeleteBotChatState(ctx, domain.BotFatherUserID, userID)
|
||||||
|
want := strings.ToLower(strings.TrimPrefix(strings.TrimSpace(arg), "@"))
|
||||||
|
if want == "" {
|
||||||
|
return botReply{Text: botFatherHelpText}
|
||||||
|
}
|
||||||
|
owned, err := s.ownedBots(ctx, userID)
|
||||||
|
if err != nil {
|
||||||
|
s.log.Error("botfather: list bots for start payload", zap.Int64("user_id", userID), zap.Error(err))
|
||||||
|
return internalReply()
|
||||||
|
}
|
||||||
|
for _, b := range owned {
|
||||||
|
if strings.EqualFold(b.user.Username, want) || strconv.FormatInt(b.user.ID, 10) == want {
|
||||||
|
state := domain.BotChatState{
|
||||||
|
BotUserID: domain.BotFatherUserID,
|
||||||
|
UserID: userID,
|
||||||
|
Command: mybotsCommand,
|
||||||
|
Step: mybotsStepMenu,
|
||||||
|
Draft: map[string]string{},
|
||||||
|
}
|
||||||
|
reply := s.myBotsBotMenu(&state, b)
|
||||||
|
if !s.saveMyBotsState(ctx, state) {
|
||||||
|
return internalReply()
|
||||||
|
}
|
||||||
|
return reply
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return botReply{Text: botFatherHelpText}
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Service) handleBotFatherCommand(ctx context.Context, userID int64, cmd string) botReply {
|
func (s *Service) handleBotFatherCommand(ctx context.Context, userID int64, cmd string) botReply {
|
||||||
switch cmd {
|
switch cmd {
|
||||||
case "start", "help":
|
case "start", "help":
|
||||||
|
|
@ -1157,3 +1199,16 @@ func parseBotCommand(text string) (string, bool) {
|
||||||
}
|
}
|
||||||
return strings.ToLower(cmd), true
|
return strings.ToLower(cmd), true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// botCommandArg returns the trimmed argument after a leading "/cmd", e.g.
|
||||||
|
// "/start my_bot" -> "my_bot". Empty when there is no argument.
|
||||||
|
func botCommandArg(text string) string {
|
||||||
|
text = strings.TrimSpace(text)
|
||||||
|
if !strings.HasPrefix(text, "/") {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
if i := strings.IndexAny(text, " \t\n"); i >= 0 {
|
||||||
|
return strings.TrimSpace(text[i+1:])
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -202,6 +202,40 @@ func TestMyBotsBotMenuAndBack(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestBotFatherStartWithBotOpensItsMenu(t *testing.T) {
|
||||||
|
svc, users, _, messages := newTestService(t)
|
||||||
|
owner := newOwner(t, users, "+2011")
|
||||||
|
makeBots(t, svc, owner.ID, 2)
|
||||||
|
|
||||||
|
// "/start <bot>" is the "Manage Bot" deep link: it lands on the per-bot menu.
|
||||||
|
body := sendToBotFather(t, svc, messages, owner, "/start mb0_bot")
|
||||||
|
if !strings.Contains(body, "@mb0_bot") || !strings.Contains(body, "What do you want to do?") {
|
||||||
|
t.Fatalf("/start mb0_bot reply = %q", body)
|
||||||
|
}
|
||||||
|
menu := botFatherUserReply(t, messages, owner.ID)
|
||||||
|
for _, want := range []string{"API Token", "Edit Bot", "Bot Settings", "Delete Bot", "Back to bots"} {
|
||||||
|
if !mybotsHasButton(menu, want) {
|
||||||
|
t.Fatalf("start menu missing %q: %+v", want, menu.ReplyMarkup)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// The buttons are live (state was saved), so Edit Bot works from here.
|
||||||
|
_, edit := pressBotFather(t, svc, messages, owner.ID, "Edit Bot")
|
||||||
|
if !strings.Contains(edit.Body, "@mb0_bot") {
|
||||||
|
t.Fatalf("edit menu after /start = %q", edit.Body)
|
||||||
|
}
|
||||||
|
|
||||||
|
// A leading @ and an unknown/foreign bot fall back to the greeting.
|
||||||
|
if body := sendToBotFather(t, svc, messages, owner, "/start @mb1_bot"); !strings.Contains(body, "@mb1_bot") {
|
||||||
|
t.Fatalf("/start @mb1_bot reply = %q", body)
|
||||||
|
}
|
||||||
|
if body := sendToBotFather(t, svc, messages, owner, "/start not_a_real_bot"); !strings.Contains(body, "create a new bot") {
|
||||||
|
t.Fatalf("/start unknown reply = %q, want greeting", body)
|
||||||
|
}
|
||||||
|
if body := sendToBotFather(t, svc, messages, owner, "/start"); !strings.Contains(body, "create a new bot") {
|
||||||
|
t.Fatalf("bare /start reply = %q, want greeting", body)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestMyBotsTokenAndRevoke(t *testing.T) {
|
func TestMyBotsTokenAndRevoke(t *testing.T) {
|
||||||
svc, users, bots, messages := newTestService(t)
|
svc, users, bots, messages := newTestService(t)
|
||||||
owner := newOwner(t, users, "+2003")
|
owner := newOwner(t, users, "+2003")
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue