Skip to content

Commit

Permalink
new: Implement API changes for 4.129.0 (linode#265)
Browse files Browse the repository at this point in the history
* Implement API changes for 4.129

* Use regexp for URLs
  • Loading branch information
LBGarber authored Jul 13, 2022
1 parent 861519d commit 9a63dad
Show file tree
Hide file tree
Showing 15 changed files with 514 additions and 4 deletions.
6 changes: 6 additions & 0 deletions client.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,8 @@ type Client struct {
ObjectStorage *Resource
Payments *Resource
Profile *Resource
ProfilePhoneNumber *Resource
ProfileSecurityQuestions *Resource
Regions *Resource
SSHKeys *Resource
StackScripts *Resource
Expand Down Expand Up @@ -467,6 +469,8 @@ func addResources(client *Client) {
objectStorageName: NewResource(client, objectStorageName, objectStorageEndpoint, false, nil, nil),
paymentsName: NewResource(client, paymentsName, paymentsEndpoint, false, Payment{}, PaymentsPagedResponse{}),
profileName: NewResource(client, profileName, profileEndpoint, false, nil, nil), // really?
profilePhoneNumberName: NewResource(client, profilePhoneNumberName, profilePhoneNumberEndpoint, false, nil, nil),
profileSecurityQuestionsName: NewResource(client, profileSecurityQuestionsName, profileSecurityQuestionsEndpoint, false, nil, nil),
regionsName: NewResource(client, regionsName, regionsEndpoint, false, Region{}, RegionsPagedResponse{}),
sshkeysName: NewResource(client, sshkeysName, sshkeysEndpoint, false, SSHKey{}, SSHKeysPagedResponse{}),
stackscriptsName: NewResource(client, stackscriptsName, stackscriptsEndpoint, false, Stackscript{}, StackscriptsPagedResponse{}),
Expand Down Expand Up @@ -527,6 +531,8 @@ func addResources(client *Client) {
client.ObjectStorage = resources[objectStorageName]
client.Payments = resources[paymentsName]
client.Profile = resources[profileName]
client.ProfilePhoneNumber = resources[profilePhoneNumberName]
client.ProfileSecurityQuestions = resources[profileSecurityQuestionsName]
client.Regions = resources[regionsName]
client.SSHKeys = resources[sshkeysName]
client.StackScripts = resources[stackscriptsName]
Expand Down
2 changes: 0 additions & 2 deletions config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import (
)

func TestConfig_LoadWithDefaults(t *testing.T) {

client := NewClient(nil)

file := createTestConfig(t, configLoadWithDefault)
Expand Down Expand Up @@ -100,7 +99,6 @@ func TestConfig_OverrideDefaults(t *testing.T) {
}

func TestConfig_NoDefaults(t *testing.T) {

client := NewClient(nil)

file := createTestConfig(t, configNoDefaults)
Expand Down
84 changes: 84 additions & 0 deletions profile_phone_number.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package linodego

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

// SendPhoneNumberVerificationCodeOptions fields are those accepted by SendPhoneNumberVerificationCode
type SendPhoneNumberVerificationCodeOptions struct {
ISOCode string `json:"iso_code"`
PhoneNumber string `json:"phone_number"`
}

// VerifyPhoneNumberOptions fields are those accepted by VerifyPhoneNumber
type VerifyPhoneNumberOptions struct {
OTPCode string `json:"otp_code"`
}

// SendPhoneNumberVerificationCode sends a one-time verification code via SMS message to the submitted phone number.
func (c *Client) SendPhoneNumberVerificationCode(ctx context.Context, opts SendPhoneNumberVerificationCodeOptions) error {
var body string
e, err := c.ProfilePhoneNumber.Endpoint()
if err != nil {
return err
}

req := c.R(ctx)

if bodyData, err := json.Marshal(opts); err == nil {
body = string(bodyData)
} else {
return NewError(err)
}

if _, err := coupleAPIErrors(req.
SetBody(body).
Post(e)); err != nil {
return err
}
return nil
}

// DeletePhoneNumber deletes the verified phone number for the User making this request.
func (c *Client) DeletePhoneNumber(ctx context.Context) error {
e, err := c.ProfilePhoneNumber.Endpoint()
if err != nil {
return err
}

req := c.R(ctx)

if _, err := coupleAPIErrors(req.
Delete(e)); err != nil {
return err
}
return nil
}

// VerifyPhoneNumber verifies a phone number by confirming the one-time code received via SMS message after accessing the Phone Verification Code Send command.
func (c *Client) VerifyPhoneNumber(ctx context.Context, opts VerifyPhoneNumberOptions) error {
var body string
e, err := c.ProfilePhoneNumber.Endpoint()
if err != nil {
return err
}

e = fmt.Sprintf("%s/verify", e)

req := c.R(ctx)

if bodyData, err := json.Marshal(opts); err == nil {
body = string(bodyData)
} else {
return NewError(err)
}

if _, err := coupleAPIErrors(req.
SetBody(body).
Post(e)); err != nil {
return err
}
return nil
}
65 changes: 65 additions & 0 deletions profile_security_questions.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package linodego

import (
"context"
"encoding/json"
)

type SecurityQuestion struct {
ID int `json:"id"`
Question string `json:"question"`
Response string `json:"response"`
}

type SecurityQuestionsListResponse struct {
SecurityQuestions []SecurityQuestion `json:"security_questions"`
}

type SecurityQuestionsAnswerQuestion struct {
QuestionID int `json:"question_id"`
Response string `json:"response"`
}

type SecurityQuestionsAnswerOptions struct {
SecurityQuestions []SecurityQuestionsAnswerQuestion `json:"security_questions"`
}

// SecurityQuestionsList returns a collection of security questions and their responses, if any, for your User Profile.
func (c *Client) SecurityQuestionsList(ctx context.Context) (*SecurityQuestionsListResponse, error) {
e, err := c.ProfileSecurityQuestions.Endpoint()
if err != nil {
return nil, err
}

req := c.R(ctx).SetResult(&SecurityQuestionsListResponse{})

r, err := coupleAPIErrors(req.Get(e))
if err != nil {
return nil, err
}
return r.Result().(*SecurityQuestionsListResponse), nil
}

// SecurityQuestionsAnswer adds security question responses for your User.
func (c *Client) SecurityQuestionsAnswer(ctx context.Context, opts SecurityQuestionsAnswerOptions) error {
var body string
e, err := c.ProfileSecurityQuestions.Endpoint()
if err != nil {
return err
}

req := c.R(ctx)

if bodyData, err := json.Marshal(opts); err == nil {
body = string(bodyData)
} else {
return NewError(err)
}

if _, err := coupleAPIErrors(req.
SetBody(body).
Post(e)); err != nil {
return err
}
return nil
}
114 changes: 114 additions & 0 deletions profile_tfa.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
package linodego

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

"github.com/linode/linodego/internal/parseabletime"
)

// TwoFactorSecret contains fields returned by CreateTwoFactorSecret
type TwoFactorSecret struct {
Expiry *time.Time `json:"expiry"`
Secret string `json:"secret"`
}

// ConfirmTwoFactorOptions contains fields used by ConfirmTwoFactor
type ConfirmTwoFactorOptions struct {
TFACode string `json:"tfa_code"`
}

// ConfirmTwoFactorResponse contains fields returned by ConfirmTwoFactor
type ConfirmTwoFactorResponse struct {
Scratch string `json:"scratch"`
}

func (s *TwoFactorSecret) UnmarshalJSON(b []byte) error {
type Mask TwoFactorSecret

p := struct {
*Mask
Expiry *parseabletime.ParseableTime `json:"expiry"`
}{
Mask: (*Mask)(s),
}

if err := json.Unmarshal(b, &p); err != nil {
return err
}

s.Expiry = (*time.Time)(p.Expiry)

return nil
}

// CreateTwoFactorSecret generates a Two Factor secret for your User.
func (c *Client) CreateTwoFactorSecret(ctx context.Context) (*TwoFactorSecret, error) {
e, err := c.Profile.Endpoint()
if err != nil {
return nil, err
}

e = fmt.Sprintf("%s/tfa-enable", e)

req := c.R(ctx).SetResult(&TwoFactorSecret{})

r, err := coupleAPIErrors(req.
Post(e))
if err != nil {
return nil, err
}

return r.Result().(*TwoFactorSecret), nil
}

// DisableTwoFactor disables Two Factor Authentication for your User.
func (c *Client) DisableTwoFactor(ctx context.Context) error {
e, err := c.Profile.Endpoint()
if err != nil {
return err
}

e = fmt.Sprintf("%s/tfa-disable", e)

req := c.R(ctx)

_, err = coupleAPIErrors(req.
Post(e))
if err != nil {
return err
}

return nil
}

// ConfirmTwoFactor confirms that you can successfully generate Two Factor codes and enables TFA on your Account.
func (c *Client) ConfirmTwoFactor(ctx context.Context, opts ConfirmTwoFactorOptions) (*ConfirmTwoFactorResponse, error) {
var body string

e, err := c.Profile.Endpoint()
if err != nil {
return nil, err
}

e = fmt.Sprintf("%s/tfa-enable-confirm", e)

if bodyData, err := json.Marshal(opts); err == nil {
body = string(bodyData)
} else {
return nil, NewError(err)
}

req := c.R(ctx).SetResult(&ConfirmTwoFactorResponse{})

r, err := coupleAPIErrors(req.
SetBody(body).
Post(e))
if err != nil {
return nil, err
}

return r.Result().(*ConfirmTwoFactorResponse), nil
}
4 changes: 4 additions & 0 deletions resources.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ const (
objectStorageName = "objectstorage"
paymentsName = "payments"
profileName = "profile"
profilePhoneNumberName = "profilephonenumber"
profileSecurityQuestionsName = "profilesecurityquestions"
regionsName = "regions"
sshkeysName = "sshkeys"
stackscriptsName = "stackscripts"
Expand Down Expand Up @@ -122,6 +124,8 @@ const (
objectStorageEndpoint = "object-storage"
paymentsEndpoint = "account/payments"
profileEndpoint = "profile"
profilePhoneNumberEndpoint = "profile/phone-number"
profileSecurityQuestionsEndpoint = "profile/security-questions"
regionsEndpoint = "regions"
sshkeysEndpoint = "profile/sshkeys"
stackscriptsEndpoint = "linode/stackscripts"
Expand Down
1 change: 1 addition & 0 deletions test/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ module test
require (
github.com/dnaeon/go-vcr v1.1.0
github.com/google/go-cmp v0.5.7
github.com/jarcoal/httpmock v1.2.0
github.com/linode/linodego v0.20.1
github.com/linode/linodego/k8s v0.0.0-00010101000000-000000000000
golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f
Expand Down
3 changes: 3 additions & 0 deletions test/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,8 @@ github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/imdario/mergo v0.3.5 h1:JboBksRwiiAJWvIYJVo46AfV+IAIKZpfrSzVKj42R4Q=
github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
github.com/jarcoal/httpmock v1.2.0 h1:gSvTxxFR/MEMfsGrvRbdfpRUMBStovlSRLw0Ep1bwwc=
github.com/jarcoal/httpmock v1.2.0/go.mod h1:oCoTsnAz4+UoOUIf5lJOWV2QQIW5UoeUI6aM2YnWAZk=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
Expand All @@ -191,6 +193,7 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/maxatome/go-testdeep v1.11.0 h1:Tgh5efyCYyJFGUYiT0qxBSIDeXw0F5zSoatlou685kk=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
Expand Down
3 changes: 2 additions & 1 deletion test/integration/databases_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,8 @@ func TestDatabase_List(t *testing.T) {
}

func waitForDatabaseUpdated(t *testing.T, client *linodego.Client, dbID int,
dbType linodego.DatabaseEngineType, minStart *time.Time) {
dbType linodego.DatabaseEngineType, minStart *time.Time,
) {
_, err := client.WaitForEventFinished(context.Background(), dbID, linodego.EntityDatabase,
linodego.ActionDatabaseUpdate, *minStart, 1200)
if err != nil {
Expand Down
20 changes: 20 additions & 0 deletions test/integration/integration_suite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import (
"testing"
"time"

"github.com/jarcoal/httpmock"

"github.com/dnaeon/go-vcr/cassette"
"github.com/dnaeon/go-vcr/recorder"
"github.com/linode/linodego"
Expand Down Expand Up @@ -150,6 +152,24 @@ func createTestClient(t *testing.T, fixturesYaml string) (*linodego.Client, func
return &c, recordStopper
}

func createMockClient(t *testing.T) *linodego.Client {
tokenSource := oauth2.StaticTokenSource(&oauth2.Token{AccessToken: validTestAPIKey})

client := &http.Client{
Transport: &oauth2.Transport{
Source: tokenSource,
},
}
httpmock.ActivateNonDefault(client)

t.Cleanup(func() {
httpmock.DeactivateAndReset()
})

c := linodego.NewClient(client)
return &c
}

// transportRecordWrapper returns a tranport.WrapperFunc which provides the test
// recorder as an http.RoundTripper.
func transportRecorderWrapper(t *testing.T, fixtureYaml string) (transport.WrapperFunc, func()) {
Expand Down
Loading

0 comments on commit 9a63dad

Please sign in to comment.