telegram

package
v1.16.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 6, 2026 License: GPL-3.0 Imports: 22 Imported by: 0

Documentation

Overview

The templates in this file are MarkdownV2 (bold is *single asterisks*, italic is _underscores_). Render them exclusively with RenderMarkdownV2 so every data value is escaped; the fullwidth punctuation (!:。,) in the static text needs no escaping because MarkdownV2 only reserves ASCII syntax characters.

Index

Constants

View Source
const AdminOrderDaily = `` /* 309-byte string literal not displayed */

AdminOrderDaily 管理员每日订单统计

View Source
const AdminOrderNotify = `` /* 331-byte string literal not displayed */

AdminOrderNotify 管理员订单通知

View Source
const BindNotify = `` /* 238-byte string literal not displayed */
View Source
const NotifyTopicTitle = "📣 运营通知"

NotifyTopicTitle names the operations feed topic the bot creates in the administrators' group.

View Source
const PurchaseNotify = `` /* 370-byte string literal not displayed */
View Source
const RechargeNotify = `` /* 349-byte string literal not displayed */

RechargeNotify 充值通知

View Source
const RenewalNotify = `` /* 370-byte string literal not displayed */
View Source
const ResetTrafficNotify = `` /* 333-byte string literal not displayed */

ResetTrafficNotify 重置流量通知

View Source
const SubscribeExpireNotify = `` /* 283-byte string literal not displayed */

SubscribeExpireNotify 订阅到期通知

View Source
const UnbindNotify = `` /* 353-byte string literal not displayed */

UnbindNotify 解绑通知

Variables

This section is empty.

Functions

func EscapeMarkdownV2 added in v1.15.18

func EscapeMarkdownV2(s string) string

EscapeMarkdownV2 returns s with all MarkdownV2 syntax characters escaped, so arbitrary data renders as literal text.

func RenderMarkdownV2 added in v1.15.18

func RenderMarkdownV2(tpl string, data map[string]string) (string, error)

RenderMarkdownV2 renders a message template after escaping every data value. Templates own their formatting; data is always literal text. This is the only correct way to build MarkdownV2 messages from dynamic data: one unescaped '.' or '-' in an order number makes Telegram reject the whole message.

func TicketTopicTitle added in v1.15.18

func TicketTopicTitle(t *ticket.Ticket) string

TicketTopicTitle names a ticket topic; the leading number keeps the topic list scannable next to /tk.

Types

type Command added in v1.15.16

type Command struct {
	Command     string
	Description string
}

Command describes one entry of the bot's command menu. It mirrors Telegram's BotCommand without binding this package to the bot library.

func AdminCommands added in v1.15.16

func AdminCommands() []Command

AdminCommands is the menu published to the administrators of the admin group (chat_administrators scope), where the administrator commands are the only place they work. It deliberately excludes /confirm_* and /cancel_* because those carry a generated action id and are only ever offered inline.

func PublicCommands added in v1.15.16

func PublicCommands() []Command

PublicCommands is the menu every user gets: account binding, plus the help entry that makes the administrator surface discoverable to the people who have access to it. Handlers still authenticate, so a non-administrator only learns that the command exists.

type TelegramAdmin

type TelegramAdmin struct {
	logger.Logger
	// contains filtered or unexported fields
}

TelegramAdmin handles administrative Telegram commands independently from the general Telegram bot flow.

func (*TelegramAdmin) Handle

func (a *TelegramAdmin) Handle(msg *models.Message)

Handle runs an administrator command.

type TelegramAdminActionStore

type TelegramAdminActionStore interface {
	Get(ctx context.Context, key string) (string, error)
	Set(ctx context.Context, key, value string, ttl time.Duration) error
	Delete(ctx context.Context, key string) error
}

TelegramAdminActionStore persists short-lived confirmations for destructive administrator commands.

type TelegramAdminDependencies

type TelegramAdminDependencies struct {
	Messenger TelegramMessenger
	Actions   TelegramAdminActionStore
	// MirrorTicketStatus and MirrorTicketReply keep the ticket's forum
	// topic in step with ticket mutations done through bot commands
	// (/close, /reopen, /rp), which bypass the support module's notifier.
	// Optional and best-effort.
	MirrorTicketStatus func(ticketID int64, status uint8)
	MirrorTicketReply  func(ticketID int64, content string)
	Tickets            repository.TicketRepo
	Orders             repository.OrderRepo
	Users              repository.UserRepo
	UserAuth           repository.UserAuthRepo
	Subscriptions      repository.UserSubscriptionRepo
	UserCache          repository.UserCacheRepo
	Plans              repository.SubscribeRepo
	Logs               repository.LogRepo
	// Wallet is the billing-domain read port for balance display.
	Wallet repository.WalletRepo
}

