Skip to content

Commit

Permalink
Merge pull request #40 from latitudesh/PD-3584-SDK-Add-Account-endpoints
Browse files Browse the repository at this point in the history
Add Accounts and Role endpoints
  • Loading branch information
ynhummel authored Apr 29, 2024
2 parents cd64af7 + e8d01e4 commit 3577b99
Show file tree
Hide file tree
Showing 8 changed files with 321 additions and 21 deletions.
136 changes: 136 additions & 0 deletions accounts.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
package latitude

const userBasePath = "/user/profile"
const userTeamsPath = "/user/teams"

// UserService interface defines available Account methods
type UserService interface {
Get(*GetOptions) (*User, *Response, error)
Update(string, *UserUpdateRequest) (*User, *Response, error)
List(listOpt *ListOptions) ([]Team, *Response, error)
}

// UserServiceOp implements UserService
type UserServiceOp struct {
client requestDoer
}

type UserGetResponse struct {
Data UserGetData `json:"data"`
Meta meta `json:"meta"`
}

type UserGetData struct {
ID string `json:"id"`
Type string `json:"type"`
Attributes UserAttributes `json:"attributes"`
}

type UserAttributes struct {
FirstName string `json:"first_name"`
LastName string `json:"last_name"`
Email string `json:"email"`
MfaEnabled bool `json:"mfa_enabled"`
CreatedAt string `json:"created_at"`
UpdatedAt string `json:"updated_at"`
Role UserRole `json:"role"`
}

type UserUpdateRequest struct {
Data UserUpdateData `json:"data"`
}

type UserUpdateData struct {
ID string `json:"id"`
Type string `json:"type"`
Attributes UserUpdateAttributes `json:"attributes"`
}

type UserUpdateAttributes struct {
FirstName string `json:"first_name"`
LastName string `json:"last_name"`
Role AvailableRole `json:"role"`
AuthenticationFactorId string `json:"authentication_factor_id"`
}

type UserRole struct {
Role
createdAt string
updatedAt string
}

type User struct {
ID string `json:"id"`
FirstName string `json:"first_name"`
LastName string `json:"last_name"`
Email string `json:"email"`
MfaEnabled bool `json:"mfa_enabled"`
CreatedAt string `json:"created_at"`
UpdatedAt string `json:"updated_at"`
Role string `json:"role"`
}

// Flatten latitude API data structure
func NewFlatUser(md UserGetData) User {
return User{
md.ID,
md.Attributes.FirstName,
md.Attributes.LastName,
md.Attributes.Email,
md.Attributes.MfaEnabled,
md.Attributes.CreatedAt,
md.Attributes.UpdatedAt,
md.Attributes.Role.Name,
}
}

// Get the current User profile
func (s *UserServiceOp) Get(opts *GetOptions) (*User, *Response, error) {
endpointPath := userBasePath
apiPathQuery := opts.WithQuery(endpointPath)
user := new(UserGetResponse)
resp, err := s.client.DoRequest("GET", apiPathQuery, nil, user)
if err != nil {
return nil, resp, err
}

flatUser := NewFlatUser(user.Data)
return &flatUser, resp, err
}

// Update the User profile
func (s *UserServiceOp) Update(id string, updateRequest *UserUpdateRequest) (*User, *Response, error) {
apiPath := userBasePath
user := new(UserGetResponse)

resp, err := s.client.DoRequest("PATCH", apiPath, updateRequest, user)
if err != nil {
return nil, resp, err
}

flatUser := NewFlatUser(user.Data)
return &flatUser, resp, err
}

// List the current User teams
func (s *UserServiceOp) List(opts *ListOptions) ([]Team, *Response, error) {
apiPathQuery := userTeamsPath
teams := []Team{}

for {
res := new(TeamGetResponse)

resp, err := s.client.DoRequest("GET", apiPathQuery, nil, res)
if err != nil {
return nil, resp, err
}

teams = append(teams, NewFlatTeamList(res.Data)...)

if apiPathQuery = nextPage(res.Meta, opts); apiPathQuery != "" {
continue
}

return teams, resp, nil
}
}
34 changes: 34 additions & 0 deletions accounts_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package latitude

import (
"testing"
)

func TestAccAccountsBasic(t *testing.T) {
skipUnlessAcceptanceTestsAllowed(t)
c, stopRecord := setup(t)
defer stopRecord()

t.Run("Get User Account", func(t *testing.T) {
profile, _, err := c.Users.Get(nil)
if err != nil {
t.Fatal(err)
}

if profile == nil {
t.Fatal("Could not find user account")
}
})

t.Run("List user teams", func(t *testing.T) {
teams, _, err := c.Users.List(nil)
if err != nil {
t.Fatal(err)
}

if len(teams) < 1 {
t.Fatal("Team must have at least a owner")
}
})

}
4 changes: 4 additions & 0 deletions latitude.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,8 @@ type Client struct {
Teams TeamService
Bandwidth BandwidthService
Members MemberService
Roles RoleService
Users UserService
}

