From acc916540eaee445be931d87f07ccfa3f8534aa8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?To=CF=80?= Date: Sat, 1 Jul 2023 15:47:11 +0200 Subject: [PATCH] refactor webhook client --- webhook/webhook_client.go | 193 +++++++++++++++++++++++++-------- webhook/webhook_client_impl.go | 131 ---------------------- webhook/webook_test.go | 4 +- 3 files changed, 152 insertions(+), 176 deletions(-) delete mode 100644 webhook/webhook_client_impl.go diff --git a/webhook/webhook_client.go b/webhook/webhook_client.go index aa7b11080..6db86277c 100644 --- a/webhook/webhook_client.go +++ b/webhook/webhook_client.go @@ -3,55 +3,162 @@ package webhook import ( "context" "errors" - - "github.com/disgoorg/snowflake/v2" + "net/url" + "strings" "github.com/disgoorg/disgo/discord" "github.com/disgoorg/disgo/rest" + "github.com/disgoorg/log" + "github.com/disgoorg/snowflake/v2" ) +// ErrInvalidWebhookURL is returned when the given webhookURL is invalid var ErrInvalidWebhookURL = errors.New("invalid webhook URL") +// NewWithURL creates a new Client by parsing the given webhookURL for the ID and Token. +func NewWithURL(webhookURL string, opts ...ConfigOpt) (*Client, error) { + u, err := url.Parse(webhookURL) + if err != nil { + return nil, err + } + + parts := strings.FieldsFunc(u.Path, func(r rune) bool { return r == '/' }) + if len(parts) != 4 { + return nil, ErrInvalidWebhookURL + } + + token := parts[3] + id, err := snowflake.Parse(parts[2]) + if err != nil { + return nil, err + } + + return New(id, token, opts...), nil +} + +// New creates a new Client with the given ID, Token and ConfigOpt(s). +func New(id snowflake.ID, token string, opts ...ConfigOpt) *Client { + config := DefaultConfig() + config.Apply(opts) + + return &Client{ + ID: id, + Token: token, + Logger: config.Logger, + Rest: config.Webhooks, + restClient: config.RestClient, + defaultAllowedMentions: config.DefaultAllowedMentions, + } +} + // Client is a high level interface for interacting with Discord's Webhooks API. -type Client interface { - // ID returns the configured Webhook id - ID() snowflake.ID - // Token returns the configured Webhook token - Token() string - // URL returns the full Webhook URL - URL() string - // Close closes all connections the Webhook Client has open - Close(ctx context.Context) - // Rest returns the underlying rest.Webhooks - Rest() rest.Webhooks - - // GetWebhook fetches the current Webhook from discord - GetWebhook(opts ...rest.RequestOpt) (*discord.IncomingWebhook, error) - // UpdateWebhook updates the current Webhook - UpdateWebhook(webhookUpdate discord.WebhookUpdateWithToken, opts ...rest.RequestOpt) (*discord.IncomingWebhook, error) - // DeleteWebhook deletes the current Webhook - DeleteWebhook(opts ...rest.RequestOpt) error - - // CreateMessage creates a new Message from the discord.WebhookMessageCreate - CreateMessage(messageCreate discord.WebhookMessageCreate, opts ...rest.RequestOpt) (*discord.Message, error) - // CreateMessageInThread creates a new Message from the discord.WebhookMessageCreate in the provided thread - CreateMessageInThread(messageCreate discord.WebhookMessageCreate, threadID snowflake.ID, opts ...rest.RequestOpt) (*discord.Message, error) - // CreateContent creates a new Message from the provided content - CreateContent(content string, opts ...rest.RequestOpt) (*discord.Message, error) - // CreateEmbeds creates a new Message from the provided discord.Embed(s) - CreateEmbeds(embeds []discord.Embed, opts ...rest.RequestOpt) (*discord.Message, error) - - // UpdateMessage updates an already sent Webhook Message with the discord.WebhookMessageUpdate - UpdateMessage(messageID snowflake.ID, messageUpdate discord.WebhookMessageUpdate, opts ...rest.RequestOpt) (*discord.Message, error) - // UpdateMessageInThread updates an already sent Webhook Message with the discord.WebhookMessageUpdate in the provided thread - UpdateMessageInThread(messageID snowflake.ID, messageUpdate discord.WebhookMessageUpdate, threadID snowflake.ID, opts ...rest.RequestOpt) (*discord.Message, error) - // UpdateContent updates an already sent Webhook Message with the content - UpdateContent(messageID snowflake.ID, content string, opts ...rest.RequestOpt) (*discord.Message, error) - // UpdateEmbeds updates an already sent Webhook Message with the discord.Embed(s) - UpdateEmbeds(messageID snowflake.ID, embeds []discord.Embed, opts ...rest.RequestOpt) (*discord.Message, error) - - // DeleteMessage deletes an already sent Webhook Message - DeleteMessage(messageID snowflake.ID, opts ...rest.RequestOpt) error - // DeleteMessageInThread deletes an already sent Webhook Message in the provided thread - DeleteMessageInThread(messageID snowflake.ID, threadID snowflake.ID, opts ...rest.RequestOpt) error +type Client struct { + ID snowflake.ID + Token string + Logger log.Logger + Rest rest.Webhooks + restClient rest.Client + defaultAllowedMentions *discord.AllowedMentions +} + +// URL returns the full Webhook URL +func (c *Client) URL() string { + return discord.WebhookURL(c.ID, c.Token) +} + +// Close closes all connections the Webhook Client has open +func (c *Client) Close(ctx context.Context) { + c.restClient.Close(ctx) +} + +// GetWebhook fetches the current Webhook from discord + +func (c *Client) GetWebhook(opts ...rest.RequestOpt) (*discord.IncomingWebhook, error) { + webhook, err := c.Rest.GetWebhookWithToken(c.ID, c.Token, opts...) + if incomingWebhook, ok := webhook.(discord.IncomingWebhook); ok && err == nil { + return &incomingWebhook, nil + } + return nil, err +} + +// UpdateWebhook updates the current Webhook +func (c *Client) UpdateWebhook(webhookUpdate discord.WebhookUpdateWithToken, opts ...rest.RequestOpt) (*discord.IncomingWebhook, error) { + webhook, err := c.Rest.UpdateWebhookWithToken(c.ID, c.Token, webhookUpdate, opts...) + if incomingWebhook, ok := webhook.(discord.IncomingWebhook); ok && err == nil { + return &incomingWebhook, nil + } + return nil, err +} + +// DeleteWebhook deletes the current Webhook +func (c *Client) DeleteWebhook(opts ...rest.RequestOpt) error { + return c.Rest.DeleteWebhookWithToken(c.ID, c.Token, opts...) +} + +// CreateMessageInThread creates a new Message from the discord.WebhookMessageCreate in the provided thread +func (c *Client) CreateMessageInThread(messageCreate discord.WebhookMessageCreate, threadID snowflake.ID, opts ...rest.RequestOpt) (*discord.Message, error) { + if messageCreate.AllowedMentions == nil { + messageCreate.AllowedMentions = c.defaultAllowedMentions + } + return c.Rest.CreateWebhookMessage(c.ID, c.Token, messageCreate, true, threadID, opts...) +} + +// CreateMessage creates a new Message from the discord.WebhookMessageCreate +func (c *Client) CreateMessage(messageCreate discord.WebhookMessageCreate, opts ...rest.RequestOpt) (*discord.Message, error) { + return c.CreateMessageInThread(messageCreate, 0, opts...) +} + +// CreateContent creates a new Message from the provided content +func (c *Client) CreateContent(content string, opts ...rest.RequestOpt) (*discord.Message, error) { + return c.CreateMessage(discord.WebhookMessageCreate{ + Content: content, + AllowedMentions: c.defaultAllowedMentions, + }, opts...) +} + +// CreateEmbeds creates a new Message from the provided discord.Embed(s) +func (c *Client) CreateEmbeds(embeds []discord.Embed, opts ...rest.RequestOpt) (*discord.Message, error) { + return c.CreateMessage(discord.WebhookMessageCreate{ + Embeds: embeds, + AllowedMentions: c.defaultAllowedMentions, + }, opts...) +} + +// UpdateMessage updates an already sent Webhook Message with the discord.WebhookMessageUpdate +func (c *Client) UpdateMessage(messageID snowflake.ID, messageUpdate discord.WebhookMessageUpdate, opts ...rest.RequestOpt) (*discord.Message, error) { + return c.UpdateMessageInThread(messageID, messageUpdate, 0, opts...) +} + +// UpdateMessageInThread updates an already sent Webhook Message with the discord.WebhookMessageUpdate in the provided thread +func (c *Client) UpdateMessageInThread(messageID snowflake.ID, messageUpdate discord.WebhookMessageUpdate, threadID snowflake.ID, opts ...rest.RequestOpt) (*discord.Message, error) { + if messageUpdate.AllowedMentions == nil { + messageUpdate.AllowedMentions = c.defaultAllowedMentions + } + return c.Rest.UpdateWebhookMessage(c.ID, c.Token, messageID, messageUpdate, threadID, opts...) +} + +// UpdateContent updates an already sent Webhook Message with the content +func (c *Client) UpdateContent(messageID snowflake.ID, content string, opts ...rest.RequestOpt) (*discord.Message, error) { + return c.UpdateMessage(messageID, discord.WebhookMessageUpdate{ + Content: &content, + AllowedMentions: c.defaultAllowedMentions, + }, opts...) +} + +// UpdateEmbeds updates an already sent Webhook Message with the discord.Embed(s) +func (c *Client) UpdateEmbeds(messageID snowflake.ID, embeds []discord.Embed, opts ...rest.RequestOpt) (*discord.Message, error) { + return c.UpdateMessage(messageID, discord.WebhookMessageUpdate{ + Embeds: &embeds, + AllowedMentions: c.defaultAllowedMentions, + }, opts...) +} + +// DeleteMessage deletes an already sent Webhook Message +func (c *Client) DeleteMessage(messageID snowflake.ID, opts ...rest.RequestOpt) error { + return c.DeleteMessageInThread(messageID, 0, opts...) +} + +// DeleteMessageInThread deletes an already sent Webhook Message in the provided thread +func (c *Client) DeleteMessageInThread(messageID snowflake.ID, threadID snowflake.ID, opts ...rest.RequestOpt) error { + return c.Rest.DeleteWebhookMessage(c.ID, c.Token, messageID, threadID, opts...) } diff --git a/webhook/webhook_client_impl.go b/webhook/webhook_client_impl.go deleted file mode 100644 index 0adbacda2..000000000 --- a/webhook/webhook_client_impl.go +++ /dev/null @@ -1,131 +0,0 @@ -package webhook - -import ( - "context" - "net/url" - "strings" - - "github.com/disgoorg/snowflake/v2" - - "github.com/disgoorg/disgo/discord" - "github.com/disgoorg/disgo/rest" -) - -// NewWithURL creates a new Client by parsing the given webhookURL for the ID and token. -func NewWithURL(webhookURL string, opts ...ConfigOpt) (Client, error) { - u, err := url.Parse(webhookURL) - if err != nil { - return nil, err - } - - parts := strings.FieldsFunc(u.Path, func(r rune) bool { return r == '/' }) - if len(parts) != 4 { - return nil, ErrInvalidWebhookURL - } - - token := parts[3] - id, err := snowflake.Parse(parts[2]) - if err != nil { - return nil, err - } - - return New(id, token, opts...), nil -} - -// New creates a new Client with the given ID, token and ConfigOpt(s). -func New(id snowflake.ID, token string, opts ...ConfigOpt) Client { - config := DefaultConfig() - config.Apply(opts) - - return &clientImpl{ - id: id, - token: token, - config: *config, - } -} - -type clientImpl struct { - id snowflake.ID - token string - config Config -} - -func (c *clientImpl) ID() snowflake.ID { - return c.id -} - -func (c *clientImpl) Token() string { - return c.token -} - -func (c *clientImpl) URL() string { - return discord.WebhookURL(c.id, c.token) -} - -func (c *clientImpl) Close(ctx context.Context) { - c.config.RestClient.Close(ctx) -} - -func (c *clientImpl) Rest() rest.Webhooks { - return c.config.Webhooks -} - -func (c *clientImpl) GetWebhook(opts ...rest.RequestOpt) (*discord.IncomingWebhook, error) { - webhook, err := c.Rest().GetWebhookWithToken(c.id, c.token, opts...) - if incomingWebhook, ok := webhook.(discord.IncomingWebhook); ok && err == nil { - return &incomingWebhook, nil - } - return nil, err -} - -func (c *clientImpl) UpdateWebhook(webhookUpdate discord.WebhookUpdateWithToken, opts ...rest.RequestOpt) (*discord.IncomingWebhook, error) { - webhook, err := c.Rest().UpdateWebhookWithToken(c.id, c.token, webhookUpdate, opts...) - if incomingWebhook, ok := webhook.(discord.IncomingWebhook); ok && err == nil { - return &incomingWebhook, nil - } - return nil, err -} - -func (c *clientImpl) DeleteWebhook(opts ...rest.RequestOpt) error { - return c.Rest().DeleteWebhookWithToken(c.id, c.token, opts...) -} - -func (c *clientImpl) CreateMessageInThread(messageCreate discord.WebhookMessageCreate, threadID snowflake.ID, opts ...rest.RequestOpt) (*discord.Message, error) { - return c.Rest().CreateWebhookMessage(c.id, c.token, messageCreate, true, threadID, opts...) -} - -func (c *clientImpl) CreateMessage(messageCreate discord.WebhookMessageCreate, opts ...rest.RequestOpt) (*discord.Message, error) { - return c.CreateMessageInThread(messageCreate, 0, opts...) -} - -func (c *clientImpl) CreateContent(content string, opts ...rest.RequestOpt) (*discord.Message, error) { - return c.CreateMessage(discord.WebhookMessageCreate{Content: content}, opts...) -} - -func (c *clientImpl) CreateEmbeds(embeds []discord.Embed, opts ...rest.RequestOpt) (*discord.Message, error) { - return c.CreateMessage(discord.WebhookMessageCreate{Embeds: embeds}, opts...) -} - -func (c *clientImpl) UpdateMessage(messageID snowflake.ID, messageUpdate discord.WebhookMessageUpdate, opts ...rest.RequestOpt) (*discord.Message, error) { - return c.UpdateMessageInThread(messageID, messageUpdate, 0, opts...) -} - -func (c *clientImpl) UpdateMessageInThread(messageID snowflake.ID, messageUpdate discord.WebhookMessageUpdate, threadID snowflake.ID, opts ...rest.RequestOpt) (*discord.Message, error) { - return c.Rest().UpdateWebhookMessage(c.id, c.token, messageID, messageUpdate, threadID, opts...) -} - -func (c *clientImpl) UpdateContent(messageID snowflake.ID, content string, opts ...rest.RequestOpt) (*discord.Message, error) { - return c.UpdateMessage(messageID, discord.WebhookMessageUpdate{Content: &content}, opts...) -} - -func (c *clientImpl) UpdateEmbeds(messageID snowflake.ID, embeds []discord.Embed, opts ...rest.RequestOpt) (*discord.Message, error) { - return c.UpdateMessage(messageID, discord.WebhookMessageUpdate{Embeds: &embeds}, opts...) -} - -func (c *clientImpl) DeleteMessage(messageID snowflake.ID, opts ...rest.RequestOpt) error { - return c.DeleteMessageInThread(messageID, 0, opts...) -} - -func (c *clientImpl) DeleteMessageInThread(messageID snowflake.ID, threadID snowflake.ID, opts ...rest.RequestOpt) error { - return c.Rest().DeleteWebhookMessage(c.id, c.token, messageID, threadID, opts...) -} diff --git a/webhook/webook_test.go b/webhook/webook_test.go index 471054cd7..2c69a353d 100644 --- a/webhook/webook_test.go +++ b/webhook/webook_test.go @@ -47,8 +47,8 @@ func TestParseURL(t *testing.T) { assert.Error(t, err, "URL parsing should have resulted in an error") return } - assert.Equal(t, tc.ID, c.ID(), "URL ID should match") - assert.Equal(t, tc.Token, c.Token(), "URL token should match") + assert.Equal(t, tc.ID, c.ID, "URL ID should match") + assert.Equal(t, tc.Token, c.Token, "URL Token should match") }) } }