Skip to content

Commit

Permalink
Add organization membership deactivate and reactivate API methods (#334)
Browse files Browse the repository at this point in the history
Add organization membership deactivate and reactivate API methods.
  • Loading branch information
mattgd authored May 17, 2024
1 parent 37d04ca commit 956eeb3
Show file tree
Hide file tree
Showing 5 changed files with 351 additions and 1 deletion.
2 changes: 1 addition & 1 deletion pkg/events/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ func TestListEvents(t *testing.T) {
}

params := ListEventsOpts{
Events: []string{"dsync.user.created"},
Events: []string{"dsync.user.created"},
OrganizationId: "org_1234",
}

Expand Down
90 changes: 90 additions & 0 deletions pkg/usermanagement/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ type OrganizationMembershipStatus string
// Constants that enumerate the status of an Organization Membership.
const (
Active OrganizationMembershipStatus = "active"
Inactive OrganizationMembershipStatus = "inactive"
PendingOrganizationMembership OrganizationMembershipStatus = "pending"
)

Expand Down Expand Up @@ -394,6 +395,9 @@ type ListOrganizationMembershipsOpts struct {
// Filter memberships by User ID.
UserID string `url:"user_id,omitempty"`

// Filter memberships by status
Statuses []OrganizationMembershipStatus `url:"statuses,omitempty"`

// Maximum number of records to return.
Limit int `url:"limit"`

Expand Down Expand Up @@ -438,6 +442,16 @@ type DeleteOrganizationMembershipOpts struct {
OrganizationMembership string
}

type DeactivateOrganizationMembershipOpts struct {
// Organization Membership unique identifier
OrganizationMembership string
}

type ReactivateOrganizationMembershipOpts struct {
// Organization Membership unique identifier
OrganizationMembership string
}

type GetInvitationOpts struct {
Invitation string
}
Expand Down Expand Up @@ -1705,6 +1719,82 @@ func (c *Client) UpdateOrganizationMembership(
return body, err
}

// DeactivateOrganizationMembership deactivates an Organization Membership
func (c *Client) DeactivateOrganizationMembership(ctx context.Context, opts DeactivateOrganizationMembershipOpts) (OrganizationMembership, error) {
endpoint := fmt.Sprintf(
"%s/user_management/organization_memberships/%s/deactivate",
c.Endpoint,
opts.OrganizationMembership,
)

req, err := http.NewRequest(
http.MethodPut,
endpoint,
nil,
)
if err != nil {
return OrganizationMembership{}, err
}
req = req.WithContext(ctx)
req.Header.Set("User-Agent", "workos-go/"+workos.Version)
req.Header.Set("Authorization", "Bearer "+c.APIKey)
req.Header.Set("Content-Type", "application/json")

res, err := c.HTTPClient.Do(req)
if err != nil {
return OrganizationMembership{}, err
}
defer res.Body.Close()

if err = workos_errors.TryGetHTTPError(res); err != nil {
return OrganizationMembership{}, err
}

var body OrganizationMembership
dec := json.NewDecoder(res.Body)
err = dec.Decode(&body)

return body, err
}

// ReactivateOrganizationMembership reactivates an Organization Membership
func (c *Client) ReactivateOrganizationMembership(ctx context.Context, opts ReactivateOrganizationMembershipOpts) (OrganizationMembership, error) {
endpoint := fmt.Sprintf(
"%s/user_management/organization_memberships/%s/reactivate",
c.Endpoint,
opts.OrganizationMembership,
)

req, err := http.NewRequest(
http.MethodPut,
endpoint,
nil,
)
if err != nil {
return OrganizationMembership{}, err
}
req = req.WithContext(ctx)
req.Header.Set("User-Agent", "workos-go/"+workos.Version)
req.Header.Set("Authorization", "Bearer "+c.APIKey)
req.Header.Set("Content-Type", "application/json")

res, err := c.HTTPClient.Do(req)
if err != nil {
return OrganizationMembership{}, err
}
defer res.Body.Close()

if err = workos_errors.TryGetHTTPError(res); err != nil {
return OrganizationMembership{}, err
}

var body OrganizationMembership
dec := json.NewDecoder(res.Body)
err = dec.Decode(&body)

return body, err
}

// GetInvitation fetches an Invitation by its ID.
func (c *Client) GetInvitation(ctx context.Context, opts GetInvitationOpts) (Invitation, error) {
endpoint := fmt.Sprintf("%s/user_management/invitations/%s", c.Endpoint, opts.Invitation)
Expand Down
194 changes: 194 additions & 0 deletions pkg/usermanagement/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1962,6 +1962,40 @@ func TestListOrganizationMemberships(t *testing.T) {
require.NoError(t, err)
require.Equal(t, expectedResponse, organizationMemberships)
})

t.Run("ListOrganizationMemberships succeeds to fetch OrganizationMemberships belonging to a User with particular statuses", func(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(listOrganizationMembershipsTestHandler))
defer server.Close()
client := &Client{
HTTPClient: server.Client(),
Endpoint: server.URL,
APIKey: "test",
}

expectedResponse := ListOrganizationMembershipsResponse{
Data: []OrganizationMembership{
{
ID: "om_01E4ZCR3C56J083X43JQXF3JK5",
UserID: "user_01E4ZCR3C5A4QZ2Z2JQXGKZJ9E",
OrganizationID: "org_01E4ZCR3C56J083X43JQXF3JK5",
Status: Active,
CreatedAt: "2021-06-25T19:07:33.155Z",
UpdatedAt: "2021-06-25T19:07:33.155Z",
},
},
ListMetadata: common.ListMetadata{
After: "",
},
}

organizationMemberships, err := client.ListOrganizationMemberships(
context.Background(),
ListOrganizationMembershipsOpts{Statuses: []OrganizationMembershipStatus{Active, Inactive}, UserID: "user_01E4ZCR3C5A4QZ2Z2JQXGKZJ9E"},
)

require.NoError(t, err)
require.Equal(t, expectedResponse, organizationMemberships)
})
}