type requestDoer interface {
Expand Down Expand Up @@ -338,6 +340,8 @@ func NewClientWithBaseURL(apiKey string, httpClient *http.Client, apiBaseURL str
c.VirtualNetworks = &VirtualNetworkServiceOp{client: c}
c.VlanAssignments = &VlanAssignmentServiceOp{client: c}
c.Members = &MemberServiceOp{client: c}
c.Roles = &RoleServiceOp{client: c}
c.Users = &UserServiceOp{client: c}
c.debug = os.Getenv(debugEnvVar) != ""

return c, nil
Expand Down
100 changes: 100 additions & 0 deletions roles.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
package latitude

import "path"

const roleBasePath = "/roles"

// RoleService interface defines available role methods
type RoleService interface {
Get(string, *GetOptions) (*Role, *Response, error)
List(*ListOptions) ([]Role, *Response, error)
}

// RoleServiceOp implements RoleService
type RoleServiceOp struct {
client requestDoer
}

type AvailableRole string

const (
Owner AvailableRole = "owner"
Administrator AvailableRole = "administrator"
Collaborator AvailableRole = "collaborator"
Billing AvailableRole = "billing"
)

type RoleGetResponse struct {
Data RoleData `json:"data"`
Meta meta `json:"meta"`
}

type RoleData struct {
ID string `json:"id"`
Type string `json:"type"`
Attributes RoleAttributes `json:"attributes"`
}

type RoleAttributes struct {
Name string `json:"name"`
}

type RoleListResponse struct {
Data []RoleData `json:"data"`
Meta meta `json:"meta"`
}

type Role struct {
ID string `json:"id"`
Name string `json:"name"`
}

func NewFlatRole(rd RoleData) Role {
return Role{
ID: rd.ID,
Name: rd.Attributes.Name,
}
}

func NewFlatRoleList(rd []RoleData) []Role {
var res []Role
for _, role := range rd {
res = append(res, NewFlatRole(role))
}
return res
}

func (s *RoleServiceOp) Get(RoleID string, opts *GetOptions) (*Role, *Response, error) {
endpointPath := path.Join(roleBasePath, RoleID)
apiPathQuery := opts.WithQuery(endpointPath)
role := new(RoleGetResponse)
resp, err := s.client.DoRequest("GET", apiPathQuery, nil, role)
if err != nil {
return nil, resp, err
}

flatRole := NewFlatRole(role.Data)
return &flatRole, resp, err
}

func (s *RoleServiceOp) List(opts *ListOptions) ([]Role, *Response, error) {
apiPathQuery := opts.WithQuery(roleBasePath)
roles := []Role{}

for {
res := new(RoleListResponse)

resp, err := s.client.DoRequest("GET", apiPathQuery, nil, res)
if err != nil {
return nil, resp, err
}

roles = append(roles, NewFlatRoleList(res.Data)...)

if apiPathQuery = nextPage(res.Meta, opts); apiPathQuery != "" {
continue
}

return roles, resp, nil
}
}
35 changes: 35 additions & 0 deletions roles_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package latitude

import (
"testing"
)

func TestAccRolesBasic(t *testing.T) {
skipUnlessAcceptanceTestsAllowed(t)
c, stopRecord := setup(t)
defer stopRecord()

// List Roles
roles, _, err := c.Roles.List(nil)
if err != nil {
t.Fatal(err)
}

if len(roles) < 1 {
t.Fatal("Team must have at least a role")
}

//Get Role
role, _, err := c.Roles.Get(roles[0].ID, nil)
if err != nil {
t.Fatal(err)
}

// Check Role data
if role.ID != roles[0].ID {
t.Fatalf("Expected the id of the GOT role to be %s, not %s", roles[0].ID, role.ID)
}
if role.Name != roles[0].Name {
t.Fatalf("Expected the line of the GOT plan to be %s, not %s", roles[0].Name, role.Name)
}
}
22 changes: 4 additions & 18 deletions team_members.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,6 @@ type MemberListAttributes struct {
Role Role `json:"role"`
}

type Role struct {
ID string `json:"id"`
Name string `json:"name"`
}

type MemberResponse struct {
Data MemberData `json:"data"`
Meta meta `json:"meta"`
Expand Down Expand Up @@ -73,21 +68,12 @@ type MemberCreateData struct {
}

type MemberCreateAttributes struct {
FirstName string `json:"first_name"`
LastName string `json:"last_name"`
Email string `json:"email"`
Role MemberRole `json:"role"`
FirstName string `json:"first_name"`
LastName string `json:"last_name"`
Email string `json:"email"`
Role AvailableRole `json:"role"`
}

type MemberRole string

const (
Owner MemberRole = "owner"
Administrator MemberRole = "administrator"
Collaborator MemberRole = "collaborator"
Billing MemberRole = "billing"
)

type Member struct {
ID string `json:"id"`
FirstName string `json:"first_name"`
Expand Down
3 changes: 0 additions & 3 deletions team_members_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ import (
"testing"
)

const ()

func deleteMember(t *testing.T, c *Client, id string) {
if _, err := c.Members.Delete(id); err != nil {
t.Fatal(err)
Expand All @@ -16,7 +14,6 @@ func TestAccMembersBasic(t *testing.T) {
skipUnlessAcceptanceTestsAllowed(t)
c, stopRecord := setup(t)
defer stopRecord()
defer projectTeardown(c)

t.Run("List Members", func(t *testing.T) {
// List Members
Expand Down
8 changes: 8 additions & 0 deletions teams.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,14 @@ func NewFlatTeam(t TeamData) Team {
}
}

func NewFlatTeamList(td []TeamData) []Team {
var res []Team
for _, team := range td {
res = append(res, NewFlatTeam(team))
}
return res
}

// Get returns a Team by id
func (u *TeamServiceOp) Get() (*Team, *Response, error) {
var flatTeam Team
Expand Down

0 comments on commit 3577b99

Please sign in to comment.