Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DASH-411: Add organization invitation CRUD to go sdk #332

Merged
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
35 changes: 25 additions & 10 deletions organization_invitation.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,31 @@ package clerk

import "encoding/json"

type PublicOrganizationData struct {
ID string `json:"id"`
Name string `json:"name"`
Slug string `json:"slug"`
ImageURL *string `json:"image_url,omitempty"`
HasImage bool `json:"has_image"`
}

type OrganizationInvitation struct {
APIResource
Object string `json:"object"`
ID string `json:"id"`
EmailAddress string `json:"email_address"`
Role string `json:"role"`
OrganizationID string `json:"organization_id"`
Status string `json:"status"`
PublicMetadata json.RawMessage `json:"public_metadata"`
PrivateMetadata json.RawMessage `json:"private_metadata"`
CreatedAt int64 `json:"created_at"`
UpdatedAt int64 `json:"updated_at"`
Object string `json:"object"`
ID string `json:"id"`
EmailAddress string `json:"email_address"`
Role string `json:"role"`
OrganizationID string `json:"organization_id"`
PublicOrganizationData *PublicOrganizationData `json:"public_organization_data,omitempty"`
Status string `json:"status"`
PublicMetadata json.RawMessage `json:"public_metadata"`
PrivateMetadata json.RawMessage `json:"private_metadata"`
CreatedAt int64 `json:"created_at"`
UpdatedAt int64 `json:"updated_at"`
}

type OrganizationInvitationList struct {
APIResource
OrganizationInvitations []*OrganizationInvitation `json:"data"`
TotalCount int64 `json:"total_count"`
}
15 changes: 15 additions & 0 deletions organizationinvitation/api.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

65 changes: 65 additions & 0 deletions organizationinvitation/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"context"
"encoding/json"
"net/http"
"net/url"

"github.com/clerk/clerk-sdk-go/v2"
)
Expand Down Expand Up @@ -47,3 +48,67 @@ func (c *Client) Create(ctx context.Context, params *CreateParams) (*clerk.Organ
err = c.Backend.Call(ctx, req, invitation)
return invitation, err
}

type ListParams struct {
clerk.APIParams
clerk.ListParams
OrganizationID string
Statuses *[]string
}

func (p *ListParams) ToQuery() url.Values {
q := p.ListParams.ToQuery()

if p.Statuses != nil && len(*p.Statuses) > 0 {
q["status"] = *p.Statuses
}

return q
}

// List returns a list of organization invitations
func (c *Client) List(ctx context.Context, params *ListParams) (*clerk.OrganizationInvitationList, error) {
path, err := clerk.JoinPath(path, params.OrganizationID, "/invitations")
if err != nil {
return nil, err
}
req := clerk.NewAPIRequest(http.MethodGet, path)
req.SetParams(params)
invitation := &clerk.OrganizationInvitationList{}
err = c.Backend.Call(ctx, req, invitation)
return invitation, err
}

type GetParams struct {
OrganizationID string
ID string
}

// Get retrieves the detail for an organization invitation.
func (c *Client) Get(ctx context.Context, params *GetParams) (*clerk.OrganizationInvitation, error) {
path, err := clerk.JoinPath(path, params.OrganizationID, "/invitations", params.ID)
if err != nil {
return nil, err
}
req := clerk.NewAPIRequest(http.MethodGet, path)
invitation := &clerk.OrganizationInvitation{}
err = c.Backend.Call(ctx, req, invitation)
return invitation, err
}

type RevokeParams struct {
OrganizationID string
ID string
}

// Revoke marks the organization invitation as revoked.
func (c *Client) Revoke(ctx context.Context, params *RevokeParams) (*clerk.OrganizationInvitation, error) {
path, err := clerk.JoinPath(path, params.OrganizationID, "/invitations", params.ID, "/revoke")
if err != nil {
return nil, err
}
req := clerk.NewAPIRequest(http.MethodPost, path)
invitation := &clerk.OrganizationInvitation{}
err = c.Backend.Call(ctx, req, invitation)
return invitation, err
}
166 changes: 166 additions & 0 deletions organizationinvitation/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"encoding/json"
"fmt"
"net/http"
"net/url"
"testing"

"github.com/clerk/clerk-sdk-go/v2"
Expand Down Expand Up @@ -62,3 +63,168 @@ func TestOrganizationInvitationClientCreate_Error(t *testing.T) {
require.Equal(t, 1, len(apiErr.Errors))
require.Equal(t, "create-error-code", apiErr.Errors[0].Code)
}

func TestOrganizationInvitationClientList(t *testing.T) {
t.Parallel()
organizationID := "org_123"
id := "orginv_123"
statuses := []string{"pending", "accepted"}
limit := int64(10)
config := &clerk.ClientConfig{}
config.HTTPClient = &http.Client{
Transport: &clerktest.RoundTripper{
T: t,
Out: json.RawMessage(fmt.Sprintf(`{"data":[{"id":"%s","object":"organization_invitation","email_address":"string","role":"string","organization_id":"%s","status":"string","public_metadata":{},"private_metadata":{},"created_at":0,"updated_at":0}],"total_count":1}`, id, organizationID)),
Method: http.MethodGet,
Path: "/v1/organizations/" + organizationID + "/invitations",
Query: &url.Values{
"limit": []string{fmt.Sprintf("%d", limit)},
"status": statuses,
},
},
}
client := NewClient(config)
response, err := client.List(context.Background(), &ListParams{
OrganizationID: organizationID,
ListParams: clerk.ListParams{
Limit: clerk.Int64(limit),
},
Statuses: &statuses,
})
require.NoError(t, err)
require.Len(t, response.OrganizationInvitations, 1)
require.Equal(t, id, response.OrganizationInvitations[0].ID)
require.Equal(t, organizationID, response.OrganizationInvitations[0].OrganizationID)
require.Equal(t, int64(1), response.TotalCount)
}

