diff --git a/CHANGELOG.md b/CHANGELOG.md index e1f607f..31917df 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## Next release +- Add support for bulk invitation creation with the `invitation.BulkCreate` method. - Add `NameQuery` to `user.ListParams`. ## 2.1.1 diff --git a/invitation.go b/invitation.go index d94a6bc..92d8166 100644 --- a/invitation.go +++ b/invitation.go @@ -16,6 +16,11 @@ type Invitation struct { UpdatedAt int64 `json:"updated_at"` } +type Invitations struct { + APIResource + Invitations []*Invitation `json:"data"` +} + type InvitationList struct { APIResource Invitations []*Invitation `json:"data"` diff --git a/invitation/api.go b/invitation/api.go index f0e74ec..72e18d5 100644 --- a/invitation/api.go +++ b/invitation/api.go @@ -18,6 +18,11 @@ func Create(ctx context.Context, params *CreateParams) (*clerk.Invitation, error return getClient().Create(ctx, params) } +// BulkCreate creates multiple invitations. +func BulkCreate(ctx context.Context, params *BulkCreateParams) (*clerk.Invitations, error) { + return getClient().BulkCreate(ctx, params) +} + // Revoke revokes a pending invitation. func Revoke(ctx context.Context, id string) (*clerk.Invitation, error) { return getClient().Revoke(ctx, id) diff --git a/invitation/client.go b/invitation/client.go index 4ac0099..9d43352 100644 --- a/invitation/client.go +++ b/invitation/client.go @@ -76,6 +76,45 @@ func (c *Client) Create(ctx context.Context, params *CreateParams) (*clerk.Invit return invitation, err } +type BulkCreateParams struct { + clerk.APIParams + Invitations []*CreateParams +} + +func (b BulkCreateParams) MarshalJSON() ([]byte, error) { + return json.Marshal(b.Invitations) +} + +type bulkCreateResponse struct { + clerk.APIResource + Invitations []*clerk.Invitation +} + +func (b *bulkCreateResponse) UnmarshalJSON(data []byte) error { + return json.Unmarshal(data, &b.Invitations) +} + +// BulkCreate creates multiple invitations. +func (c *Client) BulkCreate(ctx context.Context, params *BulkCreateParams) (*clerk.Invitations, error) { + path, err := clerk.JoinPath(path, "bulk") + if err != nil { + return nil, err + } + + req := clerk.NewAPIRequest(http.MethodPost, path) + req.SetParams(params) + + res := &bulkCreateResponse{} + if err := c.Backend.Call(ctx, req, res); err != nil { + return nil, err + } + + return &clerk.Invitations{ + APIResource: res.APIResource, + Invitations: res.Invitations, + }, nil +} + // Revoke revokes a pending invitation. func (c *Client) Revoke(ctx context.Context, id string) (*clerk.Invitation, error) { path, err := clerk.JoinPath(path, id, "revoke") diff --git a/invitation/invitation_test.go b/invitation/invitation_test.go index 9f8e5fb..1fad64c 100644 --- a/invitation/invitation_test.go +++ b/invitation/invitation_test.go @@ -162,6 +162,46 @@ func TestInvitationCreate_Error(t *testing.T) { require.Equal(t, "create-error-code", apiErr.Errors[0].Code) } +func TestBulkInvitationCreate(t *testing.T) { + emailAddresses := []string{"foo@bar.com", "bar@foo.com"} + ids := []string{"inv_123", "inv_456"} + invitations := []*clerk.Invitation{ + {ID: ids[0], EmailAddress: emailAddresses[0]}, + {ID: ids[1], EmailAddress: emailAddresses[1]}, + } + + clerk.SetBackend(clerk.NewBackend(&clerk.BackendConfig{ + HTTPClient: &http.Client{ + Transport: &clerktest.RoundTripper{ + T: t, + In: json.RawMessage(fmt.Sprintf(`[{"email_address":"%s"},{"email_address":"%s"}]`, emailAddresses[0], emailAddresses[1])), + Out: json.RawMessage(fmt.Sprintf( + `[{"id":"%s","email_address":"%s"},{"id":"%s","email_address":"%s"}]`, + ids[0], emailAddresses[0], ids[1], emailAddresses[1], + )), + Method: http.MethodPost, + Path: "/v1/invitations/bulk", + }, + }, + })) + + params := BulkCreateParams{ + Invitations: []*CreateParams{ + {EmailAddress: emailAddresses[0]}, + {EmailAddress: emailAddresses[1]}, + }, + } + + response, err := BulkCreate(context.Background(), ¶ms) + require.NoError(t, err) + require.Len(t, invitations, 2) + + for i, invitation := range response.Invitations { + require.Equal(t, ids[i], invitation.ID) + require.Equal(t, emailAddresses[i], invitation.EmailAddress) + } +} + func TestInvitationRevoke(t *testing.T) { id := "inv_123" clerk.SetBackend(clerk.NewBackend(&clerk.BackendConfig{