Skip to content
This repository has been archived by the owner on Jun 21, 2024. It is now read-only.

add Invitations service and User creation methods #346

Merged
merged 3 commits into from
Sep 28, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
155 changes: 155 additions & 0 deletions invitations.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
package packngo

import (
"path"
)

const (
invitationsBasePath = "/invitations"
)

// InvitationService interface defines available invitation methods
type InvitationService interface {
Create(string, *InvitationCreateRequest, *GetOptions) (*Invitation, *Response, error)
List(string, *ListOptions) ([]Invitation, *Response, error)
Get(string, *GetOptions) (*Invitation, *Response, error)
Accept(string, *InvitationUpdateRequest) (*Invitation, *Response, error)
Resend(string) (*Invitation, *Response, error)
Delete(string) (*Response, error)
}

type invitationsRoot struct {
Invitations []Invitation `json:"invitations"`
Meta meta `json:"meta"`
}

// Invitation represents an Equinix Metal invitation
type Invitation struct {
*Href `json:",inline"`
ID string `json:"id,omitempty"`
Invitation Href `json:"invitation,omitempty"`
InvitedBy Href `json:"invited_by,omitempty"`
Invitee string `json:"invitee,omitempty"`
Nonce string `json:"nonce,omitempty"`
Organization Href `json:"organization,omitempty"`
Projects []Href `json:"projects,omitempty"`
Roles []string `json:"roles,omitempty"`
CreatedAt *Timestamp `json:"created_at,omitempty"`
UpdatedAt *Timestamp `json:"updated_at,omitempty"`
}

// InvitationCreateRequest struct for InvitationService.Create
type InvitationCreateRequest struct {
// Invitee is the email address of the recipient
Invitee string `json:"invitee"`
Message string `json:"message,omitempty"`
ProjectsIDs []string `json:"projects_ids,omitempty"`
Roles []string `json:"roles,omitempty"`
}

// InvitationUpdateRequest struct for InvitationService.Update
type InvitationUpdateRequest struct{}

func (u Invitation) String() string {
return Stringify(u)
}

// InvitationServiceOp implements InvitationService
type InvitationServiceOp struct {
client *Client
}

var _ InvitationService = (*InvitationServiceOp)(nil)