TelegramAdminDependencies contains only the collaborators used by Telegram administrator commands. It intentionally does not accept ServiceContext.

type TelegramAdminHandler

type TelegramAdminHandler interface {
	Handle(msg *models.Message)
}

TelegramAdminHandler handles administrator Telegram commands.

type TelegramCommandRegistrar added in v1.15.16

type TelegramCommandRegistrar interface {
	SetCommands(chatID int64, commands []Command) error
	SetGroupAdminCommands(chatID int64, commands []Command) error
}

TelegramCommandRegistrar publishes the command menu Telegram shows in the message composer. A zero chatID addresses the default scope, which every user sees; a non-zero chatID scopes the menu to that chat. SetGroupAdminCommands scopes the menu to a group's administrators, which is how the administrator commands stay invisible to ordinary members.

func NewTelegramBotCommandRegistrar added in v1.15.16

func NewTelegramBotCommandRegistrar(bot *tgbot.Bot) TelegramCommandRegistrar

NewTelegramBotCommandRegistrar adapts a Telegram Bot API client to the command-menu port.

type TelegramLogic

type TelegramLogic struct {
	logger.Logger
	// contains filtered or unexported fields
}

func (*TelegramLogic) TelegramLogic

func (l *TelegramLogic) TelegramLogic(req *models.Update)

TelegramLogic routes one update. User commands live in the private chat; everything administrative — commands, support topics, ticket topics — lives in the configured admin group. Messages from other groups are ignored entirely.

type TelegramLogicDependencies

type TelegramLogicDependencies struct {
	Messenger TelegramMessenger
	Sessions  TelegramSessionStore
	UserAuth  repository.UserAuthRepo
	UserCache repository.UserCacheRepo
	Admin     TelegramAdminHandler

	// GroupChatID returns the validated admin group; zero disables group
	// routing. Read per call because re-initialisation may change it.
	GroupChatID func() int64
	Topics      repository.TelegramTopicRepo
	TopicClient TelegramTopicClient
	Tickets     repository.TicketRepo
	Users       repository.UserRepo
	Limiter     TelegramRelayLimiter
}

TelegramLogicDependencies explicitly declares the collaborators used by update routing: user command dispatch and account binding in the private chat, and the group-side relays. The group fields may be left zero, which turns every group feature off.

type TelegramMessenger

type TelegramMessenger interface {
	Send(chatID, threadID int64, message string) error
	SendMarkdown(chatID, threadID int64, message string) error
}

