Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 15 additions & 8 deletions forwardemail/accounts.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@
package forwardemail

import (
"context"
"encoding/json"
"fmt"
"time"
)

Expand All @@ -26,22 +28,27 @@ type Account struct {
}

// GetAccount retrieves the authenticated user's account information from the Forward Email API.
func (c *Client) GetAccount() (*Account, error) {
req, err := c.newRequest("GET", "/v1/account")
if err != nil {
func (c *Client) GetAccount(ctx context.Context) (*Account, error) {
if ctx == nil {
return nil, ErrNilContext
}
if err := ctx.Err(); err != nil {
return nil, err
}

req, err := c.newRequest(ctx, "GET", "/v1/account", nil)
if err != nil {
return nil, fmt.Errorf("failed to create request for GetAccount: %w", err)
}

res, err := c.doRequest(req)
if err != nil {
return nil, err
return nil, fmt.Errorf("failed to fetch account: %w", err)
}

var item Account

err = json.Unmarshal(res, &item)
if err != nil {
return nil, err
if err := json.Unmarshal(res, &item); err != nil {
return nil, fmt.Errorf("failed to parse account response: %w", err)
}

return &item, nil
Expand Down
8 changes: 3 additions & 5 deletions forwardemail/accounts_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
package forwardemail

import (
"context"
"fmt"
"net/http"
"net/http/httptest"
Expand Down Expand Up @@ -61,12 +62,9 @@ func TestClient_GetAccount(t *testing.T) {
}))
defer svr.Close()

c, _ := NewClient(ClientOptions{
APIKey: "test-key",
APIURL: svr.URL,
})
c, _ := NewClient("test-key", WithAPIURL(svr.URL))

got, _ := c.GetAccount()
got, _ := c.GetAccount(context.Background())
if diff := cmp.Diff(tt.want, got); diff != "" {
t.Fatalf("values are not the same %s", diff)
}
Expand Down
143 changes: 104 additions & 39 deletions forwardemail/aliases.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
package forwardemail

import (
"context"
"encoding/json"
"fmt"
"io"
"net/url"
"strconv"
"strings"
Expand Down Expand Up @@ -39,55 +39,89 @@ type AliasParameters struct {
}

// GetAliases retrieves all email aliases for the specified domain.
func (c *Client) GetAliases(domain string) ([]Alias, error) {
req, err := c.newRequest("GET", fmt.Sprintf("/v1/domains/%s/aliases", domain))
if err != nil {
func (c *Client) GetAliases(ctx context.Context, domain string) ([]Alias, error) {
if ctx == nil {
return nil, ErrNilContext
}
if err := ctx.Err(); err != nil {
return nil, err
}
if strings.TrimSpace(domain) == "" {
return nil, ErrEmptyDomain
}

encodedDomain := url.PathEscape(domain)

req, err := c.newRequest(ctx, "GET", fmt.Sprintf("/v1/domains/%s/aliases", encodedDomain), nil)
if err != nil {
return nil, fmt.Errorf("failed to create request for GetAliases: %w", err)
}

res, err := c.doRequest(req)
if err != nil {
return nil, err
return nil, fmt.Errorf("failed to fetch aliases: %w", err)
}

var items []Alias

err = json.Unmarshal(res, &items)
if err != nil {
return nil, err
if err := json.Unmarshal(res, &items); err != nil {
return nil, fmt.Errorf("failed to parse aliases response: %w", err)
}

return items, nil
}

// GetAlias retrieves a specific email alias by name for the specified domain.
func (c *Client) GetAlias(domain, alias string) (*Alias, error) {
req, err := c.newRequest("GET", fmt.Sprintf("/v1/domains/%s/aliases/%s", domain, alias))
if err != nil {
func (c *Client) GetAlias(ctx context.Context, domain, alias string) (*Alias, error) {
if ctx == nil {
return nil, ErrNilContext
}
if err := ctx.Err(); err != nil {
return nil, err
}
if strings.TrimSpace(domain) == "" {
return nil, ErrEmptyDomain
}
if strings.TrimSpace(alias) == "" {
return nil, ErrEmptyAlias
}

encodedDomain := url.PathEscape(domain)
encodedAlias := url.PathEscape(alias)

req, err := c.newRequest(ctx, "GET", fmt.Sprintf("/v1/domains/%s/aliases/%s", encodedDomain, encodedAlias), nil)
if err != nil {
return nil, fmt.Errorf("failed to create request for GetAlias: %w", err)
}

res, err := c.doRequest(req)
if err != nil {
return nil, err
return nil, fmt.Errorf("failed to fetch alias: %w", err)
}

var item Alias

err = json.Unmarshal(res, &item)
if err != nil {
return nil, err
if err := json.Unmarshal(res, &item); err != nil {
return nil, fmt.Errorf("failed to parse alias response: %w", err)
}

return &item, nil
}

// CreateAlias creates a new email alias for the specified domain with the given parameters.
func (c *Client) CreateAlias(domain, alias string, parameters AliasParameters) (*Alias, error) {
req, err := c.newRequest("POST", fmt.Sprintf("/v1/domains/%s/aliases", domain))
if err != nil {
func (c *Client) CreateAlias(ctx context.Context, domain, alias string, parameters AliasParameters) (*Alias, error) {
if ctx == nil {
return nil, ErrNilContext
}
if err := ctx.Err(); err != nil {
return nil, err
}
if strings.TrimSpace(domain) == "" {
return nil, ErrEmptyDomain
}
if strings.TrimSpace(alias) == "" {
return nil, ErrEmptyAlias
}

encodedDomain := url.PathEscape(domain)

params := url.Values{}
params.Add("name", alias)
Expand Down Expand Up @@ -115,30 +149,43 @@ func (c *Client) CreateAlias(domain, alias string, parameters AliasParameters) (
}
}

req.Body = io.NopCloser(strings.NewReader(params.Encode()))
req, err := c.newRequest(ctx, "POST", fmt.Sprintf("/v1/domains/%s/aliases", encodedDomain), strings.NewReader(params.Encode()))
if err != nil {
return nil, fmt.Errorf("failed to create request for CreateAlias: %w", err)
}

req.Header.Set("Content-Type", "application/x-www-form-urlencoded")

res, err := c.doRequest(req)
if err != nil {
return nil, err
return nil, fmt.Errorf("failed to create alias: %w", err)
}

var item Alias

err = json.Unmarshal(res, &item)
if err != nil {
return nil, err
if err := json.Unmarshal(res, &item); err != nil {
return nil, fmt.Errorf("failed to parse create alias response: %w", err)
}

return &item, nil
}

// UpdateAlias updates an existing email alias with new parameters for the specified domain.
func (c *Client) UpdateAlias(domain, alias string, parameters AliasParameters) (*Alias, error) {
req, err := c.newRequest("PUT", fmt.Sprintf("/v1/domains/%s/aliases/%s", domain, alias))
if err != nil {
func (c *Client) UpdateAlias(ctx context.Context, domain, alias string, parameters AliasParameters) (*Alias, error) {
if ctx == nil {
return nil, ErrNilContext
}
if err := ctx.Err(); err != nil {
return nil, err
}
if strings.TrimSpace(domain) == "" {
return nil, ErrEmptyDomain
}
if strings.TrimSpace(alias) == "" {
return nil, ErrEmptyAlias
}

encodedDomain := url.PathEscape(domain)
encodedAlias := url.PathEscape(alias)

params := url.Values{}
params.Add("name", alias)
Expand Down Expand Up @@ -166,34 +213,52 @@ func (c *Client) UpdateAlias(domain, alias string, parameters AliasParameters) (
}
}

req.Body = io.NopCloser(strings.NewReader(params.Encode()))
req, err := c.newRequest(ctx, "PUT", fmt.Sprintf("/v1/domains/%s/aliases/%s", encodedDomain, encodedAlias), strings.NewReader(params.Encode()))
if err != nil {
return nil, fmt.Errorf("failed to create request for UpdateAlias: %w", err)
}

req.Header.Set("Content-Type", "application/x-www-form-urlencoded")

res, err := c.doRequest(req)
if err != nil {
return nil, err
return nil, fmt.Errorf("failed to update alias: %w", err)
}

var item Alias

err = json.Unmarshal(res, &item)
if err != nil {
return nil, err
if err := json.Unmarshal(res, &item); err != nil {
return nil, fmt.Errorf("failed to parse update alias response: %w", err)
}

return &item, nil
}

// DeleteAlias removes an email alias from the specified domain.
func (c *Client) DeleteAlias(domain, alias string) error {
req, err := c.newRequest("DELETE", fmt.Sprintf("/v1/domains/%s/aliases/%s", domain, alias))
if err != nil {
func (c *Client) DeleteAlias(ctx context.Context, domain, alias string) error {
if ctx == nil {
return ErrNilContext
}
if err := ctx.Err(); err != nil {
return err
}
if strings.TrimSpace(domain) == "" {
return ErrEmptyDomain
}
if strings.TrimSpace(alias) == "" {
return ErrEmptyAlias
}

encodedDomain := url.PathEscape(domain)
encodedAlias := url.PathEscape(alias)

req, err := c.newRequest(ctx, "DELETE", fmt.Sprintf("/v1/domains/%s/aliases/%s", encodedDomain, encodedAlias), nil)
if err != nil {
return fmt.Errorf("failed to create request for DeleteAlias: %w", err)
}

_, err = c.doRequest(req)
if err != nil {
return err
return fmt.Errorf("failed to delete alias: %w", err)
}

return nil
Expand Down
Loading
Loading