Add support for discord forum channels/threads (discord)

Messages send to forum threads need to use the ID of the forum for the
webhook but also need to set an additional parameter during the API call
to specify the destination thread.

Receiving messages from threads works by using the thread ID. The forum
ID is not required.

This commit adds an optional channel option "ForumID" which can be used
to supply the forum ID of a thread (= channel). When sending/editing
messages the ForumID will be used for the webhook and the channel ID
will be supplied as the additional parameter "thread_id".

Fixes #1908
pull/1914/head
Tom Kunze 2 years ago committed by Tom Kunze
parent 56e7bd01ca
commit 3e3090fc53

@ -181,6 +181,7 @@ type Protocol struct {
type ChannelOptions struct {
Key string // irc, xmpp
WebhookURL string // discord
ForumID string // discord
Topic string // zulip
}

@ -63,13 +63,13 @@ func New(session *discordgo.Session, guild string, title string, autoCreate bool
}
// Send transmits a message to the given channel with the provided webhook data, and waits until Discord responds with message data.
func (t *Transmitter) Send(channelID string, params *discordgo.WebhookParams) (*discordgo.Message, error) {
func (t *Transmitter) SendThread(channelID string, threadID string, params *discordgo.WebhookParams) (*discordgo.Message, error) {
wh, err := t.getOrCreateWebhook(channelID)
if err != nil {
return nil, err
}
msg, err := t.session.WebhookExecute(wh.ID, wh.Token, true, params)
msg, err := t.session.WebhookThreadExecute(wh.ID, wh.Token, true, threadID, params)
if err != nil {
return nil, fmt.Errorf("execute failed: %w", err)
}
@ -77,15 +77,24 @@ func (t *Transmitter) Send(channelID string, params *discordgo.WebhookParams) (*
return msg, nil
}
func (t *Transmitter) Send(channelID string, params *discordgo.WebhookParams) (*discordgo.Message, error) {
return t.SendThread(channelID, "", params)
}
// Edit will edit a message in a channel, if possible.
func (t *Transmitter) Edit(channelID string, messageID string, params *discordgo.WebhookParams) error {
func (t *Transmitter) EditThread(channelID string, threadID string, messageID string, params *discordgo.WebhookParams) error {
wh := t.getWebhook(channelID)
if wh == nil {
return ErrWebhookNotFound
}
uri := discordgo.EndpointWebhookToken(wh.ID, wh.Token) + "/messages/" + messageID
threadParam := ""
if threadID != "" {
threadParam = "?thread_id=" + threadID
}
uri := discordgo.EndpointWebhookToken(wh.ID, wh.Token) + "/messages/" + messageID + threadParam
_, err := t.session.RequestWithBucketID("PATCH", uri, params, discordgo.EndpointWebhookToken("", ""))
if err != nil {
return err
@ -94,6 +103,10 @@ func (t *Transmitter) Edit(channelID string, messageID string, params *discordgo
return nil
}
func (t *Transmitter) Edit(channelID string, messageID string, params *discordgo.WebhookParams) error {
return t.EditThread(channelID, "", messageID, params)
}
// HasWebhook checks whether the transmitter is using a particular webhook.
func (t *Transmitter) HasWebhook(id string) bool {
t.mutex.RLock()

@ -42,10 +42,10 @@ func (b *Bdiscord) maybeGetLocalAvatar(msg *config.Message) string {
return ""
}
// webhookSend send one or more message via webhook, taking care of file
// uploads (from slack, telegram or mattermost).
// webhookSendThread send one or more message via webhook, taking care of file
// uploads (from slack, telegram or mattermost) and forum threads.
// Returns messageID and error.
func (b *Bdiscord) webhookSend(msg *config.Message, channelID string) (*discordgo.Message, error) {
func (b *Bdiscord) webhookSendThread(msg *config.Message, channelID string, threadID string) (*discordgo.Message, error) {
var (
res *discordgo.Message
res2 *discordgo.Message
@ -61,8 +61,9 @@ func (b *Bdiscord) webhookSend(msg *config.Message, channelID string) (*discordg
// We can't send empty messages.
if msg.Text != "" {
res, err = b.transmitter.Send(
res, err = b.transmitter.SendThread(
channelID,
threadID,
&discordgo.WebhookParams{
Content: msg.Text,
Username: msg.Username,
@ -85,8 +86,9 @@ func (b *Bdiscord) webhookSend(msg *config.Message, channelID string) (*discordg
}
content := fi.Comment
res2, err = b.transmitter.Send(
res2, err = b.transmitter.SendThread(
channelID,
threadID,
&discordgo.WebhookParams{
Username: msg.Username,
AvatarURL: msg.Avatar,
@ -108,6 +110,10 @@ func (b *Bdiscord) webhookSend(msg *config.Message, channelID string) (*discordg
return res, err
}
func (b *Bdiscord) webhookSend(msg *config.Message, channelID string) (*discordgo.Message, error) {
return b.webhookSendThread(msg, channelID, "")
}
func (b *Bdiscord) handleEventWebhook(msg *config.Message, channelID string) (string, error) {
// skip events
if msg.Event != "" && msg.Event != config.EventUserAction && msg.Event != config.EventJoinLeave && msg.Event != config.EventTopicChange {
@ -120,6 +126,15 @@ func (b *Bdiscord) handleEventWebhook(msg *config.Message, channelID string) (st
return "", nil
}
// If ForumID is set, it should be used as channelID for the webhook and the channelID is used as the thread_id
threadID := ""
if ci, ok := b.channelInfoMap[msg.Channel+b.Account]; ok {
if ci.Options.ForumID != "" {
threadID = channelID
channelID = ci.Options.ForumID
}
}
msg.Text = helper.ClipMessage(msg.Text, MessageLength, b.GetString("MessageClipped"))
msg.Text = b.replaceUserMentions(msg.Text)
// discord username must be [0..32] max
@ -129,7 +144,7 @@ func (b *Bdiscord) handleEventWebhook(msg *config.Message, channelID string) (st
if msg.ID != "" {
b.Log.Debugf("Editing webhook message")
err := b.transmitter.Edit(channelID, msg.ID, &discordgo.WebhookParams{
err := b.transmitter.EditThread(channelID, threadID, msg.ID, &discordgo.WebhookParams{
Content: msg.Text,
Username: msg.Username,
AllowedMentions: b.getAllowedMentions(),
@ -141,7 +156,7 @@ func (b *Bdiscord) handleEventWebhook(msg *config.Message, channelID string) (st
}
b.Log.Debugf("Processing webhook sending for message %#v", msg)
discordMsg, err := b.webhookSend(msg, channelID)
discordMsg, err := b.webhookSendThread(msg, channelID, threadID)
if err != nil {
b.Log.Errorf("Could not broadcast via webhook for message %#v: %s", msg, err)
return "", err

@ -1928,8 +1928,13 @@ enable=true
channel="mygreatgame"
[gateway.inout.options]
# WebhookURL sends messages in the style of "puppets". You must configure a webhook URL for each channel you want to bridge.
# OPTIONAL - ForumID: the ID of the forum channel containing the thread. The thread ID should be used for "channel" then.
# Note: Do not add "ID:" at the beginning of the ForumID.
# Example: "123456789"
ForumID=""
# OPTIONAL - WebhookURL sends messages in the style of "puppets". You must configure a webhook URL for each channel you want to bridge.
# If you have more than one channel and don't wnat to configure each channel manually, see the "AutoWebhooks" option in the gateway config.
# WebhookURL does not support forum channels (URLs containing "?thread_id="), see "ForumID"
# Example: "https://discord.com/api/webhooks/1234/abcd_xyzw"
WebhookURL=""

Loading…
Cancel
Save