Skip to content

Commit

Permalink
DE-1393 Move API Mailgun requests, responses, and helper types into a…
Browse files Browse the repository at this point in the history
… separate package (#393)
  • Loading branch information
vtopc authored Feb 23, 2025
1 parent 63a2c66 commit b276043
Show file tree
Hide file tree
Showing 96 changed files with 1,247 additions and 1,687 deletions.
20 changes: 5 additions & 15 deletions analytics.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,10 @@ import (
"context"

"github.com/mailgun/errors"
"github.com/mailgun/mailgun-go/v4/mtypes"
)

type MetricsPagination struct {
// Colon-separated value indicating column name and sort direction e.g. 'domain:asc'.
Sort string `json:"sort"`
// The number of items to skip over when satisfying the request.
// To get the first page of data set skip to zero.
// Then increment the skip by the limit for subsequent calls.
Skip int `json:"skip"`
// The maximum number of items returned in the response.
Limit int `json:"limit"`
// The total number of items in the query result set.
Total int `json:"total"`
}
type MetricsOptions = mtypes.MetricsRequest

// ListMetrics returns domain/account metrics.
//
Expand Down Expand Up @@ -58,7 +48,7 @@ func (iter *MetricsIterator) Err() error {
// Next retrieves the next page of items from the api. Returns false when there are
// no more pages to retrieve or if there was an error.
// Use `.Err()` to retrieve the error
func (iter *MetricsIterator) Next(ctx context.Context, resp *MetricsResponse) (more bool) {
func (iter *MetricsIterator) Next(ctx context.Context, resp *mtypes.MetricsResponse) (more bool) {
if iter.err != nil {
return false
}
Expand All @@ -73,7 +63,7 @@ func (iter *MetricsIterator) Next(ctx context.Context, resp *MetricsResponse) (m
return len(resp.Items) == iter.opts.Pagination.Limit
}

func (iter *MetricsIterator) fetch(ctx context.Context, resp *MetricsResponse) error {
func (iter *MetricsIterator) fetch(ctx context.Context, resp *mtypes.MetricsResponse) error {
if resp == nil {
return errors.New("resp cannot be nil")
}
Expand All @@ -86,7 +76,7 @@ func (iter *MetricsIterator) fetch(ctx context.Context, resp *MetricsResponse) e
}

// preallocate
resp.Items = make([]MetricsItem, 0, iter.opts.Pagination.Limit)
resp.Items = make([]mtypes.MetricsItem, 0, iter.opts.Pagination.Limit)

err = httpResp.parseFromJSON(resp)
if err != nil {
Expand Down
25 changes: 13 additions & 12 deletions analytics_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"testing"

"github.com/mailgun/mailgun-go/v4"
"github.com/mailgun/mailgun-go/v4/mtypes"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
Expand All @@ -14,45 +15,45 @@ func TestListMetrics(t *testing.T) {
err := mg.SetAPIBase(server.URL())
require.NoError(t, err)

start, _ := mailgun.NewRFC2822Time("Tue, 24 Sep 2024 00:00:00 +0000")
end, _ := mailgun.NewRFC2822Time("Tue, 24 Oct 2024 00:00:00 +0000")
start, _ := mtypes.NewRFC2822Time("Tue, 24 Sep 2024 00:00:00 +0000")
end, _ := mtypes.NewRFC2822Time("Tue, 24 Oct 2024 00:00:00 +0000")

opts := mailgun.MetricsOptions{
opts := mtypes.MetricsRequest{
Start: start,
End: end,
Pagination: mailgun.MetricsPagination{
Pagination: mtypes.MetricsPagination{
Limit: 10,
},
}
// filter by domain
opts.Filter.BoolGroupAnd = []mailgun.MetricsFilterPredicate{{
opts.Filter.BoolGroupAnd = []mtypes.MetricsFilterPredicate{{
Attribute: "domain",
Comparator: "=",
LabeledValues: []mailgun.MetricsLabeledValue{{Label: testDomain, Value: testDomain}},
LabeledValues: []mtypes.MetricsLabeledValue{{Label: testDomain, Value: testDomain}},
}}

wantResp := mailgun.MetricsResponse{
wantResp := mtypes.MetricsResponse{
Start: start,
End: end,
Resolution: "day",
Duration: "30d",
Dimensions: []string{"time"},
Items: []mailgun.MetricsItem{
Items: []mtypes.MetricsItem{
{
Dimensions: []mailgun.MetricsDimension{{
Dimensions: []mtypes.MetricsDimension{{
Dimension: "time",
Value: "Tue, 24 Sep 2024 00:00:00 +0000",
DisplayValue: "Tue, 24 Sep 2024 00:00:00 +0000",
}},
Metrics: mailgun.Metrics{
Metrics: mtypes.Metrics{
SentCount: ptr(uint64(4)),
DeliveredCount: ptr(uint64(3)),
OpenedCount: ptr(uint64(2)),
FailedCount: ptr(uint64(1)),
},
},
},
Pagination: mailgun.MetricsPagination{
Pagination: mtypes.MetricsPagination{
Sort: "",
Skip: 0,
Limit: 10,
Expand All @@ -63,7 +64,7 @@ func TestListMetrics(t *testing.T) {
it, err := mg.ListMetrics(opts)
require.NoError(t, err)

var page mailgun.MetricsResponse
var page mtypes.MetricsResponse
ctx := context.Background()
more := it.Next(ctx, &page)
require.Nil(t, it.Err())
Expand Down
2 changes: 1 addition & 1 deletion attachments_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ func TestMultipleAttachments(t *testing.T) {
require.NoError(t, err)

id = strings.Trim(id, "<>")
t.Logf("New Email: %s Id: %s\n", msg, id)
t.Logf("New Email: %s ID: %s\n", msg, id)

e, err := findAcceptedMessage(mg, id)
require.NoError(t, err)
Expand Down
52 changes: 17 additions & 35 deletions bounces.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,31 +3,13 @@ package mailgun
import (
"context"
"strconv"
)

// Bounce aggregates data relating to undeliverable messages to a specific intended recipient,
// identified by Address.
type Bounce struct {
// The time at which Mailgun detected the bounce.
CreatedAt RFC2822Time `json:"created_at"`
// Code provides the SMTP error code that caused the bounce
Code string `json:"code"`
// Address the bounce is for
Address string `json:"address"`
// human readable reason why
Error string `json:"error"`
}

type Paging struct {
First string `json:"first,omitempty"`
Next string `json:"next,omitempty"`
Previous string `json:"previous,omitempty"`
Last string `json:"last,omitempty"`
}
"github.com/mailgun/mailgun-go/v4/mtypes"
)

type bouncesListResponse struct {
Items []Bounce `json:"items"`
Paging Paging `json:"paging"`
Items []mtypes.Bounce `json:"items"`
Paging mtypes.Paging `json:"paging"`
}

// ListBounces returns a complete set of bounces logged against the sender's domain, if any.
Expand All @@ -46,7 +28,7 @@ func (mg *MailgunImpl) ListBounces(domain string, opts *ListOptions) *BouncesIte
url, err := r.generateUrlWithParameters()
return &BouncesIterator{
mg: mg,
bouncesListResponse: bouncesListResponse{Paging: Paging{Next: url, First: url}},
bouncesListResponse: bouncesListResponse{Paging: mtypes.Paging{Next: url, First: url}},
err: err,
}
}
Expand All @@ -57,23 +39,23 @@ type BouncesIterator struct {
err error
}

// If an error occurred during iteration `Err()` will return non nil
// Err if an error occurred during iteration `Err()` will return non nil
func (ci *BouncesIterator) Err() error {
return ci.err
}

// Next retrieves the next page of items from the api. Returns false when there
// no more pages to retrieve or if there was an error. Use `.Err()` to retrieve
// the error
func (ci *BouncesIterator) Next(ctx context.Context, items *[]Bounce) bool {
func (ci *BouncesIterator) Next(ctx context.Context, items *[]mtypes.Bounce) bool {
if ci.err != nil {
return false
}
ci.err = ci.fetch(ctx, ci.Paging.Next)
if ci.err != nil {
return false
}
cpy := make([]Bounce, len(ci.Items))
cpy := make([]mtypes.Bounce, len(ci.Items))
copy(cpy, ci.Items)
*items = cpy

Expand All @@ -83,15 +65,15 @@ func (ci *BouncesIterator) Next(ctx context.Context, items *[]Bounce) bool {
// First retrieves the first page of items from the api. Returns false if there
// was an error. It also sets the iterator object to the first page.
// Use `.Err()` to retrieve the error.
func (ci *BouncesIterator) First(ctx context.Context, items *[]Bounce) bool {
func (ci *BouncesIterator) First(ctx context.Context, items *[]mtypes.Bounce) bool {
if ci.err != nil {
return false
}
ci.err = ci.fetch(ctx, ci.Paging.First)
if ci.err != nil {
return false
}
cpy := make([]Bounce, len(ci.Items))
cpy := make([]mtypes.Bounce, len(ci.Items))
copy(cpy, ci.Items)
*items = cpy
return true
Expand All @@ -101,15 +83,15 @@ func (ci *BouncesIterator) First(ctx context.Context, items *[]Bounce) bool {
// Calling Last() is invalid unless you first call First() or Next()
// Returns false if there was an error. It also sets the iterator object
// to the last page. Use `.Err()` to retrieve the error.
func (ci *BouncesIterator) Last(ctx context.Context, items *[]Bounce) bool {
func (ci *BouncesIterator) Last(ctx context.Context, items *[]mtypes.Bounce) bool {
if ci.err != nil {
return false
}
ci.err = ci.fetch(ctx, ci.Paging.Last)
if ci.err != nil {
return false
}
cpy := make([]Bounce, len(ci.Items))
cpy := make([]mtypes.Bounce, len(ci.Items))
copy(cpy, ci.Items)
*items = cpy
return true
Expand All @@ -118,7 +100,7 @@ func (ci *BouncesIterator) Last(ctx context.Context, items *[]Bounce) bool {
// Previous retrieves the previous page of items from the api. Returns false when there
// no more pages to retrieve or if there was an error. Use `.Err()` to retrieve
// the error if any
func (ci *BouncesIterator) Previous(ctx context.Context, items *[]Bounce) bool {
func (ci *BouncesIterator) Previous(ctx context.Context, items *[]mtypes.Bounce) bool {
if ci.err != nil {
return false
}
Expand All @@ -129,7 +111,7 @@ func (ci *BouncesIterator) Previous(ctx context.Context, items *[]Bounce) bool {
if ci.err != nil {
return false
}
cpy := make([]Bounce, len(ci.Items))
cpy := make([]mtypes.Bounce, len(ci.Items))
copy(cpy, ci.Items)
*items = cpy

Expand All @@ -146,12 +128,12 @@ func (ci *BouncesIterator) fetch(ctx context.Context, url string) error {
}

// GetBounce retrieves a single bounce record, if any exist, for the given recipient address.
func (mg *MailgunImpl) GetBounce(ctx context.Context, domain, address string) (Bounce, error) {
func (mg *MailgunImpl) GetBounce(ctx context.Context, domain, address string) (mtypes.Bounce, error) {
r := newHTTPRequest(generateApiV3UrlWithDomain(mg, bouncesEndpoint, domain) + "/" + address)
r.setClient(mg.HTTPClient())
r.setBasicAuth(basicAuthUser, mg.APIKey())

var response Bounce
var response mtypes.Bounce
err := getResponseFromJSON(ctx, r, &response)
return response, err
}
Expand Down Expand Up @@ -190,7 +172,7 @@ func (mg *MailgunImpl) AddBounce(ctx context.Context, domain, address, code, bou
}

// Add Bounces adds a list of bounces to the bounce list
func (mg *MailgunImpl) AddBounces(ctx context.Context, domain string, bounces []Bounce) error {
func (mg *MailgunImpl) AddBounces(ctx context.Context, domain string, bounces []mtypes.Bounce) error {
r := newHTTPRequest(generateApiV3UrlWithDomain(mg, bouncesEndpoint, domain))
r.setClient(mg.HTTPClient())
r.setBasicAuth(basicAuthUser, mg.APIKey())
Expand Down
13 changes: 7 additions & 6 deletions bounces_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"time"

"github.com/mailgun/mailgun-go/v4"
"github.com/mailgun/mailgun-go/v4/mtypes"
"github.com/stretchr/testify/require"
)

Expand All @@ -21,7 +22,7 @@ func TestGetBounces(t *testing.T) {
ctx := context.Background()
it := mg.ListBounces(testDomain, nil)

var page []mailgun.Bounce
var page []mtypes.Bounce
for it.Next(ctx, &page) {
for _, bounce := range page {
t.Logf("Bounce: %+v\n", bounce)
Expand Down Expand Up @@ -55,7 +56,7 @@ func TestAddDelBounces(t *testing.T) {

findBounce := func(address string) bool {
it := mg.ListBounces(testDomain, nil)
var page []mailgun.Bounce
var page []mtypes.Bounce
for it.Next(ctx, &page) {
require.True(t, len(page) != 0)
for _, bounce := range page {
Expand Down Expand Up @@ -115,7 +116,7 @@ func TestAddDelBounceList(t *testing.T) {

findBounce := func(address string) bool {
it := mg.ListBounces(testDomain, nil)
var page []mailgun.Bounce
var page []mtypes.Bounce
for it.Next(ctx, &page) {
require.True(t, len(page) != 0)
for _, bounce := range page {
Expand All @@ -131,13 +132,13 @@ func TestAddDelBounceList(t *testing.T) {
return false
}

createdAt, err := mailgun.NewRFC2822Time("Thu, 13 Oct 2011 18:02:00 +0000")
createdAt, err := mtypes.NewRFC2822Time("Thu, 13 Oct 2011 18:02:00 +0000")
if err != nil {
t.Fatalf("invalid time")
}

// Generate a list of bounces
bounces := []mailgun.Bounce{
bounces := []mtypes.Bounce{
{
Code: "550",
Address: fmt.Sprintf("%s@%s", strings.ToLower(randomString(8, "bounce")), domain),
Expand Down Expand Up @@ -176,7 +177,7 @@ func TestAddDelBounceList(t *testing.T) {
require.NoError(t, err)

it := mg.ListBounces(testDomain, nil)
var page []mailgun.Bounce
var page []mtypes.Bounce
if it.Next(ctx, &page) {
t.Fatalf("Expected no item in the bounce list")
}
Expand Down
Loading

0 comments on commit b276043

Please sign in to comment.