Skip to content

Commit

Permalink
add context support
Browse files Browse the repository at this point in the history
  • Loading branch information
thomasf committed Jan 3, 2021
1 parent 0f9d1cc commit cc8b3ce
Show file tree
Hide file tree
Showing 21 changed files with 235 additions and 210 deletions.
5 changes: 3 additions & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
language: go
go:
- 1.11
- 1.12
- 1.13
- 1.14
- 1.15
install:
- export PATH=$PATH:$HOME/gopath/bin
script:
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,14 +82,14 @@ It is possible that some endpoints are missing in this SDK Client, but you can u

```go
// If using Go Modules
// import "github.com/plutov/paypal/v3"
// import "github.com/plutov/paypal/v4"
import "github.com/plutov/paypal"

// Create a client instance
c, err := paypal.NewClient("clientID", "secretID", paypal.APIBaseSandBox)
c.SetLog(os.Stdout) // Set log to terminal stdout

accessToken, err := c.GetAccessToken()
accessToken, err := c.GetAccessToken(context.Background())
```

### How to Contribute
Expand Down
21 changes: 11 additions & 10 deletions authorization.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,16 @@ package paypal

import (
"bytes"
"context"
"fmt"
"net/http"
)

// GetAuthorization returns an authorization by ID
// Endpoint: GET /v2/payments/authorizations/ID
func (c *Client) GetAuthorization(authID string) (*Authorization, error) {
func (c *Client) GetAuthorization(ctx context.Context, authID string) (*Authorization, error) {
buf := bytes.NewBuffer([]byte(""))
req, err := http.NewRequest("GET", fmt.Sprintf("%s%s%s", c.APIBase, "/v2/payments/authorizations/", authID), buf)
req, err := http.NewRequestWithContext(ctx, "GET", fmt.Sprintf("%s%s%s", c.APIBase, "/v2/payments/authorizations/", authID), buf)
auth := &Authorization{}

if err != nil {
Expand All @@ -24,19 +25,19 @@ func (c *Client) GetAuthorization(authID string) (*Authorization, error) {
// CaptureAuthorization captures and process an existing authorization.
// To use this method, the original payment must have Intent set to "authorize"
// Endpoint: POST /v2/payments/authorizations/ID/capture
func (c *Client) CaptureAuthorization(authID string, paymentCaptureRequest *PaymentCaptureRequest) (*PaymentCaptureResponse, error) {
return c.CaptureAuthorizationWithPaypalRequestId(authID, paymentCaptureRequest, "")
func (c *Client) CaptureAuthorization(ctx context.Context, authID string, paymentCaptureRequest *PaymentCaptureRequest) (*PaymentCaptureResponse, error) {
return c.CaptureAuthorizationWithPaypalRequestId(ctx, authID, paymentCaptureRequest, "")
}

// CaptureAuthorization captures and process an existing authorization with idempotency.
// To use this method, the original payment must have Intent set to "authorize"
// Endpoint: POST /v2/payments/authorizations/ID/capture
func (c *Client) CaptureAuthorizationWithPaypalRequestId(
func (c *Client) CaptureAuthorizationWithPaypalRequestId(ctx context.Context,
authID string,
paymentCaptureRequest *PaymentCaptureRequest,
requestID string,
) (*PaymentCaptureResponse, error) {
req, err := c.NewRequest("POST", fmt.Sprintf("%s%s", c.APIBase, "/v2/payments/authorizations/"+authID+"/capture"), paymentCaptureRequest)
req, err := c.NewRequest(ctx, "POST", fmt.Sprintf("%s%s", c.APIBase, "/v2/payments/authorizations/"+authID+"/capture"), paymentCaptureRequest)
paymentCaptureResponse := &PaymentCaptureResponse{}

if err != nil {
Expand All @@ -53,9 +54,9 @@ func (c *Client) CaptureAuthorizationWithPaypalRequestId(

// VoidAuthorization voids a previously authorized payment
// Endpoint: POST /v2/payments/authorizations/ID/void
func (c *Client) VoidAuthorization(authID string) (*Authorization, error) {
func (c *Client) VoidAuthorization(ctx context.Context, authID string) (*Authorization, error) {
buf := bytes.NewBuffer([]byte(""))
req, err := http.NewRequest("POST", fmt.Sprintf("%s%s", c.APIBase, "/v2/payments/authorizations/"+authID+"/void"), buf)
req, err := http.NewRequestWithContext(ctx, "POST", fmt.Sprintf("%s%s", c.APIBase, "/v2/payments/authorizations/"+authID+"/void"), buf)
auth := &Authorization{}

if err != nil {
Expand All @@ -69,9 +70,9 @@ func (c *Client) VoidAuthorization(authID string) (*Authorization, error) {
// ReauthorizeAuthorization reauthorize a Paypal account payment.
// PayPal recommends to reauthorize payment after ~3 days
// Endpoint: POST /v2/payments/authorizations/ID/reauthorize
func (c *Client) ReauthorizeAuthorization(authID string, a *Amount) (*Authorization, error) {
func (c *Client) ReauthorizeAuthorization(ctx context.Context, authID string, a *Amount) (*Authorization, error) {
buf := bytes.NewBuffer([]byte(`{"amount":{"currency":"` + a.Currency + `","total":"` + a.Total + `"}}`))
req, err := http.NewRequest("POST", fmt.Sprintf("%s%s", c.APIBase, "/v2/payments/authorizations/"+authID+"/reauthorize"), buf)
req, err := http.NewRequestWithContext(ctx, "POST", fmt.Sprintf("%s%s", c.APIBase, "/v2/payments/authorizations/"+authID+"/reauthorize"), buf)
auth := &Authorization{}

if err != nil {
Expand Down
27 changes: 14 additions & 13 deletions billing.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package paypal

import (
"context"
"errors"
"fmt"
"net/http"
Expand Down Expand Up @@ -43,8 +44,8 @@ type (

// CreateBillingPlan creates a billing plan in Paypal
// Endpoint: POST /v1/payments/billing-plans
func (c *Client) CreateBillingPlan(plan BillingPlan) (*CreateBillingResp, error) {
req, err := c.NewRequest(http.MethodPost, fmt.Sprintf("%s%s", c.APIBase, "/v1/payments/billing-plans"), plan)
func (c *Client) CreateBillingPlan(ctx context.Context, plan BillingPlan) (*CreateBillingResp, error) {
req, err := c.NewRequest(ctx, http.MethodPost, fmt.Sprintf("%s%s", c.APIBase, "/v1/payments/billing-plans"), plan)
response := &CreateBillingResp{}
if err != nil {
return response, err
Expand All @@ -55,7 +56,7 @@ func (c *Client) CreateBillingPlan(plan BillingPlan) (*CreateBillingResp, error)

// UpdateBillingPlan updates values inside a billing plan
// Endpoint: PATCH /v1/payments/billing-plans
func (c *Client) UpdateBillingPlan(planId string, pathValues map[string]map[string]interface{}) error {
func (c *Client) UpdateBillingPlan(ctx context.Context, planId string, pathValues map[string]map[string]interface{}) error {
patchData := []Patch{}
for path, data := range pathValues {
patchData = append(patchData, Patch{
Expand All @@ -64,8 +65,8 @@ func (c *Client) UpdateBillingPlan(planId string, pathValues map[string]map[stri
Value: data,
})
}
req, err := c.NewRequest(http.MethodPatch, fmt.Sprintf("%s%s%s", c.APIBase, "/v1/payments/billing-plans/", planId), patchData)

req, err := c.NewRequest(ctx, http.MethodPatch, fmt.Sprintf("%s%s%s", c.APIBase, "/v1/payments/billing-plans/", planId), patchData)
if err != nil {
return err
}
Expand All @@ -76,21 +77,21 @@ func (c *Client) UpdateBillingPlan(planId string, pathValues map[string]map[stri
// ActivatePlan activates a billing plan
// By default, a new plan is not activated
// Endpoint: PATCH /v1/payments/billing-plans/
func (c *Client) ActivatePlan(planID string) error {
return c.UpdateBillingPlan(planID, map[string]map[string]interface{}{
func (c *Client) ActivatePlan(ctx context.Context, planID string) error {
return c.UpdateBillingPlan(ctx, planID, map[string]map[string]interface{}{
"/": {"state": BillingPlanStatusActive},
})
}

// CreateBillingAgreement creates an agreement for specified plan
// Endpoint: POST /v1/payments/billing-agreements
func (c *Client) CreateBillingAgreement(a BillingAgreement) (*CreateAgreementResp, error) {
func (c *Client) CreateBillingAgreement(ctx context.Context, a BillingAgreement) (*CreateAgreementResp, error) {
// PayPal needs only ID, so we will remove all fields except Plan ID
a.Plan = BillingPlan{
ID: a.Plan.ID,
}

req, err := c.NewRequest(http.MethodPost, fmt.Sprintf("%s%s", c.APIBase, "/v1/payments/billing-agreements"), a)
req, err := c.NewRequest(ctx, http.MethodPost, fmt.Sprintf("%s%s", c.APIBase, "/v1/payments/billing-agreements"), a)
response := &CreateAgreementResp{}
if err != nil {
return response, err
Expand All @@ -101,8 +102,8 @@ func (c *Client) CreateBillingAgreement(a BillingAgreement) (*CreateAgreementRes

// ExecuteApprovedAgreement - Use this call to execute (complete) a PayPal agreement that has been approved by the payer.
// Endpoint: POST /v1/payments/billing-agreements/token/agreement-execute
func (c *Client) ExecuteApprovedAgreement(token string) (*ExecuteAgreementResponse, error) {
req, err := http.NewRequest(http.MethodPost, fmt.Sprintf("%s/v1/payments/billing-agreements/%s/agreement-execute", c.APIBase, token), nil)
func (c *Client) ExecuteApprovedAgreement(ctx context.Context, token string) (*ExecuteAgreementResponse, error) {
req, err := http.NewRequestWithContext(ctx, http.MethodPost, fmt.Sprintf("%s/v1/payments/billing-agreements/%s/agreement-execute", c.APIBase, token), nil)
response := &ExecuteAgreementResponse{}

if err != nil {
Expand All @@ -125,8 +126,8 @@ func (c *Client) ExecuteApprovedAgreement(token string) (*ExecuteAgreementRespon

// ListBillingPlans lists billing-plans
// Endpoint: GET /v1/payments/billing-plans
func (c *Client) ListBillingPlans(bplp BillingPlanListParams) (*BillingPlanListResp, error) {
req, err := c.NewRequest("GET", fmt.Sprintf("%s%s", c.APIBase, "/v1/payments/billing-plans"), nil)
func (c *Client) ListBillingPlans(ctx context.Context, bplp BillingPlanListParams) (*BillingPlanListResp, error) {
req, err := c.NewRequest(ctx, "GET", fmt.Sprintf("%s%s", c.APIBase, "/v1/payments/billing-plans"), nil)
response := &BillingPlanListResp{}
if err != nil {
return response, err
Expand Down
11 changes: 6 additions & 5 deletions client.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package paypal

import (
"bytes"
"context"
"encoding/json"
"errors"
"fmt"
Expand Down Expand Up @@ -30,9 +31,9 @@ func NewClient(clientID string, secret string, APIBase string) (*Client, error)
// GetAccessToken returns struct of TokenResponse
// No need to call SetAccessToken to apply new access token for current Client
// Endpoint: POST /v1/oauth2/token
func (c *Client) GetAccessToken() (*TokenResponse, error) {
func (c *Client) GetAccessToken(ctx context.Context) (*TokenResponse, error) {
buf := bytes.NewBuffer([]byte("grant_type=client_credentials"))
req, err := http.NewRequest("POST", fmt.Sprintf("%s%s", c.APIBase, "/v1/oauth2/token"), buf)
req, err := http.NewRequestWithContext(ctx, "POST", fmt.Sprintf("%s%s", c.APIBase, "/v1/oauth2/token"), buf)
if err != nil {
return &TokenResponse{}, err
}
Expand Down Expand Up @@ -140,7 +141,7 @@ func (c *Client) SendWithAuth(req *http.Request, v interface{}) error {
if c.Token != nil {
if !c.tokenExpiresAt.IsZero() && c.tokenExpiresAt.Sub(time.Now()) < RequestNewTokenBeforeExpiresIn {
// c.Token will be updated in GetAccessToken call
if _, err := c.GetAccessToken(); err != nil {
if _, err := c.GetAccessToken(req.Context()); err != nil {
c.Unlock()
return err
}
Expand All @@ -164,7 +165,7 @@ func (c *Client) SendWithBasicAuth(req *http.Request, v interface{}) error {

// NewRequest constructs a request
// Convert payload to a JSON
func (c *Client) NewRequest(method, url string, payload interface{}) (*http.Request, error) {
func (c *Client) NewRequest(ctx context.Context, method, url string, payload interface{}) (*http.Request, error) {
var buf io.Reader
if payload != nil {
b, err := json.Marshal(&payload)
Expand All @@ -173,7 +174,7 @@ func (c *Client) NewRequest(method, url string, payload interface{}) (*http.Requ
}
buf = bytes.NewBuffer(b)
}
return http.NewRequest(method, url, buf)
return http.NewRequestWithContext(ctx, method, url, buf)
}

// log will dump request and response to the log file
Expand Down
12 changes: 8 additions & 4 deletions example_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
package paypal_test

import "github.com/plutov/paypal/v3"
import (
"context"

"github.com/plutov/paypal/v4"
)

func Example() {
// Initialize client
Expand All @@ -10,7 +14,7 @@ func Example() {
}

// Retrieve access token
_, err = c.GetAccessToken()
_, err = c.GetAccessToken(context.Background())
if err != nil {
panic(err)
}
Expand All @@ -24,7 +28,7 @@ func ExampleClient_CreateSinglePayout_Venmo() {
}

// Retrieve access token
_, err = c.GetAccessToken()
_, err = c.GetAccessToken(context.Background())
if err != nil {
panic(err)
}
Expand All @@ -51,5 +55,5 @@ func ExampleClient_CreateSinglePayout_Venmo() {
},
}

c.CreateSinglePayout(payout)
c.CreateSinglePayout(context.Background(), payout)
}
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
module github.com/plutov/paypal/v3
module github.com/plutov/paypal/v4

go 1.12
go 1.13

require github.com/stretchr/testify v1.6.0
13 changes: 7 additions & 6 deletions identity.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package paypal

import (
"context"
"fmt"
"net/http"
"net/url"
Expand All @@ -9,15 +10,15 @@ import (

// GrantNewAccessTokenFromAuthCode - Use this call to grant a new access token, using the previously obtained authorization code.
// Endpoint: POST /v1/identity/openidconnect/tokenservice
func (c *Client) GrantNewAccessTokenFromAuthCode(code, redirectURI string) (*TokenResponse, error) {
func (c *Client) GrantNewAccessTokenFromAuthCode(ctx context.Context, code, redirectURI string) (*TokenResponse, error) {
token := &TokenResponse{}

q := url.Values{}
q.Set("grant_type", "authorization_code")
q.Set("code", code)
q.Set("redirect_uri", redirectURI)

req, err := http.NewRequest("POST", fmt.Sprintf("%s%s", c.APIBase, "/v1/identity/openidconnect/tokenservice"), strings.NewReader(q.Encode()))
req, err := http.NewRequestWithContext(ctx, "POST", fmt.Sprintf("%s%s", c.APIBase, "/v1/identity/openidconnect/tokenservice"), strings.NewReader(q.Encode()))
if err != nil {
return token, err
}
Expand All @@ -33,15 +34,15 @@ func (c *Client) GrantNewAccessTokenFromAuthCode(code, redirectURI string) (*Tok

// GrantNewAccessTokenFromRefreshToken - Use this call to grant a new access token, using a refresh token.
// Endpoint: POST /v1/identity/openidconnect/tokenservice
func (c *Client) GrantNewAccessTokenFromRefreshToken(refreshToken string) (*TokenResponse, error) {
func (c *Client) GrantNewAccessTokenFromRefreshToken(ctx context.Context, refreshToken string) (*TokenResponse, error) {
type request struct {
GrantType string `json:"grant_type"`
RefreshToken string `json:"refresh_token"`
}

token := &TokenResponse{}

req, err := c.NewRequest("POST", fmt.Sprintf("%s%s", c.APIBase, "/v1/identity/openidconnect/tokenservice"), request{GrantType: "refresh_token", RefreshToken: refreshToken})
req, err := c.NewRequest(ctx, "POST", fmt.Sprintf("%s%s", c.APIBase, "/v1/identity/openidconnect/tokenservice"), request{GrantType: "refresh_token", RefreshToken: refreshToken})
if err != nil {
return token, err
}
Expand All @@ -56,10 +57,10 @@ func (c *Client) GrantNewAccessTokenFromRefreshToken(refreshToken string) (*Toke
// GetUserInfo - Use this call to retrieve user profile attributes.
// Endpoint: GET /v1/identity/openidconnect/userinfo/?schema=<Schema>
// Pass the schema that is used to return as per openidconnect protocol. The only supported schema value is openid.
func (c *Client) GetUserInfo(schema string) (*UserInfo, error) {
func (c *Client) GetUserInfo(ctx context.Context, schema string) (*UserInfo, error) {
u := &UserInfo{}

req, err := http.NewRequest("GET", fmt.Sprintf("%s%s%s", c.APIBase, "/v1/identity/openidconnect/userinfo/?schema=", schema), nil)
req, err := http.NewRequestWithContext(ctx, "GET", fmt.Sprintf("%s%s%s", c.APIBase, "/v1/identity/openidconnect/userinfo/?schema=", schema), nil)
if err != nil {
return u, err
}
Expand Down
Loading

0 comments on commit cc8b3ce

Please sign in to comment.