1
0
Fork 0
mirror of https://github.com/diamondburned/arikawa.git synced 2024-11-01 12:34:28 +00:00
arikawa/api/webhook/webhook.go

174 lines
5.4 KiB
Go
Raw Normal View History

// Package webhook provides means to interact with webhooks directly and not
// through the bot API.
package webhook
import (
"mime/multipart"
"net/url"
"strconv"
"github.com/pkg/errors"
2020-10-28 22:39:59 +00:00
"github.com/diamondburned/arikawa/v2/api"
"github.com/diamondburned/arikawa/v2/discord"
"github.com/diamondburned/arikawa/v2/utils/httputil"
"github.com/diamondburned/arikawa/v2/utils/json/option"
"github.com/diamondburned/arikawa/v2/utils/sendpart"
)
// Client is the client used to interact with a webhook.
type Client struct {
// Client is the httputil.Client used to call Discord's API.
*httputil.Client
// ID is the id of the webhook.
ID discord.WebhookID
// Token is the token of the webhook.
Token string
}
// New creates a new Client using the passed token and id.
func New(id discord.WebhookID, token string) *Client {
return NewCustom(id, token, httputil.NewClient())
}
// NewCustom creates a new Client creates a new Client using the passed token
// and ID and makes API calls using the passed httputil.Client
func NewCustom(id discord.WebhookID, token string, c *httputil.Client) *Client {
return &Client{
Client: c,
ID: id,
Token: token,
}
}
// Get gets the webhook.
func (c *Client) Get() (*discord.Webhook, error) {
var w *discord.Webhook
return w, c.RequestJSON(&w, "GET", api.EndpointWebhooks+c.ID.String()+"/"+c.Token)
}
// Modify modifies the webhook.
func (c *Client) Modify(data api.ModifyWebhookData) (*discord.Webhook, error) {
var w *discord.Webhook
return w, c.RequestJSON(
&w, "PATCH",
api.EndpointWebhooks+c.ID.String()+"/"+c.Token,
httputil.WithJSONBody(data),
)
}
// Delete deletes a webhook permanently.
func (c *Client) Delete() error {
return c.FastRequest("DELETE", api.EndpointWebhooks+c.ID.String()+"/"+c.Token)
}
// https://discord.com/developers/docs/resources/webhook#execute-webhook-jsonform-params
type ExecuteData struct {
// Content are the message contents (up to 2000 characters).
//
// Required: one of content, file, embeds
Content string `json:"content,omitempty"`
// Username overrides the default username of the webhook
Username string `json:"username,omitempty"`
// AvatarURL overrides the default avatar of the webhook.
AvatarURL discord.URL `json:"avatar_url,omitempty"`
// TTS is true if this is a TTS message.
TTS bool `json:"tts,omitempty"`
// Embeds contains embedded rich content.
//
// Required: one of content, file, embeds
Embeds []discord.Embed `json:"embeds,omitempty"`
// Files represents a list of files to upload. This will not be JSON-encoded
// and will only be available through WriteMultipart.
Files []sendpart.File `json:"-"`
// AllowedMentions are the allowed mentions for the message.
AllowedMentions *api.AllowedMentions `json:"allowed_mentions,omitempty"`
}
// NeedsMultipart returns true if the ExecuteWebhookData has files.
func (data ExecuteData) NeedsMultipart() bool {
return len(data.Files) > 0
}
// WriteMultipart writes the webhook data into the given multipart body. It does
// not close body.
func (data ExecuteData) WriteMultipart(body *multipart.Writer) error {
return sendpart.Write(body, data, data.Files)
}
// Execute sends a message to the webhook, but doesn't wait for the message to
// get created. This is generally faster, but only applicable if no further
// interaction is required.
func (c *Client) Execute(data ExecuteData) (err error) {
_, err = c.execute(data, false)
return
}
// ExecuteAndWait executes the webhook, and waits for the generated
// discord.Message to be returned.
func (c *Client) ExecuteAndWait(data ExecuteData) (*discord.Message, error) {
return c.execute(data, true)
}
func (c *Client) execute(data ExecuteData, wait bool) (*discord.Message, error) {
if data.Content == "" && len(data.Embeds) == 0 && len(data.Files) == 0 {
return nil, api.ErrEmptyMessage
}
if data.AllowedMentions != nil {
if err := data.AllowedMentions.Verify(); err != nil {
return nil, errors.Wrap(err, "allowedMentions error")
}
}
for i, embed := range data.Embeds {
if err := embed.Validate(); err != nil {
return nil, errors.Wrap(err, "embed error at "+strconv.Itoa(i))
}
}
var param url.Values
if wait {
param = url.Values{"wait": {"true"}}
}
var URL = api.EndpointWebhooks + c.ID.String() + "/" + c.Token + "?" + param.Encode()
var msg *discord.Message
var ptr interface{}
if wait {
ptr = &msg
}
return msg, sendpart.POST(c.Client, data, ptr, URL)
}
// https://discord.com/developers/docs/resources/webhook#edit-webhook-message-jsonform-params
type EditMessageData struct {
// Content are the message contents. They may be up to 2000 characters
// characters long.
Content option.NullableString `json:"content,omitempty"`
// Embeds is an array of up to 10 discord.Embeds.
Embeds *[]discord.Embed `json:"embeds,omitempty"`
// AllowedMentions are the AllowedMentions for the message.
AllowedMentions *api.AllowedMentions `json:"allowed_mentions,omitempty"`
}
// EditMessage edits a previously-sent webhook message from the same webhook.
func (c *Client) EditMessage(messageID discord.MessageID, data EditMessageData) error {
return c.FastRequest("PATCH",
api.EndpointWebhooks+c.ID.String()+"/"+c.Token+"/messages/"+messageID.String(),
httputil.WithJSONBody(data))
}
// DeleteMessage deletes a message that was previously created by the same
// webhook.
func (c *Client) DeleteMessage(messageID discord.MessageID) error {
return c.FastRequest("DELETE",
api.EndpointWebhooks+c.ID.String()+"/"+c.Token+"/messages/"+messageID.String())
}