Skip to content

Commit

Permalink
feat: managed accounts service - create, list, get, update
Browse files Browse the repository at this point in the history
  • Loading branch information
MegaportPhilipBrowne committed Sep 24, 2024
1 parent acfbbf2 commit 74c20ee
Show file tree
Hide file tree
Showing 4 changed files with 308 additions and 0 deletions.
3 changes: 3 additions & 0 deletions client.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,8 @@ type Client struct {
MVEService MVEService
// ServiceKeyService provides methods for interacting with the Service Keys API
ServiceKeyService ServiceKeyService
// ManagedAccountService provides methods for interacting with the Managed Accounts API
ManagedAccountService ManagedAccountService

accessToken string // Access Token for client
tokenExpiry time.Time // Token Expiration
Expand Down Expand Up @@ -125,6 +127,7 @@ func NewClient(httpClient *http.Client, base *url.URL) *Client {
c.VXCService = NewVXCService(c)
c.PartnerService = NewPartnerService(c)
c.ServiceKeyService = NewServiceKeyService(c)
c.ManagedAccountService = NewManagedAccountService(c)

c.headers = make(map[string]string)

Expand Down
3 changes: 3 additions & 0 deletions errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,3 +60,6 @@ var ErrNoAvailableVxcPorts = errors.New("there are no available ports for you to

// ErrCostCentreTooLong is returned when a cost centre is longer than 255 characters
var ErrCostCentreTooLong = errors.New("cost centre must be less than 255 characters")

// ErrManagedAccountNotFound is returned when a managed account can't be found
var ErrManagedAccountNotFound = errors.New("managed account not found")
137 changes: 137 additions & 0 deletions managed_account.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
package megaport

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

type ManagedAccountService interface {
// ListManagedAccounts retrieves a list of managed accounts. Megaport Partners can use this command to list all the managed companies linked to their account.
ListManagedAccounts(ctx context.Context) ([]*ManagedAccount, error)
// CreateManagedAccount creates a new managed account. As a Megaport Partner, use this endpoint to create a new managed company.
CreateManagedAccount(ctx context.Context, req *ManagedAccountRequest) (*ManagedAccount, error)
// UpdateManagedAccount updates an existing managed account. As a Megaport Partner, use this endpoint to update an existing managed company. You identify the company by providing the companyUid as a parameter for the endpoint.
UpdateManagedAccount(ctx context.Context, companyUID string, req *ManagedAccountRequest) (*ManagedAccount, error)
// GetManagedAccount retrieves a managed account by name. As a Megaport Partner, use this endpoint to retrieve a managed company by name.
GetManagedAccount(ctx context.Context, companyUID string, managedAccountName string) (*ManagedAccount, error)
}

type ManagedAccountServiceOp struct {
Client *Client
}

type ManagedAccount struct {
AccountRef string `json:"accountRef"`
AccountName string `json:"accountName"`
CompanyUID string `json:"companyUid"`
}

type ManagedAccountRequest struct {
AccountName string `json:"accountName"` // A required string that specifies a unique, easily identifiable name for the account. The length can range from 1 to 128 characters.
AccountRef string `json:"accountRef"` // A required string that specifies a reference ID for the managed account. The accountRef is typically an identifier used in partner systems (for example, CRM or billing). This value is shown on the invoices as the Managed Account Reference. The accountRef also identifies the account in email notifications. (The accountRef value maps to the Managed Account UID in the Portal interface.)
}

type ManagedAccountAPIResponse struct {
Message string `json:"message"`
Terms string `json:"terms"`
Data *ManagedAccount `json:"data"`
}

type ManagedAccountListAPIResponse struct {
Message string `json:"message"`
Terms string `json:"terms"`
Data []*ManagedAccount `json:"data"`
}

// NewManagedAccountService creates a new instance of the ManagedAccount Service.
func NewManagedAccountService(c *Client) *ManagedAccountServiceOp {
return &ManagedAccountServiceOp{
Client: c,
}
}

func (svc *ManagedAccountServiceOp) ListManagedAccounts(ctx context.Context) ([]*ManagedAccount, error) {
path := "/v2/managedCompanies"
req, err := svc.Client.NewRequest(ctx, "GET", path, nil)
if err != nil {
return nil, err
}

response, err := svc.Client.Do(ctx, req, nil)
if err != nil {
return nil, err
}

defer response.Body.Close()
body, fileErr := io.ReadAll(response.Body)

if fileErr != nil {
return nil, fileErr
}

var apiResponse *ManagedAccountListAPIResponse

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

return apiResponse.Data, nil
}

func (svc *ManagedAccountServiceOp) CreateManagedAccount(ctx context.Context, req *ManagedAccountRequest) (*ManagedAccount, error) {
path := "/v2/managedCompanies"
clientReq, err := svc.Client.NewRequest(ctx, "POST", path, req)
if err != nil {
return nil, err
}
response, err := svc.Client.Do(ctx, clientReq, nil)
if err != nil {
return nil, err
}
defer response.Body.Close()
body, err := io.ReadAll(response.Body)
if err != nil {
return nil, err
}
var createManagedAccountResponse *ManagedAccountAPIResponse
if err := json.Unmarshal(body, &createManagedAccountResponse); err != nil {
return nil, err
}
return createManagedAccountResponse.Data, nil
}

func (svc *ManagedAccountServiceOp) UpdateManagedAccount(ctx context.Context, companyUID string, req *ManagedAccountRequest) (*ManagedAccount, error) {
path := "/v2/managedCompanies/" + companyUID
clientReq, err := svc.Client.NewRequest(ctx, "PUT", path, req)
if err != nil {
return nil, err
}
response, err := svc.Client.Do(ctx, clientReq, nil)
if err != nil {
return nil, err
}
defer response.Body.Close()
body, err := io.ReadAll(response.Body)
if err != nil {
return nil, err
}
var updateManagedAccountResponse *ManagedAccountAPIResponse
if err := json.Unmarshal(body, &updateManagedAccountResponse); err != nil {
return nil, err
}
return updateManagedAccountResponse.Data, nil
}

func (svc *ManagedAccountServiceOp) GetManagedAccount(ctx context.Context, companyUID string, managedAccountName string) (*ManagedAccount, error) {
accounts, err := svc.ListManagedAccounts(ctx)
if err != nil {
return nil, err
}
for _, account := range accounts {
if account.AccountName == managedAccountName {
return account, nil
}
}
return nil, ErrManagedAccountNotFound
}
165 changes: 165 additions & 0 deletions managed_account_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
package megaport

import (
"context"
"fmt"
"net/http"
"net/http/httptest"
"net/url"
"testing"

"github.com/stretchr/testify/suite"
)

// ManagedAccountClientTestSuite tests the Managed Account service client
type ManagedAccountClientTestSuite struct {
ClientTestSuite
}

func TestManagedAccountClientTestSuite(t *testing.T) {
t.Parallel()
suite.Run(t, new(PortClientTestSuite))
}

func (suite *ManagedAccountClientTestSuite) SetupTest() {
suite.mux = http.NewServeMux()
suite.server = httptest.NewServer(suite.mux)

suite.client = NewClient(nil, nil)
url, _ := url.Parse(suite.server.URL)
suite.client.BaseURL = url
}

func (suite *ManagedAccountClientTestSuite) TearDownTest() {
suite.server.Close()
}

func (suite *ManagedAccountClientTestSuite) TestCreateManagedAccount() {
ctx := context.Background()
createReq := &ManagedAccountRequest{
AccountName: "Test Account",
AccountRef: "test-account",
}
path := "/v2/managedCompanies"
jblob := `{
"message": "New managed company has been successfully created.",
"terms": "This data is subject to the Acceptable Use Policy https://www.megaport.com/legal/acceptable-use-policy",
"data": {
"accountRef": "555-1212-0317-1967",
"accountName": "Best Company Ever",
"companyUid": "fd404dc9-9efd-43c1-9e0b-a58a9d250130"
}
}`
suite.mux.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) {
suite.testMethod(r, http.MethodPost)
fmt.Fprint(w, jblob)
})
createRes, err := suite.client.ManagedAccountService.CreateManagedAccount(ctx, createReq)
suite.NoError(err)
suite.NotNil(createRes)
want := &ManagedAccount{
AccountRef: "555-1212-0317-1967",
AccountName: "Best Company Ever",
CompanyUID: "fd404dc9-9efd-43c1-9e0b-a58a9d250130",
}
suite.Equal(want, createRes)
}

func (suite *ManagedAccountClientTestSuite) TestListManagedAccounts() {
ctx := context.Background()
path := "/v2/managedCompanies"
jblob := `{
"message": "Managed Accounts.",
"terms": "This data is subject to the Acceptable Use Policy https://www.megaport.com/legal/acceptable-use-policy",
"data": [
{
"accountRef": "AUS-BNE-4101-KK",
"accountName": "Demo Company",
"companyUid": "ccfcf1dc-cf38-4526-9f2f-13d36a2441db"
},
{
"accountRef": "555-1212-0317-1967",
"accountName": "Best Company Ever",
"companyUid": "fd404dc9-9efd-43c1-9e0b-a58a9d250130"
}
]
}`
want := []*ManagedAccount{
{
AccountRef: "AUS-BNE-4101-KK",
AccountName: "Demo Company",
CompanyUID: "ccfcf1dc-cf38-4526-9f2f-13d36a2441db",
},
{
AccountRef: "555-1212-0317-1967",
AccountName: "Best Company Ever",
CompanyUID: "fd404dc9-9efd-43c1-9e0b-a58a9d250130",
},
}
suite.mux.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) {
suite.testMethod(r, http.MethodGet)
fmt.Fprint(w, jblob)
})
listRes, err := suite.client.ManagedAccountService.ListManagedAccounts(ctx)
suite.NoError(err)
suite.NotNil(listRes)
suite.Equal(want, listRes)
}

