package api import ( "io" "git.sr.ht/~diamondburned/arikawa/discord" "git.sr.ht/~diamondburned/arikawa/httputil" "github.com/pkg/errors" ) type Message struct { ID discord.Snowflake `json:"id"` Type MessageType `json:"type"` ChannelID discord.Snowflake `json:"channel_id"` GuildID discord.Snowflake `json:"guild_id,omitempty"` // The author object follows the structure of the user object, but is only // a valid user in the case where the message is generated by a user or bot // user. If the message is generated by a webhook, the author object // corresponds to the webhook's id, username, and avatar. You can tell if a // message is generated by a webhook by checking for the webhook_id on the // message object. Author User `json:"author"` // The member object exists in MESSAGE_CREATE and MESSAGE_UPDATE // events from text-based guild channels. Member *GuildMember `json:"member,omitempty"` Content string `json:"content"` Timestamp discord.Timestamp `json:"timestamp,omitempty"` EditedTimestamp *discord.Timestamp `json:"edited_timestamp,omitempty"` TTS bool `json:"tts"` Pinned bool `json:"pinned"` // The user objects in the mentions array will only have the partial // member field present in MESSAGE_CREATE and MESSAGE_UPDATE events from // text-based guild channels. Mentions []GuildUser `json:"mentions"` MentionRoleIDs []discord.Snowflake `json:"mention_roles"` MentionEveryone bool `json:"mention_everyone"` // Not all channel mentions in a message will appear in mention_channels. MentionChannels []ChannelMention `json:"mention_channels,omitempty"` Attachments []Attachment `json:"attachments"` Embeds []Embed `json:"embeds"` Reactions []Reaction `json:"reaction,omitempty"` // Used for validating a message was sent Nonce string `json:"nonce,omitempty"` WebhookID discord.Snowflake `json:"webhook_id,omitempty"` Activity *MessageActivity `json:"activity,omitempty"` Application *MessageApplication `json:"application,omitempty"` Reference *MessageReference `json:"message_reference,omitempty"` Flags MessageFlags `json:"flags"` } type MessageType uint8 const ( DefaultMessage MessageType = iota RecipientAddMessage RecipientRemoveMessage CallMessage ChannelNameChangeMessage ChannelIconChangeMessage ChannelPinnedMessage GuildMemberJoinMessage NitroBoostMessage NitroTier1Message NitroTier2Message NitroTier3Message ChannelFollowAddMessage ) type MessageFlags uint8 const ( CrosspostedMessage MessageFlags = 1 << iota MessageIsCrosspost SuppressEmbeds SourceMessageDeleted UrgentMessage ) type ChannelMention struct { ChannelID discord.Snowflake `json:"id"` GuildID discord.Snowflake `json:"guild_id"` ChannelType ChannelType `json:"type"` ChannelName string `json:"name"` } type GuildUser struct { User Member *GuildMember `json:"member,omitempty"` } // type MessageActivity struct { Type MessageActivityType `json:"type"` // From a Rich Presence event PartyID string `json:"party_id,omitempty"` } type MessageActivityType uint8 const ( JoinMessage MessageActivityType = iota + 1 SpectateMessage ListenMessage JoinRequestMessage ) // type MessageApplication struct { ID discord.Snowflake `json:"id"` CoverID string `json:"cover_image,omitempty"` Description string `json:"description"` Icon string `json:"icon"` Name string `json:"name"` } // type MessageReference struct { ChannelID discord.Snowflake `json:"channel_id"` // Field might not be provided MessageID discord.Snowflake `json:"message_id,omitempty"` GuildID discord.Snowflake `json:"guild_id,omitempty"` } // type Attachment struct { ID discord.Snowflake `json:"id"` Filename string `json:"filename"` Size uint64 `json:"size"` URL discord.URL `json:"url"` Proxy discord.URL `json:"proxy_url"` // Only if Image Height uint `json:"height,omitempty"` Width uint `json:"width,omitempty"` } // func (c *Client) Messages( channelID discord.Snowflake, limit uint) ([]Message, error) { return c.messages(channelID, limit, nil) } func (c *Client) MessagesAround( channelID, around discord.Snowflake, limit uint) ([]Message, error) { return c.messages(channelID, limit, map[string]interface{}{ "around": around, }) } func (c *Client) MessagesBefore( channelID, before discord.Snowflake, limit uint) ([]Message, error) { return c.messages(channelID, limit, map[string]interface{}{ "before": before, }) } func (c *Client) MessagesAfter( channelID, after discord.Snowflake, limit uint) ([]Message, error) { return c.messages(channelID, limit, map[string]interface{}{ "after": after, }) } func (c *Client) messages(channelID discord.Snowflake, limit uint, body map[string]interface{}) ([]Message, error) { if body == nil { body = map[string]interface{}{} } switch { case limit == 0: limit = 50 case limit > 100: limit = 100 } body["limit"] = limit var msgs []Message return msgs, c.RequestJSON(&msgs, "GET", EndpointChannels+channelID.String(), httputil.WithJSONBody(c, body)) } func (c *Client) Message( channelID, messageID discord.Snowflake) (*Message, error) { var msg *Message return msg, c.RequestJSON(&msg, "GET", EndpointChannels+channelID.String()+"/messages/"+messageID.String()) } func (c *Client) SendMessage(channelID discord.Snowflake, content string, embed *Embed) (*Message, error) { return c.SendMessageComplex(channelID, SendMessageData{ Content: content, Embed: embed, }) } func (c *Client) SendMessageComplex(channelID discord.Snowflake, data SendMessageData) (*Message, error) { if data.Embed != nil { if err := data.Embed.Validate(); err != nil { return nil, errors.Wrap(err, "Embed error") } } var URL = EndpointChannels + channelID.String() var msg *Message if len(data.Files) == 0 { // No files, no need for streaming return msg, c.RequestJSON(&msg, "POST", URL, httputil.WithJSONBody(c, data)) } writer := func(w io.Writer) error { return data.WriteMultipart(c, w) } resp, err := c.MeanwhileBody(writer, "POST", URL) if err != nil { return nil, err } defer resp.Body.Close() return msg, c.DecodeStream(resp.Body, &msg) } func (c *Client) EditMessage(channelID, messageID discord.Snowflake, content string, embed *Embed, suppressEmbeds bool) (*Message, error) { var param struct { Content string `json:"content,omitempty"` Embed *Embed `json:"embed,omitempty"` Flags MessageFlags `json:"flags,omitempty"` } param.Content = content param.Embed = embed if suppressEmbeds { param.Flags = SuppressEmbeds } var msg *Message return msg, c.RequestJSON( &msg, "PATCH", EndpointChannels+channelID.String()+"/messages/"+messageID.String(), httputil.WithJSONBody(c, param), ) } // DeleteMessage deletes a message. Requires MANAGE_MESSAGES if the message is // not made by yourself. func (c *Client) DeleteMessage(channelID, messageID discord.Snowflake) error { return c.FastRequest("DELETE", EndpointChannels+channelID.String()+ "/messages/"+messageID.String()) } // DeleteMessages only works for bots. It can't delete messages older than 2 // weeks, and will fail if tried. This endpoint requires MANAGE_MESSAGES. func (c *Client) DeleteMessages(channelID discord.Snowflake, messageIDs []discord.Snowflake) error { var param struct { Messages []discord.Snowflake `json:"messages"` } param.Messages = messageIDs return c.FastRequest("POST", EndpointChannels+channelID.String()+ "/messages/bulk-delete", httputil.WithJSONBody(c, param)) }