func TestOrganizationInvitationClientList_Error(t *testing.T) {
t.Parallel()
config := &clerk.ClientConfig{}
config.HTTPClient = &http.Client{
Transport: &clerktest.RoundTripper{
T: t,
Status: http.StatusBadRequest,
Out: json.RawMessage(`{
"errors":[{
"code":"list-error-code"
}],
"clerk_trace_id":"list-trace-id"
}`),
},
}
client := NewClient(config)
_, err := client.List(context.Background(), &ListParams{OrganizationID: "org_123"})
require.Error(t, err)
apiErr, ok := err.(*clerk.APIErrorResponse)
require.True(t, ok)
require.Equal(t, "list-trace-id", apiErr.TraceID)
require.Equal(t, 1, len(apiErr.Errors))
require.Equal(t, "list-error-code", apiErr.Errors[0].Code)
}

func TestOrganizationInvitationClientGet(t *testing.T) {
t.Parallel()
organizationID := "org_123"
id := "orginv_123"
config := &clerk.ClientConfig{}
config.HTTPClient = &http.Client{
Transport: &clerktest.RoundTripper{
T: t,
Out: json.RawMessage(fmt.Sprintf(`{"id":"%s","object":"organization_invitation","email_address":"string","role":"string","organization_id":"%s","status":"string","public_metadata":{},"private_metadata":{},"created_at":0,"updated_at":0}`, id, organizationID)),
Method: http.MethodGet,
Path: "/v1/organizations/" + organizationID + "/invitations/" + id,
},
}
client := NewClient(config)
response, err := client.Get(context.Background(), &GetParams{
OrganizationID: organizationID,
ID: id,
})
require.NoError(t, err)
require.Equal(t, id, response.ID)
require.Equal(t, organizationID, response.OrganizationID)
}

func TestOrganizationInvitationClientGet_Error(t *testing.T) {
t.Parallel()
organizationID := "org_123"
id := "orginv_123"
config := &clerk.ClientConfig{}
config.HTTPClient = &http.Client{
Transport: &clerktest.RoundTripper{
T: t,
Status: http.StatusBadRequest,
Out: json.RawMessage(`{
"errors":[{
"code":"get-error-code"
}],
"clerk_trace_id":"get-trace-id"
}`),
},
}
client := NewClient(config)
_, err := client.Get(context.Background(), &GetParams{
OrganizationID: organizationID,
ID: id,
})
require.Error(t, err)
apiErr, ok := err.(*clerk.APIErrorResponse)
require.True(t, ok)
require.Equal(t, "get-trace-id", apiErr.TraceID)
require.Equal(t, 1, len(apiErr.Errors))
require.Equal(t, "get-error-code", apiErr.Errors[0].Code)
}

func TestOrganizationInvitationClientRevoke(t *testing.T) {
t.Parallel()
organizationID := "org_123"
id := "orginv_123"
config := &clerk.ClientConfig{}
config.HTTPClient = &http.Client{
Transport: &clerktest.RoundTripper{
T: t,
Out: json.RawMessage(fmt.Sprintf(`{"id":"%s","object":"organization_invitation","email_address":"string","role":"string","organization_id":"%s","status":"string","public_metadata":{},"private_metadata":{},"created_at":0,"updated_at":0}`, id, organizationID)),
Method: http.MethodPost,
Path: "/v1/organizations/" + organizationID + "/invitations/" + id + "/revoke",
},
}
client := NewClient(config)
response, err := client.Revoke(context.Background(), &RevokeParams{
OrganizationID: organizationID,
ID: id,
})
require.NoError(t, err)
require.Equal(t, id, response.ID)
require.Equal(t, organizationID, response.OrganizationID)
}

func TestOrganizationInvitationClientRevoke_Error(t *testing.T) {
t.Parallel()
organizationID := "org_123"
id := "orginv_123"
config := &clerk.ClientConfig{}
config.HTTPClient = &http.Client{
Transport: &clerktest.RoundTripper{
T: t,
Status: http.StatusBadRequest,
Out: json.RawMessage(`{
"errors":[{
"code":"revoke-error-code"
}],
"clerk_trace_id":"revoke-trace-id"
}`),
},
}
client := NewClient(config)
_, err := client.Revoke(context.Background(), &RevokeParams{
OrganizationID: organizationID,
ID: id,
})
require.Error(t, err)
apiErr, ok := err.(*clerk.APIErrorResponse)
require.True(t, ok)
require.Equal(t, "revoke-trace-id", apiErr.TraceID)
require.Equal(t, 1, len(apiErr.Errors))
require.Equal(t, "revoke-error-code", apiErr.Errors[0].Code)
}
Loading