func (suite *ManagedAccountClientTestSuite) TestUpdateManagedAccount() {
ctx := context.Background()
updateReq := &ManagedAccountRequest{
AccountName: "Test Account",
AccountRef: "test-account",
}
path := "/v2/managedCompanies/fd404dc9-9efd-43c1-9e0b-a58a9d250130"
jblob := `{
"message": "Managed company has been successfully updated.",
"terms": "This data is subject to the Acceptable Use Policy https://www.megaport.com/legal/acceptable-use-policy",
"data": {
"accountRef": "555-1212-0317-1967",
"accountName": "Best Company Ever",
"companyUid": "fd404dc9-9efd-43c1-9e0b-a58a9d250130"
}
}`
want := &ManagedAccount{
AccountRef: "555-1212-0317-1967",
AccountName: "Best Company Ever",
CompanyUID: "fd404dc9-9efd-43c1-9e0b-a58a9d250130",
}
suite.mux.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) {
suite.testMethod(r, http.MethodPatch)
fmt.Fprint(w, jblob)
})
updateRes, err := suite.client.ManagedAccountService.UpdateManagedAccount(ctx, "fd404dc9-9efd-43c1-9e0b-a58a9d250130", updateReq)
suite.NoError(err)
suite.NotNil(updateRes)
suite.Equal(want, updateRes)
}

func (suite *ManagedAccountClientTestSuite) TestGetManagedAccount() {
ctx := context.Background()
path := "/v2/managedCompanies/fd404dc9-9efd-43c1-9e0b-a58a9d250130"
jblob := `{
"message": "Managed company details.",
"terms": "This data is subject to the Acceptable Use Policy https://www.megaport.com/legal/acceptable-use-policy",
"data": {
"accountRef": "555-1212-0317-1967",
"accountName": "Best Company Ever",
"companyUid": "fd404dc9-9efd-43c1-9e0b-a58a9d250130"
}
}`
want := &ManagedAccount{
AccountRef: "555-1212-0317-1967",
AccountName: "Best Company Ever",
CompanyUID: "fd404dc9-9efd-43c1-9e0b-a58a9d250130",
}
suite.mux.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) {
suite.testMethod(r, http.MethodGet)
fmt.Fprint(w, jblob)
})
getRes, err := suite.client.ManagedAccountService.GetManagedAccount(ctx, "fd404dc9-9efd-43c1-9e0b-a58a9d250130", "Best Company Ever")
suite.NoError(err)
suite.NotNil(getRes)
suite.Equal(want, getRes)
}

0 comments on commit 74c20ee

Please sign in to comment.