Merge pull request #1306 from aaron-tsar/fix/telegram-instance-per-topic-config

fix(telegram): honor per-group/topic overrides for DB instances
This commit is contained in:
Clark Cant authored and GitHub committed 2026-06-29 23:54:41 +07:00
commit c8d292c691
2 files changed
+95 -20

No files matched your search

+22 -20
View File
@@ -20,26 +20,27 @@ type telegramCreds struct {
// telegramInstanceConfig maps the non-secret config JSONB from the channel_instances table.
type telegramInstanceConfig struct {
APIServer string `json:"api_server,omitempty"`
Proxy string `json:"proxy,omitempty"`
DMPolicy string `json:"dm_policy,omitempty"`
GroupPolicy string `json:"group_policy,omitempty"`
RequireMention *bool `json:"require_mention,omitempty"`
MentionMode string `json:"mention_mode,omitempty"`
HistoryLimit int `json:"history_limit,omitempty"`
DMStream *bool `json:"dm_stream,omitempty"`
GroupStream *bool `json:"group_stream,omitempty"`
DraftTransport *bool `json:"draft_transport,omitempty"` // sendMessageDraft for DM streaming (default true)
ReasoningDelivery string `json:"reasoning_delivery,omitempty"`
ReasoningStream *bool `json:"reasoning_stream,omitempty"` // show reasoning as separate message (default true)
ReactionLevel string `json:"reaction_level,omitempty"`
MediaMaxMB int64 `json:"media_max_mb,omitempty"`
MediaMaxBytes int64 `json:"media_max_bytes,omitempty"` // deprecated: use media_max_mb
LinkPreview *bool `json:"link_preview,omitempty"`
BlockReply *bool `json:"block_reply,omitempty"`
ChatBehavior *config.ChatBehaviorConfig `json:"chat_behavior,omitempty"`
ForceIPv4 bool `json:"force_ipv4,omitempty"`
AllowFrom []string `json:"allow_from,omitempty"`
APIServer string `json:"api_server,omitempty"`
Proxy string `json:"proxy,omitempty"`
DMPolicy string `json:"dm_policy,omitempty"`
GroupPolicy string `json:"group_policy,omitempty"`
RequireMention *bool `json:"require_mention,omitempty"`
MentionMode string `json:"mention_mode,omitempty"`
HistoryLimit int `json:"history_limit,omitempty"`
DMStream *bool `json:"dm_stream,omitempty"`
GroupStream *bool `json:"group_stream,omitempty"`
DraftTransport *bool `json:"draft_transport,omitempty"` // sendMessageDraft for DM streaming (default true)
ReasoningDelivery string `json:"reasoning_delivery,omitempty"`
ReasoningStream *bool `json:"reasoning_stream,omitempty"` // show reasoning as separate message (default true)
ReactionLevel string `json:"reaction_level,omitempty"`
MediaMaxMB int64 `json:"media_max_mb,omitempty"`
MediaMaxBytes int64 `json:"media_max_bytes,omitempty"` // deprecated: use media_max_mb
LinkPreview *bool `json:"link_preview,omitempty"`
BlockReply *bool `json:"block_reply,omitempty"`
ChatBehavior *config.ChatBehaviorConfig `json:"chat_behavior,omitempty"`
ForceIPv4 bool `json:"force_ipv4,omitempty"`
AllowFrom []string `json:"allow_from,omitempty"`
Groups map[string]*config.TelegramGroupConfig `json:"groups,omitempty"`
}
// Factory creates a Telegram channel from DB instance data (no extra stores).
@@ -119,6 +120,7 @@ func buildChannel(name string, creds json.RawMessage, cfg json.RawMessage,
BlockReply: ic.BlockReply,
ChatBehavior: ic.ChatBehavior,
ForceIPv4: ic.ForceIPv4,
Groups: ic.Groups,
}
// DB instances default to "pairing" for groups (secure by default).
@@ -0,0 +1,73 @@
package telegram
import (
"encoding/json"
"testing"
)
const validBotToken = "123456:abcdefghijklmnopqrstuvwxyzABCDE1234"
func TestFactory_PropagatesGroupsAndTopics(t *testing.T) {
creds := json.RawMessage(`{"token":"` + validBotToken + `"}`)
cfg := json.RawMessage(`{
"groups": {
"-1003957927661": {
"enabled": false,
"topics": {
"13": { "enabled": true }
}
}
}
}`)
ch, err := Factory("telegram-test", creds, cfg, nil, nil)
if err != nil {
t.Fatalf("Factory: %v", err)
}
tg, ok := ch.(*Channel)
if !ok {
t.Fatalf("Factory returned %T, want *Channel", ch)
}
if tg.config.Groups == nil {
t.Fatal("config.Groups is nil — dashboard groups/topics payload was dropped on unmarshal")
}
group, ok := tg.config.Groups["-1003957927661"]
if !ok || group == nil {
t.Fatal("group -1003957927661 missing from resolved config")
}
if group.Enabled == nil || *group.Enabled != false {
t.Errorf("group.Enabled = %v, want false", group.Enabled)
}
allowed := resolveTopicConfig(tg.config, "-1003957927661", 13)
if !allowed.isEnabled() {
t.Error("topic 13: isEnabled() = false, want true")
}
other := resolveTopicConfig(tg.config, "-1003957927661", 99)
if other.isEnabled() {
t.Error("topic 99: isEnabled() = true, want false")
}
general := resolveTopicConfig(tg.config, "-1003957927661", telegramGeneralTopicID)
if general.isEnabled() {
t.Error("General topic: isEnabled() = true, want false")
}
}
func TestFactory_NilGroupsWhenAbsent(t *testing.T) {
creds := json.RawMessage(`{"token":"` + validBotToken + `"}`)
cfg := json.RawMessage(`{"group_policy":"open"}`)
ch, err := Factory("telegram-test", creds, cfg, nil, nil)
if err != nil {
t.Fatalf("Factory: %v", err)
}
tg := ch.(*Channel)
if tg.config.Groups != nil {
t.Errorf("config.Groups = %v, want nil when groups absent", tg.config.Groups)
}
def := resolveTopicConfig(tg.config, "-100123", 0)
if !def.isEnabled() {
t.Error("isEnabled() = false, want true by default when no overrides set")
}
}