TelegramMessenger sends a response to a Telegram chat. A non-zero threadID addresses one forum topic inside a group; zero addresses the chat itself (private chats, or a group's General topic). Send delivers plain text; SendMarkdown delivers MarkdownV2 produced by RenderMarkdownV2, and must never receive unescaped dynamic data — Telegram rejects the whole message over one stray reserved character.

func NewTelegramBotMessenger

func NewTelegramBotMessenger(bot *tgbot.Bot) TelegramMessenger

NewTelegramBotMessenger adapts a Telegram Bot API client to the command messenger port.

type TelegramRedisStore

TelegramRedisStore supports account-binding sessions, administrator command confirmations, and the support relay rate limit.

func NewTelegramRedisStore

func NewTelegramRedisStore(client *redis.Client) TelegramRedisStore

NewTelegramRedisStore adapts Redis to the binding-session and administrator confirmation ports.

type TelegramRelayLimiter added in v1.15.18

type TelegramRelayLimiter interface {
	// Allow reports whether the chat may relay another message right now.
	// shouldNotify is true only for the first rejection of a window, so a
	// flood is answered with one notice instead of one per message.
	Allow(ctx context.Context, chatID int64) (allowed, shouldNotify bool)
}

TelegramRelayLimiter caps how fast one chat may relay support messages into the admin group.

type TelegramSessionStore

type TelegramSessionStore interface {
	Get(ctx context.Context, key string) (string, error)
	Delete(ctx context.Context, key string) error
}

TelegramSessionStore reads and consumes short-lived account-binding tokens. Deleting the token on a successful bind is what makes the deep link single-use.

type TelegramTopicClient added in v1.15.18

type TelegramTopicClient interface {
	// ValidateAdminGroup confirms the chat is a forum-enabled supergroup
	// where the bot may manage topics.
	ValidateAdminGroup(ctx context.Context, chatID int64) error
	CreateTopic(ctx context.Context, chatID int64, name string) (int64, error)
	DeleteTopic(ctx context.Context, chatID, threadID int64) error
	CloseTopic(ctx context.Context, chatID, threadID int64) error
	ReopenTopic(ctx context.Context, chatID, threadID int64) error
	// ForwardToThread relays a user's message into a group topic keeping
	// the sender identity visible to the support staff.
	ForwardToThread(ctx context.Context, chatID, threadID, fromChatID int64, messageID int) error
	// CopyTo relays a group message to a private chat without exposing
	// which administrator wrote it.
	CopyTo(ctx context.Context, toChatID, fromChatID int64, messageID int) error
}

TelegramTopicClient is the group-side Bot API surface the topic layer drives. telegramBotMessenger implements it; tests fake it.

func NewTelegramTopicClient added in v1.15.18

func NewTelegramTopicClient(bot *tgbot.Bot) TelegramTopicClient

NewTelegramTopicClient adapts the bot client to the topic-management port.

type TopicService added in v1.15.18

type TopicService struct {
	logger.Logger
	// contains filtered or unexported fields
}

TopicService owns the mapping between forum topics and the conversation each carries.

func NewTopicService added in v1.15.18

func NewTopicService(ctx context.Context, client TelegramTopicClient, topics repository.TelegramTopicRepo, group int64) *TopicService

func (*TopicService) Close added in v1.15.18

func (s *TopicService) Close(topic *telegramtopic.Topic) error

Close closes the forum topic and marks the mapping; a topic already gone from Telegram still gets its mapping closed.

func (*TopicService) Ensure added in v1.15.18

func (s *TopicService) Ensure(kind uint8, refID int64, title string) (topic *telegramtopic.Topic, created bool, err error)

Ensure returns the mapping for (kind, ref), creating the forum topic on first use; created reports whether this call made it. Concurrent creators race on the unique key; the loser adopts the winner's row.

func (*TopicService) PostMarkdown added in v1.15.18

func (s *TopicService) PostMarkdown(m TelegramMessenger, topic *telegramtopic.Topic, text string) (*telegramtopic.Topic, error)

PostMarkdown sends MarkdownV2 into a topic through Relay's self-healing.

func (*TopicService) PostText added in v1.15.18

PostText is PostMarkdown for plain text.

func (*TopicService) Recreate added in v1.15.18

func (s *TopicService) Recreate(topic *telegramtopic.Topic) (*telegramtopic.Topic, error)

Recreate repoints a mapping whose topic was deleted inside Telegram.

func (*TopicService) Relay added in v1.15.18

func (s *TopicService) Relay(topic *telegramtopic.Topic, op func(threadID int64) error) (*telegramtopic.Topic, error)

Relay runs op against the topic's thread, transparently recreating a deleted topic or reopening a closed one, then retrying once. It returns the mapping actually used, which may have been repointed.

func (*TopicService) Reopen added in v1.15.18

func (s *TopicService) Reopen(topic *telegramtopic.Topic) (*telegramtopic.Topic, error)

Reopen reopens a closed topic and marks the mapping active. A missing topic is recreated instead.

func (*TopicService) TicketCreated added in v1.15.18

func (s *TopicService) TicketCreated(m TelegramMessenger, t *ticket.Ticket, userLabel string) error

TicketCreated opens the ticket's topic and posts its opening message. Only tickets created after the group went live get a topic; older tickets have no mapping and their events are skipped upstream.

func (*TopicService) TicketReplied added in v1.15.18

func (s *TopicService) TicketReplied(m TelegramMessenger, ticketID int64, from, content string) error

TicketReplied posts a website-side reply into the ticket's topic. A ticket without a mapping predates the group and is silently skipped.

func (*TopicService) TicketStatusChanged added in v1.15.18

func (s *TopicService) TicketStatusChanged(ticketID int64, status uint8) error

TicketStatusChanged mirrors a website-side status change onto the topic: closing the ticket closes the topic, any other status reopens it.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL