~samwhited/paddle

a744c2d50ead081d66adc7a4136aa93b8b54a020 — Sam Whited 2 years ago 4600a21
user: new package with user APIs
1 files changed, 90 insertions(+), 0 deletions(-)

A user/users.go
A user/users.go => user/users.go +90 -0
@@ 0,0 1,90 @@
// Package user provides /subscription APIs related to users.
package user

import (
	"bytes"
	"encoding/json"
	"net/url"
	"strconv"

	"soquee.net/paddle"
)

const (
	listUsersURL = "/subscription/users"
)

// Client performs operations related to users.
type Client struct {
	*paddle.Client
}

// ListSubscription lists all users of the given subscription.
func (c Client) ListSubscription(id uint64) (Iter, error) {
	return c.list("subscription_id", id)
}

// ListPlan lists all users of the given subscription.
func (c Client) ListPlan(id uint64) (Iter, error) {
	// TODO: the docs say "plan" and "subscription_id" but don't explicitly list
	// either. Is it plan or plan_id?
	return c.list("plan", id)
}

// List lists all users.
func (c Client) List() (Iter, error) {
	return c.list("", 0)
}

func (c Client) list(filter string, id uint64) (Iter, error) {
	v := url.Values{}
	if filter != "" {
		v.Add("filter", strconv.FormatUint(id, 10))
	}
	msg, err := c.Do(listUsersURL, v)
	if err != nil {
		return Iter{}, err
	}
	return Iter{
		d: json.NewDecoder(bytes.NewReader(msg)),
	}, nil
}

// Iter provides a mechanism for lazily decoding and iterating over a list.
type Iter struct {
	d *json.Decoder
}

// Next returns true if there is more data to decode.
func (c Iter) Next() bool {
	return c.d.More()
}

// Decode returns the next user.
func (c Iter) Decode() (*User, error) {
	user := &User{}
	err := c.d.Decode(user)
	return user, err
}

// User represents a single user on a subscription.
type User struct {
	ID               uint64      `json:"user_id"`
	Subscription     uint64      `json:"subscription_id"`
	Plan             uint64      `json:"plan_id"`
	Email            string      `json:"user_email"`
	MarketingConsent bool        `json:"marketing_consent"`
	UpdateURL        string      `json:"update_url"`
	CancelURL        string      `json:"cancel_url"`
	State            string      `json:"active"`
	SignupDate       paddle.Time `json:"signup_date"`
	LastPayment      Payment     `json:"last_payment"`
	NextPayment      Payment     `json:"last_payment"`
}

// Payment represents a past or future payment.
type Payment struct {
	Amount   float64         `json:"amount"`
	Currency paddle.Currency `json:"currency"`
	Date     paddle.Time     `json:"date"`
}