e71e40eef5
CI / changes (pull_request) Successful in 2s
CI / unit (pull_request) Successful in 11s
CI / integration (pull_request) Successful in 19s
CI / ui (pull_request) Successful in 57s
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Successful in 1m39s
Add a second standalone promo bot to the bot container (answers /start with a localized message + a URL button into the main bot's Mini App) and gate write access in a channel's linked discussion chat: grant on join when the Telegram user is registered and neither admin-suspended nor holding a new chat_muted role, and revoke/grant on the matching moderation change for a member currently in the chat. Eligibility (registered AND NOT suspended AND NOT chat_muted; the game suspension dominates) is resolved once in the backend and reached two ways: the bot's join-time unary ResolveChatEligibility over the existing mTLS bot-link, and a backend chat_access_changed event -> gateway -> ChatGate command (idempotent; a temporary-block-expiry sweeper may over-emit). The bot guards the block/unblock path with getChatMember, since bots cannot list members. A web_app button cannot open another bot's Mini App (it signs initData with the sending bot's token), so the promo button is a t.me ?startapp URL reusing the UI's VITE_TELEGRAM_LINK. The bot must be a chat admin with the restrict-members right and chat_member in its allowed updates. No schema change: chat_muted reuses the data-driven account_roles table.
51 lines
1.6 KiB
Go
51 lines
1.6 KiB
Go
package botlink
|
|
|
|
import (
|
|
botlinkv1 "scrabble/pkg/proto/botlink/v1"
|
|
telegramv1 "scrabble/pkg/proto/telegram/v1"
|
|
)
|
|
|
|
// NotifyCommand builds an out-of-app push command rendered by the bot in the
|
|
// recipient's interface language.
|
|
func NotifyCommand(externalID, kind string, payload []byte, language string) *botlinkv1.Command {
|
|
return &botlinkv1.Command{
|
|
Payload: &botlinkv1.Command_Notify{Notify: &telegramv1.NotifyRequest{
|
|
ExternalId: externalID,
|
|
Kind: kind,
|
|
Payload: payload,
|
|
Language: language,
|
|
}},
|
|
}
|
|
}
|
|
|
|
// SendToUserCommand builds an admin text message addressed to one user.
|
|
func SendToUserCommand(externalID, text string) *botlinkv1.Command {
|
|
return &botlinkv1.Command{
|
|
Payload: &botlinkv1.Command_SendToUser{SendToUser: &telegramv1.SendToUserRequest{
|
|
ExternalId: externalID,
|
|
Text: text,
|
|
}},
|
|
}
|
|
}
|
|
|
|
// SendToGameChannelCommand builds an admin text message for the bot's game channel.
|
|
func SendToGameChannelCommand(text string) *botlinkv1.Command {
|
|
return &botlinkv1.Command{
|
|
Payload: &botlinkv1.Command_SendToChannel{SendToChannel: &telegramv1.SendToGameChannelRequest{
|
|
Text: text,
|
|
}},
|
|
}
|
|
}
|
|
|
|
// ChatGateCommand builds a chat-gate command that sets whether the Telegram user
|
|
// identified by externalID may write in the moderated discussion chat. The bot
|
|
// applies it only to a member currently in the chat (guarded on getChatMember).
|
|
func ChatGateCommand(externalID string, allow bool) *botlinkv1.Command {
|
|
return &botlinkv1.Command{
|
|
Payload: &botlinkv1.Command_ChatGate{ChatGate: &botlinkv1.ChatGateCommand{
|
|
ExternalId: externalID,
|
|
Allow: allow,
|
|
}},
|
|
}
|
|
}
|