feat(wordledaily): send the wordle BotFather game

Cards from /wordledaily and the 07:00 push now use the BotFather game
wordle, and Play answers it. The module, commands and page route keep the
wordledaily name.
This commit is contained in:
tiennm99 committed 2026-10-09 17:23:17 +07:00
1 parent c0231ceadf
commit bc8a7d8869
6 files changed
+18 -14

No files matched your search

+3 -1
View File
@@ -29,7 +29,9 @@ data and scoring through `internal/modules/wordle/wordlist`.
## Setup
1. **BotFather:** create a game for the bot with `/newgame` and the short name
`wordledaily`. The share link is then `t.me/<bot username>?game=wordledaily`.
`wordle`. The share link is then `t.me/<bot username>?game=wordle`. The
module, its commands and its routes keep the name `wordledaily`; only the
BotFather game is `wordle`.
2. **Public URL:** this uses the same `GAME_BASE_URL` as the
[noitu game](noitu-game.md#setup). The page is served at
`<GAME_BASE_URL>/games/wordledaily/`.
@@ -50,7 +50,7 @@ func TestModule_Registration(t *testing.T) {
if strings.Join(names, " ") != "wordledaily wordledaily_subscribe wordledaily_unsubscribe" {
t.Fatalf("commands = %v", names)
}
if len(mod.Games) != 1 || mod.Games[0].ShortName != "wordledaily" {
if len(mod.Games) != 1 || mod.Games[0].ShortName != "wordle" {
t.Fatalf("games = %+v", mod.Games)
}
if len(mod.HTTP) != 0 || len(mod.Crons) != 0 {
@@ -84,7 +84,7 @@ func TestNew_FromEnv(t *testing.T) {
func TestPlay_DisabledAnswersAlert(t *testing.T) {
rb := install(t, newService(config{}).module())
rb.Bot.ProcessUpdate(context.Background(), testutil.NewGameCallback(1, 1, 5, ShortName))
rb.Bot.ProcessUpdate(context.Background(), testutil.NewGameCallback(1, 1, 5, GameShortName))
f := answerForm(t, rb)
if f["text"] != msgDisabled || f["show_alert"] != "true" || f["url"] != "" {
t.Fatalf("answer = %v", f)
@@ -108,7 +108,7 @@ func TestPlay_AnswersSignedURLForEveryCardForm(t *testing.T) {
h := newHarness(t)
rb := install(t, h.svc.module())
topic := testutil.NewGameCallback(42, groupChat, 9, ShortName)
topic := testutil.NewGameCallback(42, groupChat, 9, GameShortName)
topic.CallbackQuery.From.LastName = "Nguyen"
topic.CallbackQuery.Message.Message.IsTopicMessage = true
topic.CallbackQuery.Message.Message.MessageThreadID = 77
@@ -122,7 +122,7 @@ func TestPlay_AnswersSignedURLForEveryCardForm(t *testing.T) {
}
inaccessible := &models.Update{CallbackQuery: &models.CallbackQuery{
ID: "q", From: models.User{ID: 42, FirstName: "A"}, GameShortName: ShortName,
ID: "q", From: models.User{ID: 42, FirstName: "A"}, GameShortName: GameShortName,
Message: models.MaybeInaccessibleMessage{
Type: models.MaybeInaccessibleMessageTypeInaccessibleMessage,
InaccessibleMessage: &models.InaccessibleMessage{Chat: models.Chat{ID: -5}, MessageID: 3},
@@ -133,12 +133,12 @@ func TestPlay_AnswersSignedURLForEveryCardForm(t *testing.T) {
t.Fatalf("inaccessible claims = %+v", c)
}
rb.Bot.ProcessUpdate(context.Background(), testutil.NewInlineGameCallback(42, "BAAAInline", ShortName))
rb.Bot.ProcessUpdate(context.Background(), testutil.NewInlineGameCallback(42, "BAAAInline", GameShortName))
if c := decodeURLToken(t, h, answerForm(t, rb)["url"]); c.InlineID != "BAAAInline" || c.ChatID != 0 {
t.Fatalf("inline claims = %+v", c)
}
none := testutil.NewInlineGameCallback(42, "", ShortName)
none := testutil.NewInlineGameCallback(42, "", GameShortName)
rb.Bot.ProcessUpdate(context.Background(), none)
if f := answerForm(t, rb); f["text"] != msgNoGameTarget || f["show_alert"] != "true" {
t.Fatalf("no target = %v", f)
@@ -172,7 +172,7 @@ func TestCommand_SendsGameKeepingTopic(t *testing.T) {
u.Message.MessageThreadID, u.Message.IsTopicMessage = 77, true
rb.Bot.ProcessUpdate(context.Background(), u)
games := sentMethod(rb, "sendGame")
if len(games) != 1 || games[0].Form["game_short_name"] != ShortName || games[0].Form["message_thread_id"] != "77" || games[0].ChatID() != "-100" {
if len(games) != 1 || games[0].Form["game_short_name"] != GameShortName || games[0].Form["message_thread_id"] != "77" || games[0].ChatID() != "-100" {
t.Fatalf("sent %+v", rb.Sent())
}
// A reply chain in an ordinary supergroup carries a thread id too, but
+1 -1
View File
@@ -33,7 +33,7 @@ func (s *service) handleCommand(ctx context.Context, b *bot.Bot, update *models.
if _, err := b.SendGame(ctx, &bot.SendGameParams{
ChatID: msg.Chat.ID,
MessageThreadID: topicOf(msg),
GameShorName: ShortName, // the library's field name is misspelled
GameShorName: GameShortName, // the library's field name is misspelled
}); err != nil {
_ = chathelper.Reply(ctx, b, msg, msgSendGameFail)
return err
+1 -1
View File
@@ -83,7 +83,7 @@ func (s *service) pushTo(ctx context.Context, api telegramAPI, num int, sub subs
}
}
}
_, err := api.SendGame(ctx, &bot.SendGameParams{ChatID: sub.ChatID, MessageThreadID: sub.ThreadID, GameShorName: ShortName})
_, err := api.SendGame(ctx, &bot.SendGameParams{ChatID: sub.ChatID, MessageThreadID: sub.ThreadID, GameShorName: GameShortName})
return err
}
+1 -1
View File
@@ -70,7 +70,7 @@ func TestPush_RecapThenCardWithCrownTiesAndLoss(t *testing.T) {
t.Fatalf("not sent to the topic: %+v", c)
}
}
if sent[1].Form["game_short_name"] != ShortName {
if sent[1].Form["game_short_name"] != GameShortName {
t.Fatalf("card = %v", sent[1].Form)
}
// The same puzzle is never pushed twice.
+5 -3
View File
@@ -30,9 +30,11 @@ import (
)
const (
// ShortName is the game's BotFather short name and the module's catalog
// key, so its routes live under /games/wordledaily/.
// ShortName is the module's catalog key and command name, so its routes
// live under /games/wordledaily/.
ShortName = "wordledaily"
// GameShortName is the BotFather game the cards send and Play answers.
GameShortName = "wordle"
subscribeCommand = ShortName + "_subscribe"
unsubscribeCommand = ShortName + "_unsubscribe"
@@ -203,7 +205,7 @@ func (s *service) module() modules.Module {
Handler: s.handleUnsubscribe,
}},
Games: []modules.Game{{
ShortName: ShortName,
ShortName: GameShortName,
Visibility: modules.VisibilityPublic,
Handler: s.handlePlay,
}},