/mybots: Edit Bot summary screen, return-to-menu, clickable @mentions

- Edit Bot now shows the current value of every field (Name/About/
  Description/Botpic/Commands) like BotFather, with real botpic status
  via a new PeerHasAvatar port method.
- After editing a field the dialog lands back on a fresh Edit Bot menu
  (working "Back to bot" / "Bots list" buttons) instead of ending, so a
  follow-up button press no longer reports the button as expired.
- Service-bot messages now render @username as a tappable mention entity.
This commit is contained in:
Astra 2026-09-08 13:44:01 +01:00
parent f474a360d7
commit 5afafc60c4
7 changed files with 215 additions and 10 deletions

View file

@ -83,6 +83,15 @@ func mybotsHasButton(msg domain.Message, label string) bool {
return ok
}
func hasMentionEntity(msg domain.Message, mention string) bool {
for _, e := range msg.Entities {
if e.Type == domain.MessageEntityMention && e.Length == len(mention) {
return true
}
}
return false
}
// pressBotFather clicks the button whose text contains label on the user's latest
// @BotFather reply and returns the callback answer plus the user's new latest
// reply (which, for an in-place edit, is the same message updated).
@ -328,6 +337,51 @@ func (d *deletableBotStore) ListBotsByOwner(ctx context.Context, ownerUserID int
return out, nil
}
func TestMyBotsEditBotShowsSummaryAndReturnsAfterEdit(t *testing.T) {
svc, users, _, messages := newTestService(t)
owner := newOwner(t, users, "+2010")
if _, _, err := svc.CreateBot(context.Background(), owner.ID, "Enigma Network", "enigma_mb_bot"); err != nil {
t.Fatalf("create bot: %v", err)
}
sendToBotFather(t, svc, messages, owner, "/mybots")
pressBotFather(t, svc, messages, owner.ID, "@enigma_mb_bot")
_, edit := pressBotFather(t, svc, messages, owner.ID, "Edit Bot")
for _, want := range []string{"Edit @enigma_mb_bot info.", "Name: Enigma Network", "About: 🚫", "Commands: no commands yet", "Botpic: 🚫"} {
if !strings.Contains(edit.Body, want) {
t.Fatalf("edit summary missing %q:\n%s", want, edit.Body)
}
}
for _, want := range []string{"Edit Name", "Edit About", "Edit Botpic", "Back to bot", "Bots list"} {
if !mybotsHasButton(edit, want) {
t.Fatalf("edit menu missing button %q: %+v", want, edit.ReplyMarkup)
}
}
// The @mention is a tappable entity, not plain text.
if !hasMentionEntity(edit, "@enigma_mb_bot") {
t.Fatalf("no mention entity for @enigma_mb_bot: %+v", edit.Entities)
}
pressBotFather(t, svc, messages, owner.ID, "Edit About")
sendToBotFather(t, svc, messages, owner, "we host things")
after := botFatherUserReply(t, messages, owner.ID)
if !strings.Contains(after.Body, "About section updated") || !strings.Contains(after.Body, "Edit @enigma_mb_bot info.") {
t.Fatalf("post-edit reply is not the edit menu:\n%s", after.Body)
}
if !strings.Contains(after.Body, "About: we host things") {
t.Fatalf("edit menu did not refresh the About value:\n%s", after.Body)
}
// The bug this guards: pressing another field on the refreshed menu must work,
// not report the button as expired.
answer, prompt := pressBotFather(t, svc, messages, owner.ID, "Edit Botpic")
if answer.Alert {
t.Fatalf("Edit Botpic on the refreshed menu alerted: %q", answer.Message)
}
if !strings.Contains(prompt.Body, "profile picture") {
t.Fatalf("Edit Botpic prompt = %q", prompt.Body)
}
}
func TestMyBotsDeleteBot(t *testing.T) {
users := memory.NewUserStore()
store := &deletableBotStore{BotStore: memory.NewBotStore(users), deleted: map[int64]bool{}}