func listOrganizationMembershipsTestHandler(w http.ResponseWriter, r *http.Request) {
Expand Down Expand Up @@ -2250,6 +2284,166 @@ func deleteOrganizationMembershipTestHandler(w http.ResponseWriter, r *http.Requ
w.Write(body)
}

func TestDeactivateOrganizationMembership(t *testing.T) {
tests := []struct {
scenario string
client *Client
options DeactivateOrganizationMembershipOpts
expected OrganizationMembership
err bool
}{
{
scenario: "Request without API Key returns an error",
client: NewClient(""),
err: true,
},
{
scenario: "Request returns an Organization Membership",
client: NewClient("test"),
options: DeactivateOrganizationMembershipOpts{
OrganizationMembership: "om_01E4ZCR3C56J083X43JQXF3JK5",
},
expected: OrganizationMembership{
ID: "om_01E4ZCR3C56J083X43JQXF3JK5",
UserID: "user_01E4ZCR3C5A4QZ2Z2JQXGKZJ9E",
OrganizationID: "org_01E4ZCR3C56J083X43JQXF3JK5",
Status: Inactive,
CreatedAt: "2021-06-25T19:07:33.155Z",
UpdatedAt: "2021-06-25T19:07:33.155Z",
},
},
}

for _, test := range tests {
t.Run(test.scenario, func(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(deactivateOrganizationMembershipTestHandler))
defer server.Close()

client := test.client
client.Endpoint = server.URL
client.HTTPClient = server.Client()

organizationMembership, err := client.DeactivateOrganizationMembership(context.Background(), test.options)
if test.err {
require.Error(t, err)
return
}
require.NoError(t, err)
require.Equal(t, test.expected, organizationMembership)
})
}
}

