mirror of
https://github.com/tiennm99/goclaw.git
synced 2026-10-14 12:16:54 +00:00
Squash merge PR #99 after resolving conflicts with current dev. PR CI run 26703381807 passed release-versioning, go, and web.
151 lines
4.8 KiB
Go
151 lines
4.8 KiB
Go
package slack
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
|
|
"github.com/nextlevelbuilder/goclaw/internal/bus"
|
|
"github.com/nextlevelbuilder/goclaw/internal/channels"
|
|
"github.com/nextlevelbuilder/goclaw/internal/config"
|
|
"github.com/nextlevelbuilder/goclaw/internal/store"
|
|
)
|
|
|
|
// slackCreds maps the credentials JSON from the channel_instances table.
|
|
type slackCreds struct {
|
|
BotToken string `json:"bot_token"` // xoxb-...
|
|
AppToken string `json:"app_token"` // xapp-... (Socket Mode)
|
|
UserToken string `json:"user_token,omitempty"` // xoxp-... (optional: custom identity)
|
|
}
|
|
|
|
// slackInstanceConfig maps the non-secret config JSONB from the channel_instances table.
|
|
type slackInstanceConfig struct {
|
|
DMPolicy string `json:"dm_policy,omitempty"`
|
|
GroupPolicy string `json:"group_policy,omitempty"`
|
|
AllowFrom []string `json:"allow_from,omitempty"`
|
|
RequireMention *bool `json:"require_mention,omitempty"`
|
|
HistoryLimit int `json:"history_limit,omitempty"`
|
|
DMStream *bool `json:"dm_stream,omitempty"`
|
|
GroupStream *bool `json:"group_stream,omitempty"`
|
|
NativeStream *bool `json:"native_stream,omitempty"`
|
|
ReactionLevel string `json:"reaction_level,omitempty"`
|
|
BlockReply *bool `json:"block_reply,omitempty"`
|
|
ChatBehavior *config.ChatBehaviorConfig `json:"chat_behavior,omitempty"`
|
|
DebounceDelay *int `json:"debounce_delay,omitempty"`
|
|
ThreadTTL *int `json:"thread_ttl,omitempty"`
|
|
}
|
|
|
|
// Factory creates a Slack channel from DB instance data.
|
|
func Factory(name string, creds json.RawMessage, cfg json.RawMessage,
|
|
msgBus *bus.MessageBus, pairingSvc store.PairingStore) (channels.Channel, error) {
|
|
|
|
var c slackCreds
|
|
if len(creds) > 0 {
|
|
if err := json.Unmarshal(creds, &c); err != nil {
|
|
return nil, fmt.Errorf("decode slack credentials: %w", err)
|
|
}
|
|
}
|
|
if c.BotToken == "" {
|
|
return nil, fmt.Errorf("slack bot_token is required")
|
|
}
|
|
if c.AppToken == "" {
|
|
return nil, fmt.Errorf("slack app_token is required for Socket Mode")
|
|
}
|
|
|
|
var ic slackInstanceConfig
|
|
if len(cfg) > 0 {
|
|
if err := json.Unmarshal(cfg, &ic); err != nil {
|
|
return nil, fmt.Errorf("decode slack config: %w", err)
|
|
}
|
|
}
|
|
|
|
slackCfg := config.SlackConfig{
|
|
Enabled: true,
|
|
BotToken: c.BotToken,
|
|
AppToken: c.AppToken,
|
|
UserToken: c.UserToken,
|
|
AllowFrom: ic.AllowFrom,
|
|
DMPolicy: ic.DMPolicy,
|
|
GroupPolicy: ic.GroupPolicy,
|
|
RequireMention: ic.RequireMention,
|
|
HistoryLimit: ic.HistoryLimit,
|
|
DMStream: ic.DMStream,
|
|
GroupStream: ic.GroupStream,
|
|
NativeStream: ic.NativeStream,
|
|
ReactionLevel: ic.ReactionLevel,
|
|
BlockReply: ic.BlockReply,
|
|
ChatBehavior: ic.ChatBehavior,
|
|
DebounceDelay: ic.DebounceDelay,
|
|
ThreadTTL: ic.ThreadTTL,
|
|
}
|
|
|
|
// Secure default: DB instances default to "pairing" for groups.
|
|
if slackCfg.GroupPolicy == "" {
|
|
slackCfg.GroupPolicy = "pairing"
|
|
}
|
|
|
|
ch, err := New(slackCfg, msgBus, pairingSvc, nil)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
ch.SetName(name)
|
|
return ch, nil
|
|
}
|
|
|
|
// FactoryWithPendingStore returns a ChannelFactory with persistent history support.
|
|
func FactoryWithPendingStore(pendingStore store.PendingMessageStore) channels.ChannelFactory {
|
|
return func(name string, creds json.RawMessage, cfg json.RawMessage,
|
|
msgBus *bus.MessageBus, pairingSvc store.PairingStore) (channels.Channel, error) {
|
|
|
|
var c slackCreds
|
|
if len(creds) > 0 {
|
|
if err := json.Unmarshal(creds, &c); err != nil {
|
|
return nil, fmt.Errorf("decode slack credentials: %w", err)
|
|
}
|
|
}
|
|
if c.BotToken == "" {
|
|
return nil, fmt.Errorf("slack bot_token is required")
|
|
}
|
|
if c.AppToken == "" {
|
|
return nil, fmt.Errorf("slack app_token is required for Socket Mode")
|
|
}
|
|
|
|
var ic slackInstanceConfig
|
|
if len(cfg) > 0 {
|
|
if err := json.Unmarshal(cfg, &ic); err != nil {
|
|
return nil, fmt.Errorf("decode slack config: %w", err)
|
|
}
|
|
}
|
|
|
|
slackCfg := config.SlackConfig{
|
|
Enabled: true,
|
|
BotToken: c.BotToken,
|
|
AppToken: c.AppToken,
|
|
UserToken: c.UserToken,
|
|
AllowFrom: ic.AllowFrom,
|
|
DMPolicy: ic.DMPolicy,
|
|
GroupPolicy: ic.GroupPolicy,
|
|
RequireMention: ic.RequireMention,
|
|
HistoryLimit: ic.HistoryLimit,
|
|
DMStream: ic.DMStream,
|
|
GroupStream: ic.GroupStream,
|
|
NativeStream: ic.NativeStream,
|
|
ReactionLevel: ic.ReactionLevel,
|
|
BlockReply: ic.BlockReply,
|
|
ChatBehavior: ic.ChatBehavior,
|
|
DebounceDelay: ic.DebounceDelay,
|
|
ThreadTTL: ic.ThreadTTL,
|
|
}
|
|
|
|
if slackCfg.GroupPolicy == "" {
|
|
slackCfg.GroupPolicy = "pairing"
|
|
}
|
|
|
|
ch, err := New(slackCfg, msgBus, pairingSvc, pendingStore)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
ch.SetName(name)
|
|
return ch, nil
|
|
}
|
|
}
|