// Lists open invitations to the project
func (s *InvitationServiceOp) List(organizationID string, opts *ListOptions) (invitations []Invitation, resp *Response, err error) {
endpointPath := path.Join(organizationBasePath, organizationID, invitationsBasePath)
apiPathQuery := opts.WithQuery(endpointPath)

for {
subset := new(invitationsRoot)

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

invitations = append(invitations, subset.Invitations...)

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

// Create a Invitation with the given InvitationCreateRequest. New invitation VerificationStage
// will be AccountCreated, unless InvitationCreateRequest contains an valid
// InvitationID and Nonce in which case the VerificationStage will be Verified.
func (s *InvitationServiceOp) Create(organizationID string, createRequest *InvitationCreateRequest, opts *GetOptions) (*Invitation, *Response, error) {
endpointPath := path.Join(organizationBasePath, organizationID, invitationsBasePath)
apiPathQuery := opts.WithQuery(endpointPath)
invitation := new(Invitation)

resp, err := s.client.DoRequest("POST", apiPathQuery, createRequest, invitation)
if err != nil {
return nil, resp, err
}

return invitation, resp, err
}

func (s *InvitationServiceOp) Get(invitationID string, opts *GetOptions) (*Invitation, *Response, error) {
if validateErr := ValidateUUID(invitationID); validateErr != nil {
return nil, nil, validateErr
}
endpointPath := path.Join(invitationsBasePath, invitationID)
apiPathQuery := opts.WithQuery(endpointPath)
invitation := new(Invitation)

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

return invitation, resp, err
}

// Update updates the current invitation
func (s *InvitationServiceOp) Delete(id string) (*Response, error) {
opts := &GetOptions{}
endpointPath := path.Join(invitationsBasePath, id)
apiPathQuery := opts.WithQuery(endpointPath)

return s.client.DoRequest("DELETE", apiPathQuery, nil, nil)
}

// Update updates the current invitation
func (s *InvitationServiceOp) Accept(id string, updateRequest *InvitationUpdateRequest) (*Invitation, *Response, error) {
opts := &GetOptions{}
endpointPath := path.Join(invitationsBasePath, id)
apiPathQuery := opts.WithQuery(endpointPath)
invitation := new(Invitation)

resp, err := s.client.DoRequest("PUT", apiPathQuery, updateRequest, invitation)
if err != nil {
return nil, resp, err
}

return invitation, resp, err
}

// Update updates the current invitation
func (s *InvitationServiceOp) Resend(id string) (*Invitation, *Response, error) {
opts := &GetOptions{}
endpointPath := path.Join(invitationsBasePath, id)
apiPathQuery := opts.WithQuery(endpointPath)
invitation := new(Invitation)

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

return invitation, resp, err
}
4 changes: 2 additions & 2 deletions packngo.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ type Client struct {
Events EventService
Facilities FacilityService
HardwareReservations HardwareReservationService
Invitations InvitationService
Metros MetroService
Notifications NotificationService
OperatingSystems OSService
Expand Down Expand Up @@ -339,7 +340,6 @@ func NewClient() (*Client, error) {
}
c := NewClientWithAuth("packngo lib", apiToken, nil)
return c, nil

}

// NewClientWithAuth initializes and returns a Client, use this to get an API Client to operate on
Expand Down Expand Up @@ -377,6 +377,7 @@ func NewClientWithBaseURL(consumerToken string, apiKey string, httpClient *http.
c.Events = &EventServiceOp{client: c}
c.Facilities = &FacilityServiceOp{client: c}
c.HardwareReservations = &HardwareReservationServiceOp{client: c}
c.Invitations = &InvitationServiceOp{client: c}
c.Metros = &MetroServiceOp{client: c}
c.Notifications = &NotificationServiceOp{client: c}
c.OperatingSystems = &OSServiceOp{client: c}
Expand All @@ -403,7 +404,6 @@ func NewClientWithBaseURL(consumerToken string, apiKey string, httpClient *http.
}

func checkResponse(r *http.Response) error {

if s := r.StatusCode; s >= 200 && s <= 299 {
// response is good, return
return nil
Expand Down
37 changes: 34 additions & 3 deletions user.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,17 @@ import (
"path"
)

const usersBasePath = "/users"
const userBasePath = "/user"
const (
usersBasePath = "/users"
userBasePath = "/user"
)

// UserService interface defines available user methods
type UserService interface {
Create(*UserCreateRequest) (*User, *Response, error)
Current() (*User, *Response, error)
List(*ListOptions) ([]User, *Response, error)
Get(string, *GetOptions) (*User, *Response, error)
Current() (*User, *Response, error)
Update(*UserUpdateRequest) (*User, *Response, error)
}

Expand Down Expand Up @@ -83,6 +86,17 @@ type UserLite struct {
AvatarThumbURL string `json:"avatar_thumb_url,omitempty"`
}

// UserCreateRequest struct for UserService.Create
type UserCreateRequest struct {
InvitationID string `json:"invitation_id,omitempty"`
Nonce string `json:"nonce,omitempty"`
FirstName string `json:"first_name,omitempty"`
LastName string `json:"last_name,omitempty"`
Password string `json:"password,omitempty"`
Customdata *interface{} `json:"customdata,omitempty"`
Emails []EmailRequest `json:"emails,omitempty"`
}

// UserUpdateRequest struct for UserService.Update
type UserUpdateRequest struct {
FirstName *string `json:"first_name,omitempty"`
Expand Down Expand Up @@ -124,6 +138,23 @@ func (s *UserServiceOp) List(opts *ListOptions) (users []User, resp *Response, e
}
}

// Create a User with the given UserCreateRequest. New user VerificationStage
// will be AccountCreated, unless UserCreateRequest contains an valid
// InvitationID and Nonce in which case the VerificationStage will be Verified.
func (s *UserServiceOp) Create(createRequest *UserCreateRequest) (*User, *Response, error) {
opts := &GetOptions{}
endpointPath := path.Join(usersBasePath)
apiPathQuery := opts.WithQuery(endpointPath)
user := new(User)

resp, err := s.client.DoRequest("POST", apiPathQuery, createRequest, user)
if err != nil {
return nil, resp, err
}

return user, resp, err
}

// Returns the user object for the currently logged-in user.
func (s *UserServiceOp) Current() (*User, *Response, error) {
user := new(User)
Expand Down