diff --git a/allowlist_identifier.go b/allowlist_identifier.go new file mode 100644 index 00000000..46da224a --- /dev/null +++ b/allowlist_identifier.go @@ -0,0 +1,18 @@ +package clerk + +type AllowlistIdentifier struct { + APIResource + Object string `json:"object"` + ID string `json:"id"` + Identifier string `json:"identifier"` + IdentifierType string `json:"identifier_type"` + InvitationID *string `json:"invitation_id,omitempty"` + CreatedAt int64 `json:"created_at"` + UpdatedAt int64 `json:"updated_at"` +} + +type AllowlistIdentifierList struct { + APIResource + AllowlistIdentifiers []*AllowlistIdentifier `json:"data"` + TotalCount int64 `json:"total_count"` +} diff --git a/allowlistidentifier/allowlist_identifier.go b/allowlistidentifier/allowlist_identifier.go new file mode 100644 index 00000000..12aa416f --- /dev/null +++ b/allowlistidentifier/allowlist_identifier.go @@ -0,0 +1,52 @@ +// Package allowlistidentifier provides the Allowlist Identifiers API. +package allowlistidentifier + +import ( + "context" + "fmt" + "net/http" + "net/url" + + "github.com/clerk/clerk-sdk-go/v2" +) + +const path = "/allowlist_identifiers" + +type CreateParams struct { + clerk.APIParams + Identifier *string `json:"identifier,omitempty"` + Notify *bool `json:"notify,omitempty"` +} + +// Create adds a new identifier to the allowlist. +func Create(ctx context.Context, params *CreateParams) (*clerk.AllowlistIdentifier, error) { + req := clerk.NewAPIRequest(http.MethodPost, path) + req.SetParams(params) + identifier := &clerk.AllowlistIdentifier{} + err := clerk.GetBackend().Call(ctx, req, identifier) + return identifier, err +} + +// Delete removes an identifier from the allowlist. +func Delete(ctx context.Context, id string) (*clerk.DeletedResource, error) { + path, err := url.JoinPath(path, id) + if err != nil { + return nil, err + } + req := clerk.NewAPIRequest(http.MethodDelete, path) + identifier := &clerk.DeletedResource{} + err = clerk.GetBackend().Call(ctx, req, identifier) + return identifier, err +} + +type ListParams struct { + clerk.APIParams +} + +// List returns all the identifiers in the allowlist. +func List(ctx context.Context, params *ListParams) (*clerk.AllowlistIdentifierList, error) { + req := clerk.NewAPIRequest(http.MethodGet, fmt.Sprintf("%s?paginated=true", path)) + list := &clerk.AllowlistIdentifierList{} + err := clerk.GetBackend().Call(ctx, req, list) + return list, err +} diff --git a/allowlistidentifier/allowlist_identifier_test.go b/allowlistidentifier/allowlist_identifier_test.go new file mode 100644 index 00000000..f3898843 --- /dev/null +++ b/allowlistidentifier/allowlist_identifier_test.go @@ -0,0 +1,124 @@ +package allowlistidentifier + +import ( + "bytes" + "context" + "encoding/json" + "fmt" + "io" + "net/http" + "testing" + + "github.com/clerk/clerk-sdk-go/v2" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestAllowlistIdentifierCreate(t *testing.T) { + identifier := "foo@bar.com" + id := "alid_123" + clerk.SetBackend(clerk.NewBackend(&clerk.BackendConfig{ + HTTPClient: &http.Client{ + Transport: &mockRoundTripper{ + T: t, + in: json.RawMessage(fmt.Sprintf(`{"identifier":"%s"}`, identifier)), + out: json.RawMessage(fmt.Sprintf(`{"id":"%s","identifier":"%s"}`, id, identifier)), + }, + }, + })) + + allowlistIdentifier, err := Create(context.Background(), &CreateParams{ + Identifier: clerk.String(identifier), + }) + require.NoError(t, err) + assert.Equal(t, id, allowlistIdentifier.ID) + assert.Equal(t, identifier, allowlistIdentifier.Identifier) +} + +func TestAllowlistIdentifierCreate_Error(t *testing.T) { + clerk.SetBackend(clerk.NewBackend(&clerk.BackendConfig{ + HTTPClient: &http.Client{ + Transport: &mockRoundTripper{ + T: t, + status: http.StatusBadRequest, + out: json.RawMessage(`{ + "errors":[{ + "code":"create-error-code" + }], + "clerk_trace_id":"create-trace-id" +}`), + }, + }, + })) + + _, err := Create(context.Background(), &CreateParams{}) + require.Error(t, err) + apiErr, ok := err.(*clerk.APIErrorResponse) + require.True(t, ok) + assert.Equal(t, "create-trace-id", apiErr.TraceID) + require.Equal(t, 1, len(apiErr.Errors)) + assert.Equal(t, "create-error-code", apiErr.Errors[0].Code) +} + +func TestAllowlistIdentifierDelete(t *testing.T) { + id := "alid_456" + clerk.SetBackend(clerk.NewBackend(&clerk.BackendConfig{ + HTTPClient: &http.Client{ + Transport: &mockRoundTripper{ + T: t, + out: json.RawMessage(fmt.Sprintf(`{"id":"%s","deleted":true}`, id)), + }, + }, + })) + + allowlistIdentifier, err := Delete(context.Background(), id) + require.NoError(t, err) + assert.Equal(t, id, allowlistIdentifier.ID) + assert.True(t, allowlistIdentifier.Deleted) +} + +func TestAllowlistIdentifierList(t *testing.T) { + clerk.SetBackend(clerk.NewBackend(&clerk.BackendConfig{ + HTTPClient: &http.Client{ + Transport: &mockRoundTripper{ + T: t, + out: json.RawMessage(`{ + "data": [{"id":"alid_123","identifier":"foo@bar.com"}], + "total_count": 1 +}`), + }, + }, + })) + + list, err := List(context.Background(), &ListParams{}) + require.NoError(t, err) + assert.Equal(t, int64(1), list.TotalCount) + assert.Equal(t, 1, len(list.AllowlistIdentifiers)) + assert.Equal(t, "alid_123", list.AllowlistIdentifiers[0].ID) + assert.Equal(t, "foo@bar.com", list.AllowlistIdentifiers[0].Identifier) +} + +type mockRoundTripper struct { + T *testing.T + status int + in json.RawMessage + out json.RawMessage +} + +func (rt *mockRoundTripper) RoundTrip(r *http.Request) (*http.Response, error) { + if rt.status == 0 { + rt.status = http.StatusOK + } + if rt.in != nil { + body, err := io.ReadAll(r.Body) + if err != nil { + return nil, err + } + defer r.Body.Close() + assert.JSONEq(rt.T, string(rt.in), string(body)) + } + return &http.Response{ + StatusCode: rt.status, + Body: io.NopCloser(bytes.NewReader(rt.out)), + }, nil +}