Compare commits

..

6 Commits

Author SHA1 Message Date
4b0a87c3f2 Remove fallback quoted msgs in XMPP replies
Some checks failed
Development / golangci-lint (push) Has been cancelled
Development / test-build-upload (1.22.x, ubuntu-latest) (push) Has been cancelled
CodeQL / Analyze (go) (push) Has been cancelled
2025-11-03 23:17:30 -08:00
f73bee90ab Fancy replies using rich embeds on Discord side
Some checks failed
Development / golangci-lint (push) Has been cancelled
Development / test-build-upload (1.22.x, ubuntu-latest) (push) Has been cancelled
2025-11-03 15:17:34 -08:00
186d28858b patch: fix Go builds
Some checks failed
Development / golangci-lint (push) Has been cancelled
Development / test-build-upload (1.22.x, ubuntu-latest) (push) Has been cancelled
2025-11-03 13:19:01 -08:00
bab3681ac2 Merge pull request 'Merge XMPP reply feature into upstream repo' (#5) from uwaru/matterbridge:master into updatexmppp
Some checks failed
Development / test-build-upload (1.22.x, ubuntu-latest) (push) Waiting to run
Development / golangci-lint (push) Has been cancelled
Reviewed-on: #5
2025-02-23 09:52:49 -08:00
b74b884793 xmpp: Add support for replies
Some checks failed
Development / golangci-lint (pull_request) Has been cancelled
Development / test-build-upload (1.22.x, ubuntu-latest) (pull_request) Has been cancelled
2024-11-04 04:52:16 +01:00
Wim
996e4a7fcf Update go-xmpp dependency 2024-05-24 01:16:34 +02:00
20 changed files with 1785 additions and 131 deletions

View File

@@ -353,7 +353,15 @@ func (b *Bdiscord) handleEventBotUser(msg *config.Message, channelID string) (st
for _, msgPart := range msgParts {
m := discordgo.MessageSend{
Content: msg.Username + msgPart,
Embeds: []*discordgo.MessageEmbed{
{
Description: msgPart,
Author: &discordgo.MessageEmbedAuthor{
Name: msg.Username,
IconURL: msg.Avatar,
},
},
},
AllowedMentions: b.getAllowedMentions(),
}

View File

@@ -46,6 +46,7 @@ func (b *Bdiscord) maybeGetLocalAvatar(msg *config.Message) string {
func (b *Bdiscord) webhookSendTextOnly(msg *config.Message, channelID string) (string, error) {
msgParts := helper.ClipOrSplitMessage(msg.Text, MessageLength, b.GetString("MessageClipped"), b.GetInt("MessageSplitMaxCount"))
msgIds := []string{}
b.Log.Debugf("Final avatar URL: %s", msg.Avatar)
for _, msgPart := range msgParts {
res, err := b.transmitter.Send(
channelID,

View File

@@ -1,7 +1,9 @@
package bxmpp
import (
"bufio"
"regexp"
"strings"
"github.com/42wim/matterbridge/bridge/config"
)
@@ -28,3 +30,23 @@ func (b *Bxmpp) cacheAvatar(msg *config.Message) string {
}
return ""
}
func trimLeadingQuotedLines(s string) string {
scanner := bufio.NewScanner(strings.NewReader(s))
var builder strings.Builder
skipping := true
for scanner.Scan() {
line := scanner.Text()
if skipping {
if strings.HasPrefix(line, "> ") {
// still skipping
continue
}
skipping = false
}
builder.WriteString(line + "\n")
}
return strings.TrimRight(builder.String(), "\n")
}

View File

@@ -14,6 +14,7 @@ import (
"github.com/42wim/matterbridge/bridge"
"github.com/42wim/matterbridge/bridge/config"
"github.com/42wim/matterbridge/bridge/helper"
lru "github.com/hashicorp/golang-lru"
"github.com/jpillora/backoff"
"github.com/matterbridge/go-xmpp"
"github.com/rs/xid"
@@ -28,13 +29,20 @@ type Bxmpp struct {
connected bool
sync.RWMutex
StanzaIDs *lru.Cache
OriginIDs *lru.Cache
avatarAvailability map[string]bool
avatarMap map[string]string
}
func New(cfg *bridge.Config) bridge.Bridger {
stanzaIDs, _ := lru.New(5000)
originIDs, _ := lru.New(5000)
return &Bxmpp{
Config: cfg,
StanzaIDs: stanzaIDs,
OriginIDs: originIDs,
xmppMap: make(map[string]string),
avatarAvailability: make(map[string]bool),
avatarMap: make(map[string]string),
@@ -124,12 +132,20 @@ func (b *Bxmpp) Send(msg config.Message) (string, error) {
return "", nil
}
if msg.ParentNotFound() {
msg.ParentID = ""
}
// Post normal message.
var msgReplaceID string
msgID := xid.New().String()
if msg.ID != "" {
msgReplaceID = msg.ID
}
var replyID string
if res, ok := b.StanzaIDs.Get(msg.ParentID); ok {
replyID, _ = res.(string)
}
b.Log.Debugf("=> Sending message %#v", msg)
if _, err := b.xc.Send(xmpp.Chat{
Type: "groupchat",
@@ -137,6 +153,7 @@ func (b *Bxmpp) Send(msg config.Message) (string, error) {
Text: msg.Username + msg.Text,
ID: msgID,
ReplaceID: msgReplaceID,
ReplyID: replyID,
}); err != nil {
return "", err
}
@@ -297,6 +314,11 @@ func (b *Bxmpp) handleXMPP() error {
if v.Type == "groupchat" {
b.Log.Debugf("== Receiving %#v", v)
if v.ID != "" && v.StanzaID != "" {
b.StanzaIDs.Add(v.ID, v.StanzaID)
b.OriginIDs.Add(v.StanzaID, v.ID)
}
// Skip invalid messages.
if b.skipMessage(v) {
continue
@@ -321,6 +343,13 @@ func (b *Bxmpp) handleXMPP() error {
if v.ReplaceID != "" {
msgID = v.ReplaceID
}
var parentID string
if res, ok := b.OriginIDs.Get(v.ReplyID); ok {
parentID, _ = res.(string)
v.Text = trimLeadingQuotedLines(v.Text)
}
rmsg := config.Message{
Username: b.parseNick(v.Remote),
Text: v.Text,
@@ -328,6 +357,7 @@ func (b *Bxmpp) handleXMPP() error {
Account: b.Account,
Avatar: avatar,
UserID: v.Remote,
ParentID: parentID,
ID: msgID,
Event: event,
}

3
go.mod
View File

@@ -6,7 +6,7 @@ require (
github.com/Philipp15b/go-steam v1.0.1-0.20200727090957-6ae9b3c0a560
github.com/Rhymen/go-whatsapp v0.1.2-0.20211102134409-31a2e740845c
github.com/SevereCloud/vksdk/v2 v2.17.0
github.com/bwmarrin/discordgo v0.28.1
github.com/bwmarrin/discordgo v0.29.0
github.com/d5/tengo/v2 v2.17.0
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc
github.com/fsnotify/fsnotify v1.7.0
@@ -149,5 +149,6 @@ require (
)
//replace github.com/matrix-org/gomatrix => github.com/matterbridge/gomatrix v0.0.0-20220205235239-607eb9ee6419
replace github.com/matterbridge/go-xmpp => "/home/irc-discord/uwaru-go-xmpp"
go 1.22.0

2
go.sum
View File

@@ -44,6 +44,8 @@ github.com/bufbuild/protocompile v0.4.0/go.mod h1:3v93+mbWn/v3xzN+31nwkJfrEpAUwp
github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s=
github.com/bwmarrin/discordgo v0.28.1 h1:gXsuo2GBO7NbR6uqmrrBDplPUx2T3nzu775q/Rd1aG4=
github.com/bwmarrin/discordgo v0.28.1/go.mod h1:NJZpH+1AfhIcyQsPeuBKsUtYrRnjkyu0kIVMCHkZtRY=
github.com/bwmarrin/discordgo v0.29.0 h1:FmWeXFaKUwrcL3Cx65c20bTRW+vOb6k8AnaP+EgjDno=
github.com/bwmarrin/discordgo v0.29.0/go.mod h1:NJZpH+1AfhIcyQsPeuBKsUtYrRnjkyu0kIVMCHkZtRY=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=

View File

@@ -18,6 +18,13 @@ const (
RoleSelectMenuComponent ComponentType = 6
MentionableSelectMenuComponent ComponentType = 7
ChannelSelectMenuComponent ComponentType = 8
SectionComponent ComponentType = 9
TextDisplayComponent ComponentType = 10
ThumbnailComponent ComponentType = 11
MediaGalleryComponent ComponentType = 12
FileComponentType ComponentType = 13
SeparatorComponent ComponentType = 14
ContainerComponent ComponentType = 17
)
// MessageComponent is a base interface for all message components.
@@ -50,6 +57,20 @@ func (umc *unmarshalableMessageComponent) UnmarshalJSON(src []byte) error {
umc.MessageComponent = &SelectMenu{}
case TextInputComponent:
umc.MessageComponent = &TextInput{}
case SectionComponent:
umc.MessageComponent = &Section{}
case TextDisplayComponent:
umc.MessageComponent = &TextDisplay{}
case ThumbnailComponent:
umc.MessageComponent = &Thumbnail{}
case MediaGalleryComponent:
umc.MessageComponent = &MediaGallery{}
case FileComponentType:
umc.MessageComponent = &FileComponent{}
case SeparatorComponent:
umc.MessageComponent = &Separator{}
case ContainerComponent:
umc.MessageComponent = &Container{}
default:
return fmt.Errorf("unknown component type: %d", v.Type)
}
@@ -66,9 +87,13 @@ func MessageComponentFromJSON(b []byte) (MessageComponent, error) {
return u.MessageComponent, nil
}
// ActionsRow is a container for components within one row.
// ActionsRow is a top-level container component for displaying a row of interactive components.
type ActionsRow struct {
// Can contain Button, SelectMenu and TextInput.
// NOTE: maximum of 5.
Components []MessageComponent `json:"components"`
// Unique identifier for the component; auto populated through increment if not provided.
ID int `json:"id,omitempty"`
}
// MarshalJSON is a method for marshaling ActionsRow to a JSON object.
@@ -86,13 +111,17 @@ func (r ActionsRow) MarshalJSON() ([]byte, error) {
// UnmarshalJSON is a helper function to unmarshal Actions Row.
func (r *ActionsRow) UnmarshalJSON(data []byte) error {
type actionsRow ActionsRow
var v struct {
actionsRow
RawComponents []unmarshalableMessageComponent `json:"components"`
}
err := json.Unmarshal(data, &v)
if err != nil {
return err
}
*r = ActionsRow(v.actionsRow)
r.Components = make([]MessageComponent, len(v.RawComponents))
for i, v := range v.RawComponents {
r.Components[i] = v.MessageComponent
@@ -121,6 +150,8 @@ const (
DangerButton ButtonStyle = 4
// LinkButton is a special type of button which navigates to a URL. Has grey color.
LinkButton ButtonStyle = 5
// PremiumButton is a special type of button with a blurple color that links to a SKU.
PremiumButton ButtonStyle = 6
)
// ComponentEmoji represents button emoji, if it does have one.
@@ -140,6 +171,10 @@ type Button struct {
// NOTE: Only button with LinkButton style can have link. Also, URL is mutually exclusive with CustomID.
URL string `json:"url,omitempty"`
CustomID string `json:"custom_id,omitempty"`
// Identifier for a purchasable SKU. Only available when using premium-style buttons.
SKUID string `json:"sku_id,omitempty"`
// Unique identifier for the component; auto populated through increment if not provided.
ID int `json:"id,omitempty"`
}
// MarshalJSON is a method for marshaling Button to a JSON object.
@@ -226,6 +261,9 @@ type SelectMenu struct {
// NOTE: Can only be used in SelectMenu with Channel menu type.
ChannelTypes []ChannelType `json:"channel_types,omitempty"`
// Unique identifier for the component; auto populated through increment if not provided.
ID int `json:"id,omitempty"`
}
// Type is a method to get the type of a component.
@@ -259,6 +297,9 @@ type TextInput struct {
Required bool `json:"required"`
MinLength int `json:"min_length,omitempty"`
MaxLength int `json:"max_length,omitempty"`
// Unique identifier for the component; auto populated through increment if not provided.
ID int `json:"id,omitempty"`
}
// Type is a method to get the type of a component.
@@ -287,3 +328,277 @@ const (
TextInputShort TextInputStyle = 1
TextInputParagraph TextInputStyle = 2
)
// Section is a top-level layout component that allows you to join text contextually with an accessory.
type Section struct {
// Unique identifier for the component; auto populated through increment if not provided.
ID int `json:"id,omitempty"`
// Array of text display components; max of 3.
Components []MessageComponent `json:"components"`
// Can be Button or Thumbnail
Accessory MessageComponent `json:"accessory"`
}
// UnmarshalJSON is a method for unmarshaling Section from JSON
func (s *Section) UnmarshalJSON(data []byte) error {
type section Section
var v struct {
section
RawComponents []unmarshalableMessageComponent `json:"components"`
RawAccessory unmarshalableMessageComponent `json:"accessory"`
}
err := json.Unmarshal(data, &v)
if err != nil {
return err
}
*s = Section(v.section)
s.Accessory = v.RawAccessory.MessageComponent
s.Components = make([]MessageComponent, len(v.RawComponents))
for i, v := range v.RawComponents {
s.Components[i] = v.MessageComponent
}
return nil
}
// Type is a method to get the type of a component.
func (Section) Type() ComponentType {
return SectionComponent
}
// MarshalJSON is a method for marshaling Section to a JSON object.
func (s Section) MarshalJSON() ([]byte, error) {
type section Section
return Marshal(struct {
section
Type ComponentType `json:"type"`
}{
section: section(s),
Type: s.Type(),
})
}
// TextDisplay is a top-level component that allows you to add markdown-formatted text to the message.
type TextDisplay struct {
Content string `json:"content"`
}
// Type is a method to get the type of a component.
func (TextDisplay) Type() ComponentType {
return TextDisplayComponent
}
// MarshalJSON is a method for marshaling TextDisplay to a JSON object.
func (t TextDisplay) MarshalJSON() ([]byte, error) {
type textDisplay TextDisplay
return Marshal(struct {
textDisplay
Type ComponentType `json:"type"`
}{
textDisplay: textDisplay(t),
Type: t.Type(),
})
}
// Thumbnail component can be used as an accessory for a section component.
type Thumbnail struct {
// Unique identifier for the component; auto populated through increment if not provided.
ID int `json:"id,omitempty"`
Media UnfurledMediaItem `json:"media"`
Description *string `json:"description,omitempty"`
Spoiler bool `json:"spoiler,omitemoty"`
}
// Type is a method to get the type of a component.
func (Thumbnail) Type() ComponentType {
return ThumbnailComponent
}
// MarshalJSON is a method for marshaling Thumbnail to a JSON object.
func (t Thumbnail) MarshalJSON() ([]byte, error) {
type thumbnail Thumbnail
return Marshal(struct {
thumbnail
Type ComponentType `json:"type"`
}{
thumbnail: thumbnail(t),
Type: t.Type(),
})
}
// MediaGallery is a top-level component allows you to group images, videos or gifs into a gallery grid.
type MediaGallery struct {
// Unique identifier for the component; auto populated through increment if not provided.
ID int `json:"id,omitempty"`
// Array of media gallery items; max of 10.
Items []MediaGalleryItem `json:"items"`
}
// Type is a method to get the type of a component.
func (MediaGallery) Type() ComponentType {
return MediaGalleryComponent
}
// MarshalJSON is a method for marshaling MediaGallery to a JSON object.
func (m MediaGallery) MarshalJSON() ([]byte, error) {
type mediaGallery MediaGallery
return Marshal(struct {
mediaGallery
Type ComponentType `json:"type"`
}{
mediaGallery: mediaGallery(m),
Type: m.Type(),
})
}
// MediaGalleryItem represents an item used in MediaGallery.
type MediaGalleryItem struct {
Media UnfurledMediaItem `json:"media"`
Description *string `json:"description,omitempty"`
Spoiler bool `json:"spoiler"`
}
// FileComponent is a top-level component that allows you to display an uploaded file as an attachment to the message and reference it in the component.
type FileComponent struct {
// Unique identifier for the component; auto populated through increment if not provided.
ID int `json:"id,omitempty"`
File UnfurledMediaItem `json:"file"`
Spoiler bool `json:"spoiler"`
}
// Type is a method to get the type of a component.
func (FileComponent) Type() ComponentType {
return FileComponentType
}
// MarshalJSON is a method for marshaling FileComponent to a JSON object.
func (f FileComponent) MarshalJSON() ([]byte, error) {
type fileComponent FileComponent
return Marshal(struct {
fileComponent
Type ComponentType `json:"type"`
}{
fileComponent: fileComponent(f),
Type: f.Type(),
})
}
// SeparatorSpacingSize represents spacing size around the separator.
type SeparatorSpacingSize uint
// Separator spacing sizes.
const (
SeparatorSpacingSizeSmall SeparatorSpacingSize = 1
SeparatorSpacingSizeLarge SeparatorSpacingSize = 2
)
// Separator is a top-level layout component that adds vertical padding and visual division between other components.
type Separator struct {
// Unique identifier for the component; auto populated through increment if not provided.
ID int `json:"id,omitempty"`
Divider *bool `json:"divider,omitempty"`
Spacing *SeparatorSpacingSize `json:"spacing,omitempty"`
}
// Type is a method to get the type of a component.
func (Separator) Type() ComponentType {
return SeparatorComponent
}
// MarshalJSON is a method for marshaling Separator to a JSON object.
func (s Separator) MarshalJSON() ([]byte, error) {
type separator Separator
return Marshal(struct {
separator
Type ComponentType `json:"type"`
}{
separator: separator(s),
Type: s.Type(),
})
}
// Container is a top-level layout component.
// Containers are visually distinct from surrounding components and have an optional customizable color bar (similar to embeds).
type Container struct {
// Unique identifier for the component; auto populated through increment if not provided.
ID int `json:"id,omitempty"`
AccentColor *int `json:"accent_color,omitempty"`
Spoiler bool `json:"spoiler"`
Components []MessageComponent `json:"components"`
}
// Type is a method to get the type of a component.
func (Container) Type() ComponentType {
return ContainerComponent
}
// UnmarshalJSON is a method for unmarshaling Container from JSON
func (c *Container) UnmarshalJSON(data []byte) error {
type container Container
var v struct {
container
RawComponents []unmarshalableMessageComponent `json:"components"`
}
err := json.Unmarshal(data, &v)
if err != nil {
return err
}
*c = Container(v.container)
c.Components = make([]MessageComponent, len(v.RawComponents))
for i, v := range v.RawComponents {
c.Components[i] = v.MessageComponent
}
return nil
}
// MarshalJSON is a method for marshaling Container to a JSON object.
func (c Container) MarshalJSON() ([]byte, error) {
type container Container
return Marshal(struct {
container
Type ComponentType `json:"type"`
}{
container: container(c),
Type: c.Type(),
})
}
// UnfurledMediaItem represents an unfurled media item.
type UnfurledMediaItem struct {
URL string `json:"url"`
}
// UnfurledMediaItemLoadingState is the loading state of the unfurled media item.
type UnfurledMediaItemLoadingState uint
// Unfurled media item loading states.
const (
UnfurledMediaItemLoadingStateUnknown UnfurledMediaItemLoadingState = 0
UnfurledMediaItemLoadingStateLoading UnfurledMediaItemLoadingState = 1
UnfurledMediaItemLoadingStateLoadingSuccess UnfurledMediaItemLoadingState = 2
UnfurledMediaItemLoadingStateLoadedNotFound UnfurledMediaItemLoadingState = 3
)
// ResolvedUnfurledMediaItem represents a resolved unfurled media item.
type ResolvedUnfurledMediaItem struct {
URL string `json:"url"`
ProxyURL string `json:"proxy_url"`
Width int `json:"width"`
Height int `json:"height"`
ContentType string `json:"content_type"`
}

View File

@@ -22,7 +22,7 @@ import (
)
// VERSION of DiscordGo, follows Semantic Versioning. (http://semver.org/)
const VERSION = "0.28.1"
const VERSION = "0.29.0"
// New creates a new Discord session with provided token.
// If the token is for a bot, it must be prefixed with "Bot "

View File

@@ -33,6 +33,7 @@ var (
EndpointWebhooks = EndpointAPI + "webhooks/"
EndpointStickers = EndpointAPI + "stickers/"
EndpointStageInstances = EndpointAPI + "stage-instances"
EndpointSKUs = EndpointAPI + "skus"
EndpointCDN = "https://cdn.discordapp.com/"
EndpointCDNAttachments = EndpointCDN + "attachments/"
@@ -114,6 +115,12 @@ var (
EndpointGuildMemberAvatarAnimated = func(gId, uID, aID string) string {
return EndpointCDNGuilds + gId + "/users/" + uID + "/avatars/" + aID + ".gif"
}
EndpointGuildMemberBanner = func(gId, uID, hash string) string {
return EndpointCDNGuilds + gId + "/users/" + uID + "/banners/" + hash + ".png"
}
EndpointGuildMemberBannerAnimated = func(gId, uID, hash string) string {
return EndpointCDNGuilds + gId + "/users/" + uID + "/banners/" + hash + ".gif"
}
EndpointRoleIcon = func(rID, hash string) string {
return EndpointCDNRoleIcons + rID + "/" + hash + ".png"
@@ -162,6 +169,37 @@ var (
return EndpointMessageReactions(cID, mID, eID) + "/" + uID
}
EndpointPoll = func(cID, mID string) string {
return EndpointChannel(cID) + "/polls/" + mID
}
EndpointPollAnswerVoters = func(cID, mID string, aID int) string {
return EndpointPoll(cID, mID) + "/answers/" + strconv.Itoa(aID)
}
EndpointPollExpire = func(cID, mID string) string {
return EndpointPoll(cID, mID) + "/expire"
}
EndpointApplicationSKUs = func(aID string) string {
return EndpointApplication(aID) + "/skus"
}
EndpointEntitlements = func(aID string) string {
return EndpointApplication(aID) + "/entitlements"
}
EndpointEntitlement = func(aID, eID string) string {
return EndpointEntitlements(aID) + "/" + eID
}
EndpointEntitlementConsume = func(aID, eID string) string {
return EndpointEntitlement(aID, eID) + "/consume"
}
EndpointSubscriptions = func(skuID string) string {
return EndpointSKUs + "/" + skuID + "/subscriptions"
}
EndpointSubscription = func(skuID, subID string) string {
return EndpointSubscriptions(skuID) + "/" + subID
}
EndpointApplicationGlobalCommands = func(aID string) string {
return EndpointApplication(aID) + "/commands"
}
@@ -208,6 +246,9 @@ var (
EndpointApplication = func(aID string) string { return EndpointApplications + "/" + aID }
EndpointApplicationRoleConnectionMetadata = func(aID string) string { return EndpointApplication(aID) + "/role-connections/metadata" }
EndpointApplicationEmojis = func(aID string) string { return EndpointApplication(aID) + "/emojis" }
EndpointApplicationEmoji = func(aID, eID string) string { return EndpointApplication(aID) + "/emojis/" + eID }
EndpointOAuth2 = EndpointAPI + "oauth2/"
EndpointOAuth2Applications = EndpointOAuth2 + "applications"
EndpointOAuth2Application = func(aID string) string { return EndpointOAuth2Applications + "/" + aID }

View File

@@ -18,6 +18,9 @@ const (
channelUpdateEventType = "CHANNEL_UPDATE"
connectEventType = "__CONNECT__"
disconnectEventType = "__DISCONNECT__"
entitlementCreateEventType = "ENTITLEMENT_CREATE"
entitlementDeleteEventType = "ENTITLEMENT_DELETE"
entitlementUpdateEventType = "ENTITLEMENT_UPDATE"
eventEventType = "__EVENT__"
guildAuditLogEntryCreateEventType = "GUILD_AUDIT_LOG_ENTRY_CREATE"
guildBanAddEventType = "GUILD_BAN_ADD"
@@ -38,13 +41,19 @@ const (
guildScheduledEventUpdateEventType = "GUILD_SCHEDULED_EVENT_UPDATE"
guildScheduledEventUserAddEventType = "GUILD_SCHEDULED_EVENT_USER_ADD"
guildScheduledEventUserRemoveEventType = "GUILD_SCHEDULED_EVENT_USER_REMOVE"
guildStickersUpdateEventType = "GUILD_STICKERS_UPDATE"
guildUpdateEventType = "GUILD_UPDATE"
integrationCreateEventType = "INTEGRATION_CREATE"
integrationDeleteEventType = "INTEGRATION_DELETE"
integrationUpdateEventType = "INTEGRATION_UPDATE"
interactionCreateEventType = "INTERACTION_CREATE"
inviteCreateEventType = "INVITE_CREATE"
inviteDeleteEventType = "INVITE_DELETE"
messageCreateEventType = "MESSAGE_CREATE"
messageDeleteEventType = "MESSAGE_DELETE"
messageDeleteBulkEventType = "MESSAGE_DELETE_BULK"
messagePollVoteAddEventType = "MESSAGE_POLL_VOTE_ADD"
messagePollVoteRemoveEventType = "MESSAGE_POLL_VOTE_REMOVE"
messageReactionAddEventType = "MESSAGE_REACTION_ADD"
messageReactionRemoveEventType = "MESSAGE_REACTION_REMOVE"
messageReactionRemoveAllEventType = "MESSAGE_REACTION_REMOVE_ALL"
@@ -57,6 +66,9 @@ const (
stageInstanceEventCreateEventType = "STAGE_INSTANCE_EVENT_CREATE"
stageInstanceEventDeleteEventType = "STAGE_INSTANCE_EVENT_DELETE"
stageInstanceEventUpdateEventType = "STAGE_INSTANCE_EVENT_UPDATE"
subscriptionCreateEventType = "SUBSCRIPTION_CREATE"
subscriptionDeleteEventType = "SUBSCRIPTION_DELETE"
subscriptionUpdateEventType = "SUBSCRIPTION_UPDATE"
threadCreateEventType = "THREAD_CREATE"
threadDeleteEventType = "THREAD_DELETE"
threadListSyncEventType = "THREAD_LIST_SYNC"
@@ -280,6 +292,66 @@ func (eh disconnectEventHandler) Handle(s *Session, i interface{}) {
}
}
// entitlementCreateEventHandler is an event handler for EntitlementCreate events.
type entitlementCreateEventHandler func(*Session, *EntitlementCreate)
// Type returns the event type for EntitlementCreate events.
func (eh entitlementCreateEventHandler) Type() string {
return entitlementCreateEventType
}
// New returns a new instance of EntitlementCreate.
func (eh entitlementCreateEventHandler) New() interface{} {
return &EntitlementCreate{}
}
// Handle is the handler for EntitlementCreate events.
func (eh entitlementCreateEventHandler) Handle(s *Session, i interface{}) {
if t, ok := i.(*EntitlementCreate); ok {
eh(s, t)
}
}
// entitlementDeleteEventHandler is an event handler for EntitlementDelete events.
type entitlementDeleteEventHandler func(*Session, *EntitlementDelete)
// Type returns the event type for EntitlementDelete events.
func (eh entitlementDeleteEventHandler) Type() string {
return entitlementDeleteEventType
}
// New returns a new instance of EntitlementDelete.
func (eh entitlementDeleteEventHandler) New() interface{} {
return &EntitlementDelete{}
}
// Handle is the handler for EntitlementDelete events.
func (eh entitlementDeleteEventHandler) Handle(s *Session, i interface{}) {
if t, ok := i.(*EntitlementDelete); ok {
eh(s, t)
}
}
// entitlementUpdateEventHandler is an event handler for EntitlementUpdate events.
type entitlementUpdateEventHandler func(*Session, *EntitlementUpdate)
// Type returns the event type for EntitlementUpdate events.
func (eh entitlementUpdateEventHandler) Type() string {
return entitlementUpdateEventType
}
// New returns a new instance of EntitlementUpdate.
func (eh entitlementUpdateEventHandler) New() interface{} {
return &EntitlementUpdate{}
}
// Handle is the handler for EntitlementUpdate events.
func (eh entitlementUpdateEventHandler) Handle(s *Session, i interface{}) {
if t, ok := i.(*EntitlementUpdate); ok {
eh(s, t)
}
}
// eventEventHandler is an event handler for Event events.
type eventEventHandler func(*Session, *Event)
@@ -675,6 +747,26 @@ func (eh guildScheduledEventUserRemoveEventHandler) Handle(s *Session, i interfa
}
}
// guildStickersUpdateEventHandler is an event handler for GuildStickersUpdate events.
type guildStickersUpdateEventHandler func(*Session, *GuildStickersUpdate)
// Type returns the event type for GuildStickersUpdate events.
func (eh guildStickersUpdateEventHandler) Type() string {
return guildStickersUpdateEventType
}
// New returns a new instance of GuildStickersUpdate.
func (eh guildStickersUpdateEventHandler) New() interface{} {
return &GuildStickersUpdate{}
}
// Handle is the handler for GuildStickersUpdate events.
func (eh guildStickersUpdateEventHandler) Handle(s *Session, i interface{}) {
if t, ok := i.(*GuildStickersUpdate); ok {
eh(s, t)
}
}
// guildUpdateEventHandler is an event handler for GuildUpdate events.
type guildUpdateEventHandler func(*Session, *GuildUpdate)
@@ -695,6 +787,66 @@ func (eh guildUpdateEventHandler) Handle(s *Session, i interface{}) {
}
}
// integrationCreateEventHandler is an event handler for IntegrationCreate events.
type integrationCreateEventHandler func(*Session, *IntegrationCreate)
// Type returns the event type for IntegrationCreate events.
func (eh integrationCreateEventHandler) Type() string {
return integrationCreateEventType
}
// New returns a new instance of IntegrationCreate.
func (eh integrationCreateEventHandler) New() interface{} {
return &IntegrationCreate{}
}
// Handle is the handler for IntegrationCreate events.
func (eh integrationCreateEventHandler) Handle(s *Session, i interface{}) {
if t, ok := i.(*IntegrationCreate); ok {
eh(s, t)
}
}
// integrationDeleteEventHandler is an event handler for IntegrationDelete events.
type integrationDeleteEventHandler func(*Session, *IntegrationDelete)
// Type returns the event type for IntegrationDelete events.
func (eh integrationDeleteEventHandler) Type() string {
return integrationDeleteEventType
}
// New returns a new instance of IntegrationDelete.
func (eh integrationDeleteEventHandler) New() interface{} {
return &IntegrationDelete{}
}
// Handle is the handler for IntegrationDelete events.
func (eh integrationDeleteEventHandler) Handle(s *Session, i interface{}) {
if t, ok := i.(*IntegrationDelete); ok {
eh(s, t)
}
}
// integrationUpdateEventHandler is an event handler for IntegrationUpdate events.
type integrationUpdateEventHandler func(*Session, *IntegrationUpdate)
// Type returns the event type for IntegrationUpdate events.
func (eh integrationUpdateEventHandler) Type() string {
return integrationUpdateEventType
}
// New returns a new instance of IntegrationUpdate.
func (eh integrationUpdateEventHandler) New() interface{} {
return &IntegrationUpdate{}
}
// Handle is the handler for IntegrationUpdate events.
func (eh integrationUpdateEventHandler) Handle(s *Session, i interface{}) {
if t, ok := i.(*IntegrationUpdate); ok {
eh(s, t)
}
}
// interactionCreateEventHandler is an event handler for InteractionCreate events.
type interactionCreateEventHandler func(*Session, *InteractionCreate)
@@ -815,6 +967,46 @@ func (eh messageDeleteBulkEventHandler) Handle(s *Session, i interface{}) {
}
}
// messagePollVoteAddEventHandler is an event handler for MessagePollVoteAdd events.
type messagePollVoteAddEventHandler func(*Session, *MessagePollVoteAdd)
// Type returns the event type for MessagePollVoteAdd events.
func (eh messagePollVoteAddEventHandler) Type() string {
return messagePollVoteAddEventType
}
// New returns a new instance of MessagePollVoteAdd.
func (eh messagePollVoteAddEventHandler) New() interface{} {
return &MessagePollVoteAdd{}
}
// Handle is the handler for MessagePollVoteAdd events.
func (eh messagePollVoteAddEventHandler) Handle(s *Session, i interface{}) {
if t, ok := i.(*MessagePollVoteAdd); ok {
eh(s, t)
}
}
// messagePollVoteRemoveEventHandler is an event handler for MessagePollVoteRemove events.
type messagePollVoteRemoveEventHandler func(*Session, *MessagePollVoteRemove)
// Type returns the event type for MessagePollVoteRemove events.
func (eh messagePollVoteRemoveEventHandler) Type() string {
return messagePollVoteRemoveEventType
}
// New returns a new instance of MessagePollVoteRemove.
func (eh messagePollVoteRemoveEventHandler) New() interface{} {
return &MessagePollVoteRemove{}
}
// Handle is the handler for MessagePollVoteRemove events.
func (eh messagePollVoteRemoveEventHandler) Handle(s *Session, i interface{}) {
if t, ok := i.(*MessagePollVoteRemove); ok {
eh(s, t)
}
}
// messageReactionAddEventHandler is an event handler for MessageReactionAdd events.
type messageReactionAddEventHandler func(*Session, *MessageReactionAdd)
@@ -1050,6 +1242,66 @@ func (eh stageInstanceEventUpdateEventHandler) Handle(s *Session, i interface{})
}
}
// subscriptionCreateEventHandler is an event handler for SubscriptionCreate events.
type subscriptionCreateEventHandler func(*Session, *SubscriptionCreate)
// Type returns the event type for SubscriptionCreate events.
func (eh subscriptionCreateEventHandler) Type() string {
return subscriptionCreateEventType
}
// New returns a new instance of SubscriptionCreate.
func (eh subscriptionCreateEventHandler) New() interface{} {
return &SubscriptionCreate{}
}
// Handle is the handler for SubscriptionCreate events.
func (eh subscriptionCreateEventHandler) Handle(s *Session, i interface{}) {
if t, ok := i.(*SubscriptionCreate); ok {
eh(s, t)
}
}
// subscriptionDeleteEventHandler is an event handler for SubscriptionDelete events.
type subscriptionDeleteEventHandler func(*Session, *SubscriptionDelete)
// Type returns the event type for SubscriptionDelete events.
func (eh subscriptionDeleteEventHandler) Type() string {
return subscriptionDeleteEventType
}
// New returns a new instance of SubscriptionDelete.
func (eh subscriptionDeleteEventHandler) New() interface{} {
return &SubscriptionDelete{}
}
// Handle is the handler for SubscriptionDelete events.
func (eh subscriptionDeleteEventHandler) Handle(s *Session, i interface{}) {
if t, ok := i.(*SubscriptionDelete); ok {
eh(s, t)
}
}
// subscriptionUpdateEventHandler is an event handler for SubscriptionUpdate events.
type subscriptionUpdateEventHandler func(*Session, *SubscriptionUpdate)
// Type returns the event type for SubscriptionUpdate events.
func (eh subscriptionUpdateEventHandler) Type() string {
return subscriptionUpdateEventType
}
// New returns a new instance of SubscriptionUpdate.
func (eh subscriptionUpdateEventHandler) New() interface{} {
return &SubscriptionUpdate{}
}
// Handle is the handler for SubscriptionUpdate events.
func (eh subscriptionUpdateEventHandler) Handle(s *Session, i interface{}) {
if t, ok := i.(*SubscriptionUpdate); ok {
eh(s, t)
}
}
// threadCreateEventHandler is an event handler for ThreadCreate events.
type threadCreateEventHandler func(*Session, *ThreadCreate)
@@ -1296,6 +1548,12 @@ func handlerForInterface(handler interface{}) EventHandler {
return connectEventHandler(v)
case func(*Session, *Disconnect):
return disconnectEventHandler(v)
case func(*Session, *EntitlementCreate):
return entitlementCreateEventHandler(v)
case func(*Session, *EntitlementDelete):
return entitlementDeleteEventHandler(v)
case func(*Session, *EntitlementUpdate):
return entitlementUpdateEventHandler(v)
case func(*Session, *Event):
return eventEventHandler(v)
case func(*Session, *GuildAuditLogEntryCreate):
@@ -1336,8 +1594,16 @@ func handlerForInterface(handler interface{}) EventHandler {
return guildScheduledEventUserAddEventHandler(v)
case func(*Session, *GuildScheduledEventUserRemove):
return guildScheduledEventUserRemoveEventHandler(v)
case func(*Session, *GuildStickersUpdate):
return guildStickersUpdateEventHandler(v)
case func(*Session, *GuildUpdate):
return guildUpdateEventHandler(v)
case func(*Session, *IntegrationCreate):
return integrationCreateEventHandler(v)
case func(*Session, *IntegrationDelete):
return integrationDeleteEventHandler(v)
case func(*Session, *IntegrationUpdate):
return integrationUpdateEventHandler(v)
case func(*Session, *InteractionCreate):
return interactionCreateEventHandler(v)
case func(*Session, *InviteCreate):
@@ -1350,6 +1616,10 @@ func handlerForInterface(handler interface{}) EventHandler {
return messageDeleteEventHandler(v)
case func(*Session, *MessageDeleteBulk):
return messageDeleteBulkEventHandler(v)
case func(*Session, *MessagePollVoteAdd):
return messagePollVoteAddEventHandler(v)
case func(*Session, *MessagePollVoteRemove):
return messagePollVoteRemoveEventHandler(v)
case func(*Session, *MessageReactionAdd):
return messageReactionAddEventHandler(v)
case func(*Session, *MessageReactionRemove):
@@ -1374,6 +1644,12 @@ func handlerForInterface(handler interface{}) EventHandler {
return stageInstanceEventDeleteEventHandler(v)
case func(*Session, *StageInstanceEventUpdate):
return stageInstanceEventUpdateEventHandler(v)
case func(*Session, *SubscriptionCreate):
return subscriptionCreateEventHandler(v)
case func(*Session, *SubscriptionDelete):
return subscriptionDeleteEventHandler(v)
case func(*Session, *SubscriptionUpdate):
return subscriptionUpdateEventHandler(v)
case func(*Session, *ThreadCreate):
return threadCreateEventHandler(v)
case func(*Session, *ThreadDelete):
@@ -1411,6 +1687,9 @@ func init() {
registerInterfaceProvider(channelDeleteEventHandler(nil))
registerInterfaceProvider(channelPinsUpdateEventHandler(nil))
registerInterfaceProvider(channelUpdateEventHandler(nil))
registerInterfaceProvider(entitlementCreateEventHandler(nil))
registerInterfaceProvider(entitlementDeleteEventHandler(nil))
registerInterfaceProvider(entitlementUpdateEventHandler(nil))
registerInterfaceProvider(guildAuditLogEntryCreateEventHandler(nil))
registerInterfaceProvider(guildBanAddEventHandler(nil))
registerInterfaceProvider(guildBanRemoveEventHandler(nil))
@@ -1430,13 +1709,19 @@ func init() {
registerInterfaceProvider(guildScheduledEventUpdateEventHandler(nil))
registerInterfaceProvider(guildScheduledEventUserAddEventHandler(nil))
registerInterfaceProvider(guildScheduledEventUserRemoveEventHandler(nil))
registerInterfaceProvider(guildStickersUpdateEventHandler(nil))
registerInterfaceProvider(guildUpdateEventHandler(nil))
registerInterfaceProvider(integrationCreateEventHandler(nil))
registerInterfaceProvider(integrationDeleteEventHandler(nil))
registerInterfaceProvider(integrationUpdateEventHandler(nil))
registerInterfaceProvider(interactionCreateEventHandler(nil))
registerInterfaceProvider(inviteCreateEventHandler(nil))
registerInterfaceProvider(inviteDeleteEventHandler(nil))
registerInterfaceProvider(messageCreateEventHandler(nil))
registerInterfaceProvider(messageDeleteEventHandler(nil))
registerInterfaceProvider(messageDeleteBulkEventHandler(nil))
registerInterfaceProvider(messagePollVoteAddEventHandler(nil))
registerInterfaceProvider(messagePollVoteRemoveEventHandler(nil))
registerInterfaceProvider(messageReactionAddEventHandler(nil))
registerInterfaceProvider(messageReactionRemoveEventHandler(nil))
registerInterfaceProvider(messageReactionRemoveAllEventHandler(nil))
@@ -1448,6 +1733,9 @@ func init() {
registerInterfaceProvider(stageInstanceEventCreateEventHandler(nil))
registerInterfaceProvider(stageInstanceEventDeleteEventHandler(nil))
registerInterfaceProvider(stageInstanceEventUpdateEventHandler(nil))
registerInterfaceProvider(subscriptionCreateEventHandler(nil))
registerInterfaceProvider(subscriptionDeleteEventHandler(nil))
registerInterfaceProvider(subscriptionUpdateEventHandler(nil))
registerInterfaceProvider(threadCreateEventHandler(nil))
registerInterfaceProvider(threadDeleteEventHandler(nil))
registerInterfaceProvider(threadListSyncEventHandler(nil))

View File

@@ -53,6 +53,7 @@ type ChannelCreate struct {
// ChannelUpdate is the data for a ChannelUpdate event.
type ChannelUpdate struct {
*Channel
BeforeUpdate *Channel `json:"-"`
}
// ChannelDelete is the data for a ChannelDelete event.
@@ -180,6 +181,12 @@ type GuildEmojisUpdate struct {
Emojis []*Emoji `json:"emojis"`
}
// A GuildStickersUpdate is the data for a GuildStickersUpdate event.
type GuildStickersUpdate struct {
GuildID string `json:"guild_id"`
Stickers []*Sticker `json:"stickers"`
}
// A GuildMembersChunk is the data for a GuildMembersChunk event.
type GuildMembersChunk struct {
GuildID string `json:"guild_id"`
@@ -240,6 +247,25 @@ type GuildScheduledEventUserRemove struct {
GuildID string `json:"guild_id"`
}
// IntegrationCreate is the data for a IntegrationCreate event.
type IntegrationCreate struct {
*Integration
GuildID string `json:"guild_id"`
}
// IntegrationUpdate is the data for a IntegrationUpdate event.
type IntegrationUpdate struct {
*Integration
GuildID string `json:"guild_id"`
}
// IntegrationDelete is the data for a IntegrationDelete event.
type IntegrationDelete struct {
ID string `json:"id"`
GuildID string `json:"guild_id"`
ApplicationID string `json:"application_id,omitempty"`
}
// MessageCreate is the data for a MessageCreate event.
type MessageCreate struct {
*Message
@@ -405,4 +431,57 @@ type AutoModerationActionExecution struct {
// GuildAuditLogEntryCreate is the data for a GuildAuditLogEntryCreate event.
type GuildAuditLogEntryCreate struct {
*AuditLogEntry
GuildID string `json:"guild_id"`
}
// MessagePollVoteAdd is the data for a MessagePollVoteAdd event.
type MessagePollVoteAdd struct {
UserID string `json:"user_id"`
ChannelID string `json:"channel_id"`
MessageID string `json:"message_id"`
GuildID string `json:"guild_id,omitempty"`
AnswerID int `json:"answer_id"`
}
// MessagePollVoteRemove is the data for a MessagePollVoteRemove event.
type MessagePollVoteRemove struct {
UserID string `json:"user_id"`
ChannelID string `json:"channel_id"`
MessageID string `json:"message_id"`
GuildID string `json:"guild_id,omitempty"`
AnswerID int `json:"answer_id"`
}
// EntitlementCreate is the data for an EntitlementCreate event.
type EntitlementCreate struct {
*Entitlement
}
// EntitlementUpdate is the data for an EntitlementUpdate event.
type EntitlementUpdate struct {
*Entitlement
}
// EntitlementDelete is the data for an EntitlementDelete event.
// NOTE: Entitlements are not deleted when they expire.
type EntitlementDelete struct {
*Entitlement
}
// SubscriptionCreate is the data for an SubscriptionCreate event.
// https://discord.com/developers/docs/monetization/implementing-app-subscriptions#using-subscription-events-for-the-subscription-lifecycle
type SubscriptionCreate struct {
*Subscription
}
// SubscriptionUpdate is the data for an SubscriptionUpdate event.
// https://discord.com/developers/docs/monetization/implementing-app-subscriptions#using-subscription-events-for-the-subscription-lifecycle
type SubscriptionUpdate struct {
*Subscription
}
// SubscriptionDelete is the data for an SubscriptionDelete event.
// https://discord.com/developers/docs/monetization/implementing-app-subscriptions#using-subscription-events-for-the-subscription-lifecycle
type SubscriptionDelete struct {
*Subscription
}

View File

@@ -38,12 +38,17 @@ type ApplicationCommand struct {
Type ApplicationCommandType `json:"type,omitempty"`
Name string `json:"name"`
NameLocalizations *map[Locale]string `json:"name_localizations,omitempty"`
// NOTE: DefaultPermission will be soon deprecated. Use DefaultMemberPermissions and DMPermission instead.
// NOTE: DefaultPermission will be soon deprecated. Use DefaultMemberPermissions and Contexts instead.
DefaultPermission *bool `json:"default_permission,omitempty"`
DefaultMemberPermissions *int64 `json:"default_member_permissions,string,omitempty"`
DMPermission *bool `json:"dm_permission,omitempty"`
NSFW *bool `json:"nsfw,omitempty"`
// Deprecated: use Contexts instead.
DMPermission *bool `json:"dm_permission,omitempty"`
Contexts *[]InteractionContextType `json:"contexts,omitempty"`
IntegrationTypes *[]ApplicationIntegrationType `json:"integration_types,omitempty"`
// NOTE: Chat commands only. Otherwise it mustn't be set.
Description string `json:"description,omitempty"`
@@ -200,6 +205,18 @@ func (t InteractionType) String() string {
return fmt.Sprintf("InteractionType(%d)", t)
}
// InteractionContextType represents the context in which interaction can be used or was triggered from.
type InteractionContextType uint
const (
// InteractionContextGuild indicates that interaction can be used within guilds.
InteractionContextGuild InteractionContextType = 0
// InteractionContextBotDM indicates that interaction can be used within DMs with the bot.
InteractionContextBotDM InteractionContextType = 1
// InteractionContextPrivateChannel indicates that interaction can be used within group DMs and DMs with other users.
InteractionContextPrivateChannel InteractionContextType = 2
)
// Interaction represents data of an interaction.
type Interaction struct {
ID string `json:"id"`
@@ -233,8 +250,15 @@ type Interaction struct {
// NOTE: this field is only filled when the interaction was invoked in a guild.
GuildLocale *Locale `json:"guild_locale"`
Context InteractionContextType `json:"context"`
AuthorizingIntegrationOwners map[ApplicationIntegrationType]string `json:"authorizing_integration_owners"`
Token string `json:"token"`
Version int `json:"version"`
// Any entitlements for the invoking user, representing access to premium SKUs.
// NOTE: this field is only filled in monetized apps
Entitlements []*Entitlement `json:"entitlements"`
}
type interaction Interaction
@@ -326,6 +350,18 @@ type ApplicationCommandInteractionData struct {
TargetID string `json:"target_id"`
}
// GetOption finds and returns an application command option by its name.
func (d ApplicationCommandInteractionData) GetOption(name string) (option *ApplicationCommandInteractionDataOption) {
for _, opt := range d.Options {
if opt.Name == name {
option = opt
break
}
}
return
}
// ApplicationCommandInteractionDataResolved contains resolved data of command execution.
// Partial Member objects are missing user, deaf and mute fields.
// Partial Channel objects only have id, name, type and permissions fields.
@@ -408,6 +444,18 @@ type ApplicationCommandInteractionDataOption struct {
Focused bool `json:"focused,omitempty"`
}
// GetOption finds and returns an application command option by its name.
func (o ApplicationCommandInteractionDataOption) GetOption(name string) (option *ApplicationCommandInteractionDataOption) {
for _, opt := range o.Options {
if opt.Name == name {
option = opt
break
}
}
return
}
// IntValue is a utility function for casting option value to integer
func (o ApplicationCommandInteractionDataOption) IntValue() int64 {
if o.Type != ApplicationCommandOptionInteger {
@@ -555,6 +603,7 @@ type InteractionResponseData struct {
AllowedMentions *MessageAllowedMentions `json:"allowed_mentions,omitempty"`
Files []*File `json:"-"`
Attachments *[]*MessageAttachment `json:"attachments,omitempty"`
Poll *Poll `json:"poll,omitempty"`
// NOTE: only MessageFlagsSuppressEmbeds and MessageFlagsEphemeral can be set.
Flags MessageFlags `json:"flags,omitempty"`

View File

@@ -135,11 +135,19 @@ type Message struct {
// If the field exists but is null, the referenced message was deleted.
ReferencedMessage *Message `json:"referenced_message"`
// The message associated with the message_reference.
// This is a minimal subset of fields in a message (e.g. Author is excluded)
// NOTE: This field is only returned when referenced when MessageReference.Type is MessageReferenceTypeForward.
MessageSnapshots []MessageSnapshot `json:"message_snapshots"`
// Deprecated, use InteractionMetadata.
// Is sent when the message is a response to an Interaction, without an existing message.
// This means responses to message component interactions do not include this property,
// instead including a MessageReference, as components exist on preexisting messages.
Interaction *MessageInteraction `json:"interaction"`
InteractionMetadata *MessageInteractionMetadata `json:"interaction_metadata"`
// The flags of the message, which describe extra features of a message.
// This is a combination of bit masks; the presence of a certain permission can
// be checked by performing a bitwise AND between this int and the flag.
@@ -150,6 +158,9 @@ type Message struct {
// An array of StickerItem objects, representing sent stickers, if there were any.
StickerItems []*StickerItem `json:"sticker_items"`
// A poll object.
Poll *Poll `json:"poll"`
}
// UnmarshalJSON is a helper function to unmarshal the Message.
@@ -219,6 +230,8 @@ const (
MessageFlagsSuppressNotifications MessageFlags = 1 << 12
// MessageFlagsIsVoiceMessage this message is a voice message.
MessageFlagsIsVoiceMessage MessageFlags = 1 << 13
// MessageFlagsIsComponentsV2 this message uses the new components system. Disables the ability of sending `content` & `embeds`
MessageFlagsIsComponentsV2 MessageFlags = 1 << 15
)
// File stores info about files you e.g. send in messages.
@@ -239,6 +252,7 @@ type MessageSend struct {
Reference *MessageReference `json:"message_reference,omitempty"`
StickerIDs []string `json:"sticker_ids"`
Flags MessageFlags `json:"flags,omitempty"`
Poll *Poll `json:"poll,omitempty"`
// TODO: Remove this when compatibility is not required.
File *File `json:"-"`
@@ -338,17 +352,28 @@ type MessageAllowedMentions struct {
// A MessageAttachment stores data for message attachments.
type MessageAttachment struct {
ID string `json:"id"`
URL string `json:"url"`
ProxyURL string `json:"proxy_url"`
Filename string `json:"filename"`
ContentType string `json:"content_type"`
Width int `json:"width"`
Height int `json:"height"`
Size int `json:"size"`
Ephemeral bool `json:"ephemeral"`
ID string `json:"id"`
URL string `json:"url"`
ProxyURL string `json:"proxy_url"`
Filename string `json:"filename"`
ContentType string `json:"content_type"`
Width int `json:"width"`
Height int `json:"height"`
Size int `json:"size"`
Ephemeral bool `json:"ephemeral"`
DurationSecs float64 `json:"duration_secs"`
Waveform string `json:"waveform"`
Flags MessageAttachmentFlags `json:"flags"`
}
// MessageAttachmentFlags is the flags of a message attachment.
type MessageAttachmentFlags int
// Valid MessageAttachmentFlags values.
const (
MessageAttachmentFlagsIsRemix MessageAttachmentFlags = 1 << 2
)
// MessageEmbedFooter is a part of a MessageEmbed struct.
type MessageEmbedFooter struct {
Text string `json:"text,omitempty"`
@@ -464,16 +489,34 @@ type MessageApplication struct {
Name string `json:"name"`
}
// MessageReference contains reference data sent with crossposted messages
type MessageReference struct {
MessageID string `json:"message_id"`
ChannelID string `json:"channel_id,omitempty"`
GuildID string `json:"guild_id,omitempty"`
FailIfNotExists *bool `json:"fail_if_not_exists,omitempty"`
// MessageSnapshot represents a snapshot of a forwarded message.
// https://discord.com/developers/docs/resources/message#message-snapshot-object
type MessageSnapshot struct {
Message *Message `json:"message"`
}
func (m *Message) reference(failIfNotExists bool) *MessageReference {
// MessageReferenceType is a type of MessageReference
type MessageReferenceType int
// Known valid MessageReferenceType values
// https://discord.com/developers/docs/resources/message#message-reference-types
const (
MessageReferenceTypeDefault MessageReferenceType = 0
MessageReferenceTypeForward MessageReferenceType = 1
)
// MessageReference contains reference data sent with crossposted messages
type MessageReference struct {
Type MessageReferenceType `json:"type,omitempty"`
MessageID string `json:"message_id"`
ChannelID string `json:"channel_id,omitempty"`
GuildID string `json:"guild_id,omitempty"`
FailIfNotExists *bool `json:"fail_if_not_exists,omitempty"`
}
func (m *Message) reference(refType MessageReferenceType, failIfNotExists bool) *MessageReference {
return &MessageReference{
Type: refType,
GuildID: m.GuildID,
ChannelID: m.ChannelID,
MessageID: m.ID,
@@ -483,13 +526,18 @@ func (m *Message) reference(failIfNotExists bool) *MessageReference {
// Reference returns a MessageReference of the given message.
func (m *Message) Reference() *MessageReference {
return m.reference(true)
return m.reference(MessageReferenceTypeDefault, true)
}
// SoftReference returns a MessageReference of the given message.
// If the message doesn't exist it will instead be sent as a non-reply message.
func (m *Message) SoftReference() *MessageReference {
return m.reference(false)
return m.reference(MessageReferenceTypeDefault, false)
}
// Forward returns a MessageReference for a forwarded message.
func (m *Message) Forward() *MessageReference {
return m.reference(MessageReferenceTypeForward, true)
}
// ContentWithMentionsReplaced will replace all @<id> mentions with the
@@ -567,3 +615,24 @@ type MessageInteraction struct {
// Member is only present when the interaction is from a guild.
Member *Member `json:"member"`
}
// MessageInteractionMetadata contains metadata of an interaction, including relevant user info.
type MessageInteractionMetadata struct {
// ID of the interaction.
ID string `json:"id"`
// Type of the interaction.
Type InteractionType `json:"type"`
// User who triggered the interaction.
User *User `json:"user"`
// IDs for installation context(s) related to an interaction.
AuthorizingIntegrationOwners map[ApplicationIntegrationType]string `json:"authorizing_integration_owners"`
// ID of the original response message.
// NOTE: present only on followup messages.
OriginalResponseMessageID string `json:"original_response_message_id,omitempty"`
// ID of the message that contained interactive component.
// NOTE: present only on message component interactions.
InteractedMessageID string `json:"interacted_message_id,omitempty"`
// Metadata for interaction that was used to open a modal.
// NOTE: present only on modal submit interactions.
TriggeringInteractionMetadata *MessageInteractionMetadata `json:"triggering_interaction_metadata,omitempty"`
}

View File

@@ -178,13 +178,14 @@ func (s *Session) RequestWithBucketID(method, urlStr string, data interface{}, b
}
}
return s.request(method, urlStr, "application/json", body, bucketID, 0, options...)
return s.RequestRaw(method, urlStr, "application/json", body, bucketID, 0, options...)
}
// request makes a (GET/POST/...) Requests to Discord REST API.
// RequestRaw makes a (GET/POST/...) Requests to Discord REST API.
// Preferably use the other Request* methods but this lets you send JSON directly if that's what you have.
// Sequence is the sequence number, if it fails with a 502 it will
// retry with sequence+1 until it either succeeds or sequence >= session.MaxRestRetries
func (s *Session) request(method, urlStr, contentType string, b []byte, bucketID string, sequence int, options ...RequestOption) (response []byte, err error) {
func (s *Session) RequestRaw(method, urlStr, contentType string, b []byte, bucketID string, sequence int, options ...RequestOption) (response []byte, err error) {
if bucketID == "" {
bucketID = strings.SplitN(urlStr, "?", 2)[0]
}
@@ -358,7 +359,7 @@ func (s *Session) UserAvatarDecode(u *User, options ...RequestOption) (img image
}
// UserUpdate updates current user settings.
func (s *Session) UserUpdate(username, avatar string, options ...RequestOption) (st *User, err error) {
func (s *Session) UserUpdate(username, avatar, banner string, options ...RequestOption) (st *User, err error) {
// NOTE: Avatar must be either the hash/id of existing Avatar or
// data:image/png;base64,BASE64_STRING_OF_NEW_AVATAR_PNG
@@ -368,7 +369,8 @@ func (s *Session) UserUpdate(username, avatar string, options ...RequestOption)
data := struct {
Username string `json:"username,omitempty"`
Avatar string `json:"avatar,omitempty"`
}{username, avatar}
Banner string `json:"banner,omitempty"`
}{username, avatar, banner}
body, err := s.RequestWithBucketID("PATCH", EndpointUser("@me"), data, EndpointUsers, options...)
if err != nil {
@@ -1011,7 +1013,7 @@ func (s *Session) GuildMemberRoleRemove(guildID, userID, roleID string, options
// guildID : The ID of a Guild.
func (s *Session) GuildChannels(guildID string, options ...RequestOption) (st []*Channel, err error) {
body, err := s.request("GET", EndpointGuildChannels(guildID), "", nil, EndpointGuildChannels(guildID), 0, options...)
body, err := s.RequestRaw("GET", EndpointGuildChannels(guildID), "", nil, EndpointGuildChannels(guildID), 0, options...)
if err != nil {
return
}
@@ -1453,6 +1455,76 @@ func (s *Session) GuildEmojiDelete(guildID, emojiID string, options ...RequestOp
return
}
// ApplicationEmojis returns all emojis for the given application
// appID : ID of the application
func (s *Session) ApplicationEmojis(appID string, options ...RequestOption) (emojis []*Emoji, err error) {
body, err := s.RequestWithBucketID("GET", EndpointApplicationEmojis(appID), nil, EndpointApplicationEmojis(appID), options...)
if err != nil {
return
}
var temp struct {
Items []*Emoji `json:"items"`
}
err = unmarshal(body, &temp)
if err != nil {
return
}
emojis = temp.Items
return
}
// ApplicationEmoji returns the emoji for the given application.
// appID : ID of the application
// emojiID : ID of an Emoji to retrieve
func (s *Session) ApplicationEmoji(appID, emojiID string, options ...RequestOption) (emoji *Emoji, err error) {
var body []byte
body, err = s.RequestWithBucketID("GET", EndpointApplicationEmoji(appID, emojiID), nil, EndpointApplicationEmoji(appID, emojiID), options...)
if err != nil {
return
}
err = unmarshal(body, &emoji)
return
}
// ApplicationEmojiCreate creates a new Emoji for the given application.
// appID : ID of the application
// data : New Emoji data
func (s *Session) ApplicationEmojiCreate(appID string, data *EmojiParams, options ...RequestOption) (emoji *Emoji, err error) {
body, err := s.RequestWithBucketID("POST", EndpointApplicationEmojis(appID), data, EndpointApplicationEmojis(appID), options...)
if err != nil {
return
}
err = unmarshal(body, &emoji)
return
}
// ApplicationEmojiEdit modifies and returns updated Emoji for the given application.
// appID : ID of the application
// emojiID : ID of an Emoji
// data : Updated Emoji data
func (s *Session) ApplicationEmojiEdit(appID string, emojiID string, data *EmojiParams, options ...RequestOption) (emoji *Emoji, err error) {
body, err := s.RequestWithBucketID("PATCH", EndpointApplicationEmoji(appID, emojiID), data, EndpointApplicationEmojis(appID), options...)
if err != nil {
return
}
err = unmarshal(body, &emoji)
return
}
// ApplicationEmojiDelete deletes an Emoji for the given application.
// appID : ID of the application
// emojiID : ID of an Emoji
func (s *Session) ApplicationEmojiDelete(appID, emojiID string, options ...RequestOption) (err error) {
_, err = s.RequestWithBucketID("DELETE", EndpointApplicationEmoji(appID, emojiID), nil, EndpointApplicationEmojis(appID), options...)
return
}
// GuildTemplate returns a GuildTemplate for the given code
// templateCode: The Code of a GuildTemplate
func (s *Session) GuildTemplate(templateCode string, options ...RequestOption) (st *GuildTemplate, err error) {
@@ -1712,7 +1784,7 @@ func (s *Session) ChannelMessageSendComplex(channelID string, data *MessageSend,
if encodeErr != nil {
return st, encodeErr
}
response, err = s.request("POST", endpoint, contentType, body, endpoint, 0, options...)
response, err = s.RequestRaw("POST", endpoint, contentType, body, endpoint, 0, options...)
} else {
response, err = s.RequestWithBucketID("POST", endpoint, data, endpoint, options...)
}
@@ -1824,7 +1896,7 @@ func (s *Session) ChannelMessageEditComplex(m *MessageEdit, options ...RequestOp
if encodeErr != nil {
return st, encodeErr
}
response, err = s.request("PATCH", endpoint, contentType, body, EndpointChannelMessage(m.Channel, ""), 0, options...)
response, err = s.RequestRaw("PATCH", endpoint, contentType, body, EndpointChannelMessage(m.Channel, ""), 0, options...)
} else {
response, err = s.RequestWithBucketID("PATCH", endpoint, m, EndpointChannelMessage(m.Channel, ""), options...)
}
@@ -2361,7 +2433,7 @@ func (s *Session) webhookExecute(webhookID, token string, wait bool, threadID st
return st, encodeErr
}
response, err = s.request("POST", uri, contentType, body, uri, 0, options...)
response, err = s.RequestRaw("POST", uri, contentType, body, uri, 0, options...)
} else {
response, err = s.RequestWithBucketID("POST", uri, data, uri, options...)
}
@@ -2421,7 +2493,7 @@ func (s *Session) WebhookMessageEdit(webhookID, token, messageID string, data *W
return nil, err
}
response, err = s.request("PATCH", uri, contentType, body, uri, 0, options...)
response, err = s.RequestRaw("PATCH", uri, contentType, body, uri, 0, options...)
if err != nil {
return nil, err
}
@@ -2641,7 +2713,7 @@ func (s *Session) ForumThreadStartComplex(channelID string, threadData *ThreadSt
return th, encodeErr
}
response, err = s.request("POST", endpoint, contentType, body, endpoint, 0, options...)
response, err = s.RequestRaw("POST", endpoint, contentType, body, endpoint, 0, options...)
} else {
response, err = s.RequestWithBucketID("POST", endpoint, data, endpoint, options...)
}
@@ -3071,7 +3143,7 @@ func (s *Session) InteractionRespond(interaction *Interaction, resp *Interaction
return err
}
_, err = s.request("POST", endpoint, contentType, body, endpoint, 0, options...)
_, err = s.RequestRaw("POST", endpoint, contentType, body, endpoint, 0, options...)
return err
}
@@ -3453,3 +3525,183 @@ func (s *Session) UserApplicationRoleConnectionUpdate(appID string, rconn *Appli
err = unmarshal(body, &st)
return
}
// ----------------------------------------------------------------------
// Functions specific to polls
// ----------------------------------------------------------------------
// PollAnswerVoters returns users who voted for a particular answer in a poll on the specified message.
// channelID : ID of the channel.
// messageID : ID of the message.
// answerID : ID of the answer.
func (s *Session) PollAnswerVoters(channelID, messageID string, answerID int) (voters []*User, err error) {
endpoint := EndpointPollAnswerVoters(channelID, messageID, answerID)
var body []byte
body, err = s.RequestWithBucketID("GET", endpoint, nil, endpoint)
if err != nil {
return
}
var r struct {
Users []*User `json:"users"`
}
err = unmarshal(body, &r)
if err != nil {
return
}
voters = r.Users
return
}
// PollExpire expires poll on the specified message.
// channelID : ID of the channel.
// messageID : ID of the message.
func (s *Session) PollExpire(channelID, messageID string) (msg *Message, err error) {
endpoint := EndpointPollExpire(channelID, messageID)
var body []byte
body, err = s.RequestWithBucketID("POST", endpoint, nil, endpoint)
if err != nil {
return
}
err = unmarshal(body, &msg)
return
}
// ----------------------------------------------------------------------
// Functions specific to monetization
// ----------------------------------------------------------------------
// SKUs returns all SKUs for a given application.
// appID : The ID of the application.
func (s *Session) SKUs(appID string) (skus []*SKU, err error) {
endpoint := EndpointApplicationSKUs(appID)
body, err := s.RequestWithBucketID("GET", endpoint, nil, endpoint)
if err != nil {
return
}
err = unmarshal(body, &skus)
return
}
// Entitlements returns all Entitlements for a given app, active and expired.
// appID : The ID of the application.
// filterOptions : Optional filter options; otherwise set it to nil.
func (s *Session) Entitlements(appID string, filterOptions *EntitlementFilterOptions, options ...RequestOption) (entitlements []*Entitlement, err error) {
endpoint := EndpointEntitlements(appID)
queryParams := url.Values{}
if filterOptions != nil {
if filterOptions.UserID != "" {
queryParams.Set("user_id", filterOptions.UserID)
}
if filterOptions.SkuIDs != nil && len(filterOptions.SkuIDs) > 0 {
queryParams.Set("sku_ids", strings.Join(filterOptions.SkuIDs, ","))
}
if filterOptions.Before != nil {
queryParams.Set("before", filterOptions.Before.Format(time.RFC3339))
}
if filterOptions.After != nil {
queryParams.Set("after", filterOptions.After.Format(time.RFC3339))
}
if filterOptions.Limit > 0 {
queryParams.Set("limit", strconv.Itoa(filterOptions.Limit))
}
if filterOptions.GuildID != "" {
queryParams.Set("guild_id", filterOptions.GuildID)
}
if filterOptions.ExcludeEnded {
queryParams.Set("exclude_ended", "true")
}
}
body, err := s.RequestWithBucketID("GET", endpoint+"?"+queryParams.Encode(), nil, endpoint, options...)
if err != nil {
return
}
err = unmarshal(body, &entitlements)
return
}
// EntitlementConsume marks a given One-Time Purchase for the user as consumed.
func (s *Session) EntitlementConsume(appID, entitlementID string, options ...RequestOption) (err error) {
_, err = s.RequestWithBucketID("POST", EndpointEntitlementConsume(appID, entitlementID), nil, EndpointEntitlementConsume(appID, ""), options...)
return
}
// EntitlementTestCreate creates a test entitlement to a given SKU for a given guild or user.
// Discord will act as though that user or guild has entitlement to your premium offering.
func (s *Session) EntitlementTestCreate(appID string, data *EntitlementTest, options ...RequestOption) (err error) {
endpoint := EndpointEntitlements(appID)
_, err = s.RequestWithBucketID("POST", endpoint, data, endpoint, options...)
return
}
// EntitlementTestDelete deletes a currently-active test entitlement. Discord will act as though
// that user or guild no longer has entitlement to your premium offering.
func (s *Session) EntitlementTestDelete(appID, entitlementID string, options ...RequestOption) (err error) {
_, err = s.RequestWithBucketID("DELETE", EndpointEntitlement(appID, entitlementID), nil, EndpointEntitlement(appID, ""), options...)
return
}
// Subscriptions returns all subscriptions containing the SKU.
// skuID : The ID of the SKU.
// userID : User ID for which to return subscriptions. Required except for OAuth queries.
// before : Optional timestamp to retrieve subscriptions before this time.
// after : Optional timestamp to retrieve subscriptions after this time.
// limit : Optional maximum number of subscriptions to return (1-100, default 50).
func (s *Session) Subscriptions(skuID string, userID string, before, after *time.Time, limit int, options ...RequestOption) (subscriptions []*Subscription, err error) {
endpoint := EndpointSubscriptions(skuID)
queryParams := url.Values{}
if before != nil {
queryParams.Set("before", before.Format(time.RFC3339))
}
if after != nil {
queryParams.Set("after", after.Format(time.RFC3339))
}
if userID != "" {
queryParams.Set("user_id", userID)
}
if limit > 0 {
queryParams.Set("limit", strconv.Itoa(limit))
}
body, err := s.RequestWithBucketID("GET", endpoint+"?"+queryParams.Encode(), nil, endpoint, options...)
if err != nil {
return
}
err = unmarshal(body, &subscriptions)
return
}
// Subscription returns a subscription by its SKU and subscription ID.
// skuID : The ID of the SKU.
// subscriptionID : The ID of the subscription.
// userID : User ID for which to return the subscription. Required except for OAuth queries.
func (s *Session) Subscription(skuID, subscriptionID, userID string, options ...RequestOption) (subscription *Subscription, err error) {
endpoint := EndpointSubscription(skuID, subscriptionID)
queryParams := url.Values{}
if userID != "" {
// Unlike stated in the documentation, the user_id parameter is required here.
queryParams.Set("user_id", userID)
}
body, err := s.RequestWithBucketID("GET", endpoint+"?"+queryParams.Encode(), nil, endpoint, options...)
if err != nil {
return
}
err = unmarshal(body, &subscription)
return
}

View File

@@ -42,6 +42,7 @@ type State struct {
TrackChannels bool
TrackThreads bool
TrackEmojis bool
TrackStickers bool
TrackMembers bool
TrackThreadMembers bool
TrackRoles bool
@@ -63,6 +64,7 @@ func NewState() *State {
TrackChannels: true,
TrackThreads: true,
TrackEmojis: true,
TrackStickers: true,
TrackMembers: true,
TrackThreadMembers: true,
TrackRoles: true,
@@ -175,8 +177,8 @@ func (s *State) GuildRemove(guild *Guild) error {
// Guild gets a guild by ID.
// Useful for querying if @me is in a guild:
// _, err := discordgo.Session.State.Guild(guildID)
// isInGuild := err == nil
// _, err := discordgo.Session.State.Guild(guildID)
// isInGuild := err == nil
func (s *State) Guild(guildID string) (*Guild, error) {
if s == nil {
return nil, ErrNilState
@@ -1050,12 +1052,28 @@ func (s *State) OnInterface(se *Session, i interface{}) (err error) {
defer s.Unlock()
guild.Emojis = t.Emojis
}
case *GuildStickersUpdate:
if s.TrackStickers {
var guild *Guild
guild, err = s.Guild(t.GuildID)
if err != nil {
return err
}
s.Lock()
defer s.Unlock()
guild.Stickers = t.Stickers
}
case *ChannelCreate:
if s.TrackChannels {
err = s.ChannelAdd(t.Channel)
}
case *ChannelUpdate:
if s.TrackChannels {
old, err := s.Channel(t.ID)
if err == nil {
oldCopy := *old
t.BeforeUpdate = &oldCopy
}
err = s.ChannelAdd(t.Channel)
}
case *ChannelDelete:

View File

@@ -136,26 +136,49 @@ type Session struct {
wsMutex sync.Mutex
}
// ApplicationIntegrationType dictates where application can be installed and its available interaction contexts.
type ApplicationIntegrationType uint
const (
// ApplicationIntegrationGuildInstall indicates that app is installable to guilds.
ApplicationIntegrationGuildInstall ApplicationIntegrationType = 0
// ApplicationIntegrationUserInstall indicates that app is installable to users.
ApplicationIntegrationUserInstall ApplicationIntegrationType = 1
)
// ApplicationInstallParams represents application's installation parameters
// for default in-app oauth2 authorization link.
type ApplicationInstallParams struct {
Scopes []string `json:"scopes"`
Permissions int64 `json:"permissions,string"`
}
// ApplicationIntegrationTypeConfig represents application's configuration for a particular integration type.
type ApplicationIntegrationTypeConfig struct {
OAuth2InstallParams *ApplicationInstallParams `json:"oauth2_install_params,omitempty"`
}
// Application stores values for a Discord Application
type Application struct {
ID string `json:"id,omitempty"`
Name string `json:"name"`
Icon string `json:"icon,omitempty"`
Description string `json:"description,omitempty"`
RPCOrigins []string `json:"rpc_origins,omitempty"`
BotPublic bool `json:"bot_public,omitempty"`
BotRequireCodeGrant bool `json:"bot_require_code_grant,omitempty"`
TermsOfServiceURL string `json:"terms_of_service_url"`
PrivacyProxyURL string `json:"privacy_policy_url"`
Owner *User `json:"owner"`
Summary string `json:"summary"`
VerifyKey string `json:"verify_key"`
Team *Team `json:"team"`
GuildID string `json:"guild_id"`
PrimarySKUID string `json:"primary_sku_id"`
Slug string `json:"slug"`
CoverImage string `json:"cover_image"`
Flags int `json:"flags,omitempty"`
ID string `json:"id,omitempty"`
Name string `json:"name"`
Icon string `json:"icon,omitempty"`
Description string `json:"description,omitempty"`
RPCOrigins []string `json:"rpc_origins,omitempty"`
BotPublic bool `json:"bot_public,omitempty"`
BotRequireCodeGrant bool `json:"bot_require_code_grant,omitempty"`
TermsOfServiceURL string `json:"terms_of_service_url"`
PrivacyProxyURL string `json:"privacy_policy_url"`
Owner *User `json:"owner"`
Summary string `json:"summary"`
VerifyKey string `json:"verify_key"`
Team *Team `json:"team"`
GuildID string `json:"guild_id"`
PrimarySKUID string `json:"primary_sku_id"`
Slug string `json:"slug"`
CoverImage string `json:"cover_image"`
Flags int `json:"flags,omitempty"`
IntegrationTypesConfig map[ApplicationIntegrationType]*ApplicationIntegrationTypeConfig `json:"integration_types,omitempty"`
}
// ApplicationRoleConnectionMetadataType represents the type of application role connection metadata.
@@ -233,9 +256,13 @@ type IntegrationAccount struct {
}
// A VoiceRegion stores data for a specific voice region server.
// https://discord.com/developers/docs/resources/voice#voice-region-object
type VoiceRegion struct {
ID string `json:"id"`
Name string `json:"name"`
ID string `json:"id"`
Name string `json:"name"`
Optimal bool `json:"optimal"`
Deprecated bool `json:"deprecated"`
Custom bool `json:"custom"`
}
// InviteTargetType indicates the type of target of an invite
@@ -585,7 +612,7 @@ type Emoji struct {
// EmojiRegex is the regex used to find and identify emojis in messages
var (
EmojiRegex = regexp.MustCompile(`<(a|):[A-z0-9_~]+:[0-9]{18,20}>`)
EmojiRegex = regexp.MustCompile(`<(a|):[A-Za-z0-9_~]+:[0-9]{18,20}>`)
)
// MessageFormat returns a correctly formatted Emoji for use in Message content and embeds
@@ -620,6 +647,7 @@ type EmojiParams struct {
// NOTE: can be only set on creation.
Image string `json:"image,omitempty"`
// Roles for which this emoji will be available.
// NOTE: can not be used with application emoji endpoints.
Roles []string `json:"roles,omitempty"`
}
@@ -1291,27 +1319,35 @@ type GuildFeature string
// Constants for GuildFeature
const (
GuildFeatureAnimatedBanner GuildFeature = "ANIMATED_BANNER"
GuildFeatureAnimatedIcon GuildFeature = "ANIMATED_ICON"
GuildFeatureAutoModeration GuildFeature = "AUTO_MODERATION"
GuildFeatureBanner GuildFeature = "BANNER"
GuildFeatureCommunity GuildFeature = "COMMUNITY"
GuildFeatureDiscoverable GuildFeature = "DISCOVERABLE"
GuildFeatureFeaturable GuildFeature = "FEATURABLE"
GuildFeatureInviteSplash GuildFeature = "INVITE_SPLASH"
GuildFeatureMemberVerificationGateEnabled GuildFeature = "MEMBER_VERIFICATION_GATE_ENABLED"
GuildFeatureMonetizationEnabled GuildFeature = "MONETIZATION_ENABLED"
GuildFeatureMoreStickers GuildFeature = "MORE_STICKERS"
GuildFeatureNews GuildFeature = "NEWS"
GuildFeaturePartnered GuildFeature = "PARTNERED"
GuildFeaturePreviewEnabled GuildFeature = "PREVIEW_ENABLED"
GuildFeaturePrivateThreads GuildFeature = "PRIVATE_THREADS"
GuildFeatureRoleIcons GuildFeature = "ROLE_ICONS"
GuildFeatureTicketedEventsEnabled GuildFeature = "TICKETED_EVENTS_ENABLED"
GuildFeatureVanityURL GuildFeature = "VANITY_URL"
GuildFeatureVerified GuildFeature = "VERIFIED"
GuildFeatureVipRegions GuildFeature = "VIP_REGIONS"
GuildFeatureWelcomeScreenEnabled GuildFeature = "WELCOME_SCREEN_ENABLED"
GuildFeatureAnimatedBanner GuildFeature = "ANIMATED_BANNER"
GuildFeatureAnimatedIcon GuildFeature = "ANIMATED_ICON"
GuildFeatureApplicationCommandPermissionV2 GuildFeature = "APPLICATION_COMMAND_PERMISSIONS_V2"
GuildFeatureAutoModeration GuildFeature = "AUTO_MODERATION"
GuildFeatureBanner GuildFeature = "BANNER"
GuildFeatureCommunity GuildFeature = "COMMUNITY"
GuildFeatureCreatorMonetizableProvisional GuildFeature = "CREATOR_MONETIZABLE_PROVISIONAL"
GuildFeatureCreatorStorePage GuildFeature = "CREATOR_STORE_PAGE"
GuildFeatureDeveloperSupportServer GuildFeature = "DEVELOPER_SUPPORT_SERVER"
GuildFeatureDiscoverable GuildFeature = "DISCOVERABLE"
GuildFeatureFeaturable GuildFeature = "FEATURABLE"
GuildFeatureInvitesDisabled GuildFeature = "INVITES_DISABLED"
GuildFeatureInviteSplash GuildFeature = "INVITE_SPLASH"
GuildFeatureMemberVerificationGateEnabled GuildFeature = "MEMBER_VERIFICATION_GATE_ENABLED"
GuildFeatureMoreSoundboard GuildFeature = "MORE_SOUNDBOARD"
GuildFeatureMoreStickers GuildFeature = "MORE_STICKERS"
GuildFeatureNews GuildFeature = "NEWS"
GuildFeaturePartnered GuildFeature = "PARTNERED"
GuildFeaturePreviewEnabled GuildFeature = "PREVIEW_ENABLED"
GuildFeatureRaidAlertsDisabled GuildFeature = "RAID_ALERTS_DISABLED"
GuildFeatureRoleIcons GuildFeature = "ROLE_ICONS"
GuildFeatureRoleSubscriptionsAvailableForPurchase GuildFeature = "ROLE_SUBSCRIPTIONS_AVAILABLE_FOR_PURCHASE"
GuildFeatureRoleSubscriptionsEnabled GuildFeature = "ROLE_SUBSCRIPTIONS_ENABLED"
GuildFeatureSoundboard GuildFeature = "SOUNDBOARD"
GuildFeatureTicketedEventsEnabled GuildFeature = "TICKETED_EVENTS_ENABLED"
GuildFeatureVanityURL GuildFeature = "VANITY_URL"
GuildFeatureVerified GuildFeature = "VERIFIED"
GuildFeatureVipRegions GuildFeature = "VIP_REGIONS"
GuildFeatureWelcomeScreenEnabled GuildFeature = "WELCOME_SCREEN_ENABLED"
)
// A GuildParams stores all the data needed to update discord guild settings
@@ -1538,6 +1574,9 @@ type Member struct {
// The hash of the avatar for the guild member, if any.
Avatar string `json:"avatar"`
// The hash of the banner for the guild member, if any.
Banner string `json:"banner"`
// The underlying user on which the member is based.
User *User `json:"user"`
@@ -1582,13 +1621,29 @@ func (m *Member) AvatarURL(size string) string {
}
// BannerURL returns the URL of the member's banner image.
//
// size: The size of the desired banner image as a power of two
// Image size can be any power of two between 16 and 4096.
func (m *Member) BannerURL(size string) string {
if m.Banner == "" {
return m.User.BannerURL(size)
}
return bannerURL(
m.Banner,
EndpointGuildMemberBanner(m.GuildID, m.User.ID, m.Banner),
EndpointGuildMemberBannerAnimated(m.GuildID, m.User.ID, m.Banner),
size,
)
}
// DisplayName returns the member's guild nickname if they have one,
// otherwise it returns their discord display name.
func (m *Member) DisplayName() string {
if m.Nick != "" {
return m.Nick
}
return m.User.GlobalName
return m.User.DisplayName()
}
// ClientStatus stores the online, offline, idle, or dnd status of each device of a Guild member.
@@ -1743,6 +1798,10 @@ type AutoModerationActionMetadata struct {
// Timeout duration in seconds (maximum of 2419200 - 4 weeks).
// NOTE: should be only used with timeout action type.
Duration int `json:"duration_seconds,omitempty"`
// Additional explanation that will be shown to members whenever their message is blocked (maximum of 150 characters).
// NOTE: should be only used with block message action type.
CustomMessage string `json:"custom_message,omitempty"`
}
// AutoModerationAction stores data for an auto moderation action.
@@ -1891,8 +1950,8 @@ const (
AuditLogChangeKeyPrivacylevel AuditLogChangeKey = "privacy_level"
// AuditLogChangeKeyPruneDeleteDays is sent when number of days after which inactive and role-unassigned members are kicked changed (int) - guild
AuditLogChangeKeyPruneDeleteDays AuditLogChangeKey = "prune_delete_days"
// AuditLogChangeKeyPulibUpdatesChannelID is sent when id of the public updates channel changed (snowflake) - guild
AuditLogChangeKeyPulibUpdatesChannelID AuditLogChangeKey = "public_updates_channel_id"
// AuditLogChangeKeyPublicUpdatesChannelID is sent when id of the public updates channel changed (snowflake) - guild
AuditLogChangeKeyPublicUpdatesChannelID AuditLogChangeKey = "public_updates_channel_id"
// AuditLogChangeKeyRateLimitPerUser is sent when amount of seconds a user has to wait before sending another message changed (int) - channel
AuditLogChangeKeyRateLimitPerUser AuditLogChangeKey = "rate_limit_per_user"
// AuditLogChangeKeyRegion is sent when region changed (string) - guild
@@ -2038,6 +2097,15 @@ const (
AuditLogActionCreatorMonetizationRequestCreated AuditLogAction = 150
AuditLogActionCreatorMonetizationTermsAccepted AuditLogAction = 151
AuditLogActionOnboardingPromptCreate AuditLogAction = 163
AuditLogActionOnboardingPromptUpdate AuditLogAction = 164
AuditLogActionOnboardingPromptDelete AuditLogAction = 165
AuditLogActionOnboardingCreate AuditLogAction = 166
AuditLogActionOnboardingUpdate AuditLogAction = 167
AuditLogActionHomeSettingsCreate = 190
AuditLogActionHomeSettingsUpdate = 191
)
// GuildMemberParams stores data needed to update a member
@@ -2176,7 +2244,7 @@ func (activity *Activity) UnmarshalJSON(b []byte) error {
Type ActivityType `json:"type"`
URL string `json:"url,omitempty"`
CreatedAt int64 `json:"created_at"`
ApplicationID string `json:"application_id,omitempty"`
ApplicationID json.Number `json:"application_id,omitempty"`
State string `json:"state,omitempty"`
Details string `json:"details,omitempty"`
Timestamps TimeStamps `json:"timestamps,omitempty"`
@@ -2191,8 +2259,8 @@ func (activity *Activity) UnmarshalJSON(b []byte) error {
if err != nil {
return err
}
activity.ApplicationID = temp.ApplicationID.String()
activity.CreatedAt = time.Unix(0, temp.CreatedAt*1000000)
activity.ApplicationID = temp.ApplicationID
activity.Assets = temp.Assets
activity.Details = temp.Details
activity.Emoji = temp.Emoji
@@ -2302,63 +2370,426 @@ const (
StageInstancePrivacyLevelGuildOnly StageInstancePrivacyLevel = 2
)
// PollLayoutType represents the layout of a poll.
type PollLayoutType int
// Valid PollLayoutType values.
const (
PollLayoutTypeDefault PollLayoutType = 1
)
// PollMedia contains common data used by question and answers.
type PollMedia struct {
Text string `json:"text,omitempty"`
Emoji *ComponentEmoji `json:"emoji,omitempty"` // TODO: rename the type
}
// PollAnswer represents a single answer in a poll.
type PollAnswer struct {
// NOTE: should not be set on creation.
AnswerID int `json:"answer_id,omitempty"`
Media *PollMedia `json:"poll_media"`
}
// PollAnswerCount stores counted poll votes for a single answer.
type PollAnswerCount struct {
ID int `json:"id"`
Count int `json:"count"`
MeVoted bool `json:"me_voted"`
}
// PollResults contains voting results on a poll.
type PollResults struct {
Finalized bool `json:"is_finalized"`
AnswerCounts []*PollAnswerCount `json:"answer_counts"`
}
// Poll contains all poll related data.
type Poll struct {
Question PollMedia `json:"question"`
Answers []PollAnswer `json:"answers"`
AllowMultiselect bool `json:"allow_multiselect"`
LayoutType PollLayoutType `json:"layout_type,omitempty"`
// NOTE: should be set only on creation, when fetching use Expiry.
Duration int `json:"duration,omitempty"`
// NOTE: available only when fetching.
Results *PollResults `json:"results,omitempty"`
// NOTE: as Discord documentation notes, this field might be null even when fetching.
Expiry *time.Time `json:"expiry,omitempty"`
}
// SKUType is the type of SKU (see SKUType* consts)
// https://discord.com/developers/docs/monetization/skus
type SKUType int
// Valid SKUType values
const (
SKUTypeDurable SKUType = 2
SKUTypeConsumable SKUType = 3
SKUTypeSubscription SKUType = 5
// SKUTypeSubscriptionGroup is a system-generated group for each subscription SKU.
SKUTypeSubscriptionGroup SKUType = 6
)
// SKUFlags is a bitfield of flags used to differentiate user and server subscriptions (see SKUFlag* consts)
// https://discord.com/developers/docs/monetization/skus#sku-object-sku-flags
type SKUFlags int
const (
// SKUFlagAvailable indicates that the SKU is available for purchase.
SKUFlagAvailable SKUFlags = 1 << 2
// SKUFlagGuildSubscription indicates that the SKU is a guild subscription.
SKUFlagGuildSubscription SKUFlags = 1 << 7
// SKUFlagUserSubscription indicates that the SKU is a user subscription.
SKUFlagUserSubscription SKUFlags = 1 << 8
)
// SKU (stock-keeping units) represent premium offerings
type SKU struct {
// The ID of the SKU
ID string `json:"id"`
// The Type of the SKU
Type SKUType `json:"type"`
// The ID of the parent application
ApplicationID string `json:"application_id"`
// Customer-facing name of the SKU.
Name string `json:"name"`
// System-generated URL slug based on the SKU's name.
Slug string `json:"slug"`
// SKUFlags combined as a bitfield. The presence of a certain flag can be checked
// by performing a bitwise AND operation between this int and the flag.
Flags SKUFlags `json:"flags"`
}
// Subscription represents a user making recurring payments for at least one SKU over an ongoing period.
// https://discord.com/developers/docs/resources/subscription#subscription-object
type Subscription struct {
// ID of the subscription
ID string `json:"id"`
// ID of the user who is subscribed
UserID string `json:"user_id"`
// List of SKUs subscribed to
SKUIDs []string `json:"sku_ids"`
// List of entitlements granted for this subscription
EntitlementIDs []string `json:"entitlement_ids"`
// List of SKUs that this user will be subscribed to at renewal
RenewalSKUIDs []string `json:"renewal_sku_ids,omitempty"`
// Start of the current subscription period
CurrentPeriodStart time.Time `json:"current_period_start"`
// End of the current subscription period
CurrentPeriodEnd time.Time `json:"current_period_end"`
// Current status of the subscription
Status SubscriptionStatus `json:"status"`
// When the subscription was canceled. Only present if the subscription has been canceled.
CanceledAt *time.Time `json:"canceled_at,omitempty"`
// ISO3166-1 alpha-2 country code of the payment source used to purchase the subscription. Missing unless queried with a private OAuth scope.
Country string `json:"country,omitempty"`
}
// SubscriptionStatus is the current status of a Subscription Object
// https://discord.com/developers/docs/resources/subscription#subscription-statuses
type SubscriptionStatus int
// Valid SubscriptionStatus values
const (
SubscriptionStatusActive = 0
SubscriptionStatusEnding = 1
SubscriptionStatusInactive = 2
)
// EntitlementType is the type of entitlement (see EntitlementType* consts)
// https://discord.com/developers/docs/monetization/entitlements#entitlement-object-entitlement-types
type EntitlementType int
// Valid EntitlementType values
const (
EntitlementTypePurchase = 1
EntitlementTypePremiumSubscription = 2
EntitlementTypeDeveloperGift = 3
EntitlementTypeTestModePurchase = 4
EntitlementTypeFreePurchase = 5
EntitlementTypeUserGift = 6
EntitlementTypePremiumPurchase = 7
EntitlementTypeApplicationSubscription = 8
)
// Entitlement represents that a user or guild has access to a premium offering
// in your application.
type Entitlement struct {
// The ID of the entitlement
ID string `json:"id"`
// The ID of the SKU
SKUID string `json:"sku_id"`
// The ID of the parent application
ApplicationID string `json:"application_id"`
// The ID of the user that is granted access to the entitlement's sku
// Only available for user subscriptions.
UserID string `json:"user_id,omitempty"`
// The type of the entitlement
Type EntitlementType `json:"type"`
// The entitlement was deleted
Deleted bool `json:"deleted"`
// The start date at which the entitlement is valid.
// Not present when using test entitlements.
StartsAt *time.Time `json:"starts_at,omitempty"`
// The date at which the entitlement is no longer valid.
// Not present when using test entitlements or when receiving an ENTITLEMENT_CREATE event.
EndsAt *time.Time `json:"ends_at,omitempty"`
// The ID of the guild that is granted access to the entitlement's sku.
// Only available for guild subscriptions.
GuildID string `json:"guild_id,omitempty"`
// Whether or not the entitlement has been consumed.
// Only available for consumable items.
Consumed *bool `json:"consumed,omitempty"`
// The SubscriptionID of the entitlement.
// Not present when using test entitlements.
SubscriptionID string `json:"subscription_id,omitempty"`
}
// EntitlementOwnerType is the type of entitlement (see EntitlementOwnerType* consts)
type EntitlementOwnerType int
// Valid EntitlementOwnerType values
const (
EntitlementOwnerTypeGuildSubscription EntitlementOwnerType = 1
EntitlementOwnerTypeUserSubscription EntitlementOwnerType = 2
)
// EntitlementTest is used to test granting an entitlement to a user or guild
type EntitlementTest struct {
// The ID of the SKU to grant the entitlement to
SKUID string `json:"sku_id"`
// The ID of the guild or user to grant the entitlement to
OwnerID string `json:"owner_id"`
// OwnerType is the type of which the entitlement should be created
OwnerType EntitlementOwnerType `json:"owner_type"`
}
// EntitlementFilterOptions are the options for filtering Entitlements
type EntitlementFilterOptions struct {
// Optional user ID to look up for.
UserID string
// Optional array of SKU IDs to check for.
SkuIDs []string
// Optional timestamp to retrieve Entitlements before this time.
Before *time.Time
// Optional timestamp to retrieve Entitlements after this time.
After *time.Time
// Optional maximum number of entitlements to return (1-100, default 100).
Limit int
// Optional guild ID to look up for.
GuildID string
// Optional whether or not ended entitlements should be omitted.
ExcludeEnded bool
}
// Constants for the different bit offsets of text channel permissions
const (
// Deprecated: PermissionReadMessages has been replaced with PermissionViewChannel for text and voice channels
PermissionReadMessages = 0x0000000000000400
PermissionSendMessages = 0x0000000000000800
PermissionSendTTSMessages = 0x0000000000001000
PermissionManageMessages = 0x0000000000002000
PermissionEmbedLinks = 0x0000000000004000
PermissionAttachFiles = 0x0000000000008000
PermissionReadMessageHistory = 0x0000000000010000
PermissionMentionEveryone = 0x0000000000020000
PermissionUseExternalEmojis = 0x0000000000040000
PermissionUseSlashCommands = 0x0000000080000000
PermissionManageThreads = 0x0000000400000000
PermissionCreatePublicThreads = 0x0000000800000000
PermissionCreatePrivateThreads = 0x0000001000000000
PermissionUseExternalStickers = 0x0000002000000000
PermissionSendMessagesInThreads = 0x0000004000000000
PermissionReadMessages = 1 << 10
// Allows for sending messages in a channel and creating threads in a forum (does not allow sending messages in threads).
PermissionSendMessages = 1 << 11
// Allows for sending of /tts messages.
PermissionSendTTSMessages = 1 << 12
// Allows for deletion of other users messages.
PermissionManageMessages = 1 << 13
// Links sent by users with this permission will be auto-embedded.
PermissionEmbedLinks = 1 << 14
// Allows for uploading images and files.
PermissionAttachFiles = 1 << 15
// Allows for reading of message history.
PermissionReadMessageHistory = 1 << 16
// Allows for using the @everyone tag to notify all users in a channel, and the @here tag to notify all online users in a channel.
PermissionMentionEveryone = 1 << 17
// Allows the usage of custom emojis from other servers.
PermissionUseExternalEmojis = 1 << 18
// Deprecated: PermissionUseSlashCommands has been replaced by PermissionUseApplicationCommands
PermissionUseSlashCommands = 1 << 31
// Allows members to use application commands, including slash commands and context menu commands.
PermissionUseApplicationCommands = 1 << 31
// Allows for deleting and archiving threads, and viewing all private threads.
PermissionManageThreads = 1 << 34
// Allows for creating public and announcement threads.
PermissionCreatePublicThreads = 1 << 35
// Allows for creating private threads.
PermissionCreatePrivateThreads = 1 << 36
// Allows the usage of custom stickers from other servers.
PermissionUseExternalStickers = 1 << 37
// Allows for sending messages in threads.
PermissionSendMessagesInThreads = 1 << 38
// Allows sending voice messages.
PermissionSendVoiceMessages = 1 << 46
// Allows sending polls.
PermissionSendPolls = 1 << 49
// Allows user-installed apps to send public responses. When disabled, users will still be allowed to use their apps but the responses will be ephemeral. This only applies to apps not also installed to the server.
PermissionUseExternalApps = 1 << 50
)
// Constants for the different bit offsets of voice permissions
const (
PermissionVoicePrioritySpeaker = 0x0000000000000100
PermissionVoiceStreamVideo = 0x0000000000000200
PermissionVoiceConnect = 0x0000000000100000
PermissionVoiceSpeak = 0x0000000000200000
PermissionVoiceMuteMembers = 0x0000000000400000
PermissionVoiceDeafenMembers = 0x0000000000800000
PermissionVoiceMoveMembers = 0x0000000001000000
PermissionVoiceUseVAD = 0x0000000002000000
PermissionVoiceRequestToSpeak = 0x0000000100000000
PermissionUseActivities = 0x0000008000000000
// Allows for using priority speaker in a voice channel.
PermissionVoicePrioritySpeaker = 1 << 8
// Allows the user to go live.
PermissionVoiceStreamVideo = 1 << 9
// Allows for joining of a voice channel.
PermissionVoiceConnect = 1 << 20
// Allows for speaking in a voice channel.
PermissionVoiceSpeak = 1 << 21
// Allows for muting members in a voice channel.
PermissionVoiceMuteMembers = 1 << 22
// Allows for deafening of members in a voice channel.
PermissionVoiceDeafenMembers = 1 << 23
// Allows for moving of members between voice channels.
PermissionVoiceMoveMembers = 1 << 24
// Allows for using voice-activity-detection in a voice channel.
PermissionVoiceUseVAD = 1 << 25
// Allows for requesting to speak in stage channels.
PermissionVoiceRequestToSpeak = 1 << 32
// Deprecated: PermissionUseActivities has been replaced by PermissionUseEmbeddedActivities.
PermissionUseActivities = 1 << 39
// Allows for using Activities (applications with the EMBEDDED flag) in a voice channel.
PermissionUseEmbeddedActivities = 1 << 39
// Allows for using soundboard in a voice channel.
PermissionUseSoundboard = 1 << 42
// Allows the usage of custom soundboard sounds from other servers.
PermissionUseExternalSounds = 1 << 45
)
// Constants for general management.
const (
PermissionChangeNickname = 0x0000000004000000
PermissionManageNicknames = 0x0000000008000000
PermissionManageRoles = 0x0000000010000000
PermissionManageWebhooks = 0x0000000020000000
PermissionManageEmojis = 0x0000000040000000
PermissionManageEvents = 0x0000000200000000
// Allows for modification of own nickname.
PermissionChangeNickname = 1 << 26
// Allows for modification of other users nicknames.
PermissionManageNicknames = 1 << 27
// Allows management and editing of roles.
PermissionManageRoles = 1 << 28
// Allows management and editing of webhooks.
PermissionManageWebhooks = 1 << 29
// Deprecated: PermissionManageEmojis has been replaced by PermissionManageGuildExpressions.
PermissionManageEmojis = 1 << 30
// Allows for editing and deleting emojis, stickers, and soundboard sounds created by all users.
PermissionManageGuildExpressions = 1 << 30
// Allows for editing and deleting scheduled events created by all users.
PermissionManageEvents = 1 << 33
// Allows for viewing role subscription insights.
PermissionViewCreatorMonetizationAnalytics = 1 << 41
// Allows for creating emojis, stickers, and soundboard sounds, and editing and deleting those created by the current user.
PermissionCreateGuildExpressions = 1 << 43
// Allows for creating scheduled events, and editing and deleting those created by the current user.
PermissionCreateEvents = 1 << 44
)
// Constants for the different bit offsets of general permissions
const (
PermissionCreateInstantInvite = 0x0000000000000001
PermissionKickMembers = 0x0000000000000002
PermissionBanMembers = 0x0000000000000004
PermissionAdministrator = 0x0000000000000008
PermissionManageChannels = 0x0000000000000010
PermissionManageServer = 0x0000000000000020
PermissionAddReactions = 0x0000000000000040
PermissionViewAuditLogs = 0x0000000000000080
PermissionViewChannel = 0x0000000000000400
PermissionViewGuildInsights = 0x0000000000080000
PermissionModerateMembers = 0x0000010000000000
// Allows creation of instant invites.
PermissionCreateInstantInvite = 1 << 0
// Allows kicking members.
PermissionKickMembers = 1 << 1
// Allows banning members.
PermissionBanMembers = 1 << 2
// Allows all permissions and bypasses channel permission overwrites.
PermissionAdministrator = 1 << 3
// Allows management and editing of channels.
PermissionManageChannels = 1 << 4
// Deprecated: PermissionManageServer has been replaced by PermissionManageGuild.
PermissionManageServer = 1 << 5
// Allows management and editing of the guild.
PermissionManageGuild = 1 << 5
// Allows for the addition of reactions to messages.
PermissionAddReactions = 1 << 6
// Allows for viewing of audit logs.
PermissionViewAuditLogs = 1 << 7
// Allows guild members to view a channel, which includes reading messages in text channels and joining voice channels.
PermissionViewChannel = 1 << 10
// Allows for viewing guild insights.
PermissionViewGuildInsights = 1 << 19
// Allows for timing out users to prevent them from sending or reacting to messages in chat and threads, and from speaking in voice and stage channels.
PermissionModerateMembers = 1 << 40
PermissionAllText = PermissionViewChannel |
PermissionSendMessages |
@@ -2585,6 +3016,8 @@ const (
IntentGuildScheduledEvents Intent = 1 << 16
IntentAutoModerationConfiguration Intent = 1 << 20
IntentAutoModerationExecution Intent = 1 << 21
IntentGuildMessagePolls Intent = 1 << 24
IntentDirectMessagePolls Intent = 1 << 25
// TODO: remove when compatibility is not needed

View File

@@ -152,3 +152,11 @@ func (u *User) DefaultAvatarIndex() int {
id, _ := strconv.Atoi(u.Discriminator)
return id % 5
}
// DisplayName returns the user's global name if they have one, otherwise it returns their username.
func (u *User) DisplayName() string {
if u.GlobalName != "" {
return u.GlobalName
}
return u.Username
}

View File

@@ -515,6 +515,21 @@ func (s *Session) RequestGuildMembersBatchList(guildIDs []string, userIDs []stri
return
}
// GatewayWriteStruct allows for sending raw gateway structs over the gateway.
func (s *Session) GatewayWriteStruct(data interface{}) (err error) {
s.RLock()
defer s.RUnlock()
if s.wsConn == nil {
return ErrWSNotFound
}
s.wsMutex.Lock()
err = s.wsConn.WriteJSON(data)
s.wsMutex.Unlock()
return err
}
func (s *Session) requestGuildMembers(data requestGuildMembersData) (err error) {
s.log(LogInformational, "called")

View File

@@ -1204,6 +1204,8 @@ type Chat struct {
Lang string
ID string
ReplaceID string
ReplyID string
StanzaID string
Roster Roster
Other []string
OtherElem []XMLElement
@@ -1286,6 +1288,8 @@ func (c *Client) Recv() (stanza interface{}, err error) {
Thread: v.Thread,
ID: v.ID,
ReplaceID: v.ReplaceID.ID,
ReplyID: v.ReplyID.ID,
StanzaID: v.StanzaID.ID,
Other: v.OtherStrings(),
OtherElem: v.Other,
Stamp: stamp,
@@ -1488,7 +1492,7 @@ func (c *Client) Recv() (stanza interface{}, err error) {
// Send sends the message wrapped inside an XMPP message stanza body.
func (c *Client) Send(chat Chat) (n int, err error) {
var subtext, thdtext, oobtext, msgidtext, msgcorrecttext string
var subtext, thdtext, oobtext, msgidtext, msgcorrecttext, replytext string
if chat.Subject != `` {
subtext = `<subject>` + xmlEscape(chat.Subject) + `</subject>`
}
@@ -1512,9 +1516,13 @@ func (c *Client) Send(chat Chat) (n int, err error) {
msgcorrecttext = `<replace id='` + xmlEscape(chat.ReplaceID) + `' xmlns='urn:xmpp:message-correct:0'/>`
}
if chat.ReplyID != `` {
replytext = `<reply to='`+ xmlEscape(chat.Remote) + `' id='` + xmlEscape(chat.ReplyID) + `' xmlns='urn:xmpp:reply:0'/>`
}
chat.Text = validUTF8(chat.Text)
stanza := fmt.Sprintf("<message to='%s' type='%s' "+msgidtext+" xml:lang='en'>"+subtext+"<body>%s</body>"+msgcorrecttext+oobtext+thdtext+"</message>",
stanza := fmt.Sprintf("<message to='%s' type='%s' "+msgidtext+" xml:lang='en'>"+subtext+"<body>%s</body>"+msgcorrecttext+replytext+oobtext+thdtext+"</message>",
xmlEscape(chat.Remote), xmlEscape(chat.Type), xmlEscape(chat.Text))
if c.LimitMaxBytes != 0 && len(stanza) > c.LimitMaxBytes {
@@ -1768,6 +1776,18 @@ type clientMessageCorrect struct {
ID string `xml:"id,attr"`
}
type stanzaID struct {
XMLName xml.Name `xml:"urn:xmpp:sid:0 stanza-id"`
ID string `xml:"id,attr"`
By string `xml:"by,attr"`
}
type clientReply struct {
XMLName xml.Name `xml:"urn:xmpp:reply:0 reply"`
ID string `xml:"id,attr"`
To string `xml:"to,attr"`
}
// RFC 3921 B.1 jabber:client
type clientMessage struct {
XMLName xml.Name `xml:"jabber:client message"`
@@ -1782,6 +1802,8 @@ type clientMessage struct {
Body string `xml:"body"`
Thread string `xml:"thread"`
ReplaceID clientMessageCorrect
StanzaID stanzaID
ReplyID clientReply
// Pubsub
Event clientPubsubEvent `xml:"event"`

5
vendor/modules.txt vendored
View File

@@ -52,7 +52,7 @@ github.com/av-elier/go-decimal-to-rational
# github.com/blang/semver/v4 v4.0.0
## explicit; go 1.14
github.com/blang/semver/v4
# github.com/bwmarrin/discordgo v0.28.1
# github.com/bwmarrin/discordgo v0.29.0
## explicit; go 1.13
github.com/bwmarrin/discordgo
# github.com/d5/tengo/v2 v2.17.0
@@ -216,7 +216,7 @@ github.com/magiconair/properties
github.com/matterbridge/Rocket.Chat.Go.SDK/models
github.com/matterbridge/Rocket.Chat.Go.SDK/realtime
github.com/matterbridge/Rocket.Chat.Go.SDK/rest
# github.com/matterbridge/go-xmpp v0.0.0-20240523230155-7154bfeb76e8
# github.com/matterbridge/go-xmpp v0.0.0-20240523230155-7154bfeb76e8 => /home/irc-discord/uwaru-go-xmpp
## explicit; go 1.21.5
github.com/matterbridge/go-xmpp
# github.com/matterbridge/gomatrix v0.0.0-20220411225302-271e5088ea27
@@ -799,3 +799,4 @@ modernc.org/token
rsc.io/qr
rsc.io/qr/coding
rsc.io/qr/gf256
# github.com/matterbridge/go-xmpp => /home/irc-discord/uwaru-go-xmpp