func deactivateOrganizationMembershipTestHandler(w http.ResponseWriter, r *http.Request) {
auth := r.Header.Get("Authorization")
if auth != "Bearer test" {
http.Error(w, "bad auth", http.StatusUnauthorized)
return
}

var body []byte
var err error

if r.URL.Path == "/user_management/organization_memberships/om_01E4ZCR3C56J083X43JQXF3JK5/deactivate" {
body, err = json.Marshal(OrganizationMembership{
ID: "om_01E4ZCR3C56J083X43JQXF3JK5",
UserID: "user_01E4ZCR3C5A4QZ2Z2JQXGKZJ9E",
OrganizationID: "org_01E4ZCR3C56J083X43JQXF3JK5",
Status: Inactive,
CreatedAt: "2021-06-25T19:07:33.155Z",
UpdatedAt: "2021-06-25T19:07:33.155Z",
})
}

if err != nil {
w.WriteHeader(http.StatusInternalServerError)
return
}

w.WriteHeader(http.StatusOK)
w.Write(body)
}

func TestReactivateOrganizationMembership(t *testing.T) {
tests := []struct {
scenario string
client *Client
options ReactivateOrganizationMembershipOpts
expected OrganizationMembership
err bool
}{
{
scenario: "Request without API Key returns an error",
client: NewClient(""),
err: true,
},
{
scenario: "Request returns an Organization Membership",
client: NewClient("test"),
options: ReactivateOrganizationMembershipOpts{
OrganizationMembership: "om_01E4ZCR3C56J083X43JQXF3JK5",
},
expected: OrganizationMembership{
ID: "om_01E4ZCR3C56J083X43JQXF3JK5",
UserID: "user_01E4ZCR3C5A4QZ2Z2JQXGKZJ9E",
OrganizationID: "org_01E4ZCR3C56J083X43JQXF3JK5",
Status: Active,
CreatedAt: "2021-06-25T19:07:33.155Z",
UpdatedAt: "2021-06-25T19:07:33.155Z",
},
},
}

for _, test := range tests {
t.Run(test.scenario, func(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(reactivateOrganizationMembershipTestHandler))
defer server.Close()

client := test.client
client.Endpoint = server.URL
client.HTTPClient = server.Client()

organizationMembership, err := client.ReactivateOrganizationMembership(context.Background(), test.options)
if test.err {
require.Error(t, err)
return
}
require.NoError(t, err)
require.Equal(t, test.expected, organizationMembership)
})
}
}

func reactivateOrganizationMembershipTestHandler(w http.ResponseWriter, r *http.Request) {
auth := r.Header.Get("Authorization")
if auth != "Bearer test" {
http.Error(w, "bad auth", http.StatusUnauthorized)
return
}

var body []byte
var err error

if r.URL.Path == "/user_management/organization_memberships/om_01E4ZCR3C56J083X43JQXF3JK5/reactivate" {
body, err = json.Marshal(OrganizationMembership{
ID: "om_01E4ZCR3C56J083X43JQXF3JK5",
UserID: "user_01E4ZCR3C5A4QZ2Z2JQXGKZJ9E",
OrganizationID: "org_01E4ZCR3C56J083X43JQXF3JK5",
Status: Active,
CreatedAt: "2021-06-25T19:07:33.155Z",
UpdatedAt: "2021-06-25T19:07:33.155Z",
})
}

if err != nil {
w.WriteHeader(http.StatusInternalServerError)
return
}

w.WriteHeader(http.StatusOK)
w.Write(body)
}

func TestGetInvitation(t *testing.T) {
tests := []struct {
scenario string
Expand Down
16 changes: 16 additions & 0 deletions pkg/usermanagement/usermanagement.go
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,22 @@ func DeleteOrganizationMembership(
return DefaultClient.DeleteOrganizationMembership(ctx, opts)
}

// DeactivateOrganizationMembership deactivates an OrganizationMembership.
func DeactivateOrganizationMembership(
ctx context.Context,
opts DeactivateOrganizationMembershipOpts,
) (OrganizationMembership, error) {
return DefaultClient.DeactivateOrganizationMembership(ctx, opts)
}

// ReactivateOrganizationMembership reactivates an OrganizationMembership.
func ReactivateOrganizationMembership(
ctx context.Context,
opts ReactivateOrganizationMembershipOpts,
) (OrganizationMembership, error) {
return DefaultClient.ReactivateOrganizationMembership(ctx, opts)
}

func GetInvitation(
ctx context.Context,
opts GetInvitationOpts,
Expand Down
Loading

0 comments on commit 956eeb3

Please sign in to comment.