Repository: nukosuke/go-zendesk
Pull request #245 (2022-11-27 11:55:06)

Add methods for creating org memberships and setting default org (membership) for user
Hi, thanks for the library!  
   
In my use case I have to deal with [multiple orgs in Zendesk](https://support.zendesk.com/hc/en-us/articles/4408838140314-Enabling-multiple-organizations-for-users), so I am adding a few methods that I needed:
- `CreateOrganizationMembership`
  - https://developer.zendesk.com/api-reference/ticketing/organizations/organization_memberships/#create-membership
- `SetDefaultOrganization`
  - https://developer.zendesk.com/api-reference/ticketing/organizations/organization_memberships/#set-organization-as-default


Patch:
diff --git a/fixture/GET/organization_memberships.json b/fixture/GET/organization_memberships.json
new file mode 100644
index 0000000..7131ef5
--- /dev/null
+++ b/fixture/GET/organization_memberships.json
@@ -0,0 +1,24 @@
+{
+  "organization_memberships": [
+    {
+      "created_at": "2009-05-13T00:07:08Z",
+      "default": true,
+      "id": 4,
+      "organization_id": 361898904439,
+      "organization_name": "Rebel Alliance",
+      "updated_at": "2011-07-22T00:11:12Z",
+      "user_id": 369531345753,
+      "view_tickets": true
+    },
+    {
+      "created_at": "2012-03-13T22:01:32Z",
+      "default": null,
+      "id": 49,
+      "organization_id": 361898904439,
+      "organization_name": "Rebel Alliance",
+      "updated_at": "2012-03-13T22:01:32Z",
+      "user_id": 369537351454,
+      "view_tickets": true
+    }
+  ]
+}
diff --git a/fixture/POST/organization_membership.json b/fixture/POST/organization_membership.json
new file mode 100644
index 0000000..6a01150
--- /dev/null
+++ b/fixture/POST/organization_membership.json
@@ -0,0 +1,10 @@
+{
+  "organization_membership": {
+    "created_at": "2009-05-13T00:07:08Z",
+    "default": true,
+    "id": 4,
+    "organization_id": 361898904439,
+    "updated_at": "2011-07-22T00:11:12Z",
+    "user_id": 369531345753
+  }
+}
diff --git a/fixture/PUT/organization_membership.json b/fixture/PUT/organization_membership.json
new file mode 100644
index 0000000..6a01150
--- /dev/null
+++ b/fixture/PUT/organization_membership.json
@@ -0,0 +1,10 @@
+{
+  "organization_membership": {
+    "created_at": "2009-05-13T00:07:08Z",
+    "default": true,
+    "id": 4,
+    "organization_id": 361898904439,
+    "updated_at": "2011-07-22T00:11:12Z",
+    "user_id": 369531345753
+  }
+}
diff --git a/zendesk/mock/client.go b/zendesk/mock/client.go
index 571177b..fb16b06 100644
--- a/zendesk/mock/client.go
+++ b/zendesk/mock/client.go
@@ -185,6 +185,21 @@ func (mr *ClientMockRecorder) CreateOrganization(arg0, arg1 interface{}) *gomock
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateOrganization", reflect.TypeOf((*Client)(nil).CreateOrganization), arg0, arg1)
 }
 
+// CreateOrganizationMembership mocks base method.
+func (m *Client) CreateOrganizationMembership(arg0 context.Context, arg1 zendesk.OrganizationMembershipOptions) (zendesk.OrganizationMembership, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "CreateOrganizationMembership", arg0, arg1)
+	ret0, _ := ret[0].(zendesk.OrganizationMembership)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// CreateOrganizationMembership indicates an expected call of CreateOrganizationMembership.
+func (mr *ClientMockRecorder) CreateOrganizationMembership(arg0, arg1 interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateOrganizationMembership", reflect.TypeOf((*Client)(nil).CreateOrganizationMembership), arg0, arg1)
+}
+
 // CreateSLAPolicy mocks base method.
 func (m *Client) CreateSLAPolicy(arg0 context.Context, arg1 zendesk.SLAPolicy) (zendesk.SLAPolicy, error) {
 	m.ctrl.T.Helper()
@@ -1316,6 +1331,21 @@ func (mr *ClientMockRecorder) SearchUsers(arg0, arg1 interface{}) *gomock.Call {
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SearchUsers", reflect.TypeOf((*Client)(nil).SearchUsers), arg0, arg1)
 }
 
+// SetDefaultOrganization mocks base method.
+func (m *Client) SetDefaultOrganization(arg0 context.Context, arg1 zendesk.OrganizationMembershipOptions) (zendesk.OrganizationMembership, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "SetDefaultOrganization", arg0, arg1)
+	ret0, _ := ret[0].(zendesk.OrganizationMembership)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// SetDefaultOrganization indicates an expected call of SetDefaultOrganization.
+func (mr *ClientMockRecorder) SetDefaultOrganization(arg0, arg1 interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetDefaultOrganization", reflect.TypeOf((*Client)(nil).SetDefaultOrganization), arg0, arg1)
+}
+
 // UpdateAutomation mocks base method.
 func (m *Client) UpdateAutomation(arg0 context.Context, arg1 int64, arg2 zendesk.Automation) (zendesk.Automation, error) {
 	m.ctrl.T.Helper()
diff --git a/zendesk/organization_membership.go b/zendesk/organization_membership.go
index 4ac4b15..4f657cc 100644
--- a/zendesk/organization_membership.go
+++ b/zendesk/organization_membership.go
@@ -3,6 +3,7 @@ package zendesk
 import (
 	"context"
 	"encoding/json"
+	"fmt"
 	"time"
 )
 
@@ -28,9 +29,18 @@ type (
 		UserID         int64 `json:"user_id,omitempty" url:"user_id,omitempty"`
 	}
 
+	// OrganizationMembershipOptions is a struct for options for organization membership
+	// https://developer.zendesk.com/api-reference/ticketing/organizations/organization_memberships/
+	OrganizationMembershipOptions struct {
+		OrganizationID int64 `json:"organization_id,omitempty"`
+		UserID         int64 `json:"user_id,omitempty"`
+	}
+
 	// OrganizationMembershipAPI is an interface containing organization membership related methods
 	OrganizationMembershipAPI interface {
 		GetOrganizationMemberships(context.Context, *OrganizationMembershipListOptions) ([]OrganizationMembership, Page, error)
+		CreateOrganizationMembership(context.Context, OrganizationMembershipOptions) (OrganizationMembership, error)
+		SetDefaultOrganization(context.Context, OrganizationMembershipOptions) (OrganizationMembership, error)
 	}
 )
 
@@ -63,3 +73,48 @@ func (z *Client) GetOrganizationMemberships(ctx context.Context, opts *Organizat
 
 	return result.OrganizationMemberships, result.Page, nil
 }
+
+// CreateOrganizationMembership creates an organization membership for an existing user and org
+// https://developer.zendesk.com/api-reference/ticketing/organizations/organization_memberships/#create-membership
+func (z *Client) CreateOrganizationMembership(ctx context.Context, opts OrganizationMembershipOptions) (OrganizationMembership, error) {
+	var data, result struct {
+		OrganizationMembership OrganizationMembership `json:"organization_membership"`
+	}
+
+	data.OrganizationMembership = OrganizationMembership{
+		UserID:         opts.UserID,
+		OrganizationID: opts.OrganizationID,
+	}
+
+	body, err := z.post(ctx, "/organization_memberships.json", data)
+
+	if err != nil {
+		return OrganizationMembership{}, err
+	}
+
+	err = json.Unmarshal(body, &result)
+	if err != nil {
+		return OrganizationMembership{}, err
+	}
+
+	return result.OrganizationMembership, err
+}
+
+// SetDefaultOrganization sets the default organization for a user that has a membership in that org
+// https://developer.zendesk.com/api-reference/ticketing/organizations/organization_memberships/#set-organization-as-default
+func (z *Client) SetDefaultOrganization(ctx context.Context, opts OrganizationMembershipOptions) (OrganizationMembership, error) {
+	var result struct {
+		OrganizationMembership OrganizationMembership `json:"organization_membership"`
+	}
+
+	body, err := z.put(ctx, fmt.Sprintf("/users/%d/organizations/%d/make_default.json", opts.UserID, opts.OrganizationID), nil)
+	if err != nil {
+		return OrganizationMembership{}, err
+	}
+
+	if err := json.Unmarshal(body, &result); err != nil {
+		return OrganizationMembership{}, err
+	}
+
+	return result.OrganizationMembership, nil
+}


Test patch:
diff --git a/zendesk/organization_membership_test.go b/zendesk/organization_membership_test.go
new file mode 100644
index 0000000..b84d96f
--- /dev/null
+++ b/zendesk/organization_membership_test.go
@@ -0,0 +1,50 @@
+package zendesk
+
+import (
+	"net/http"
+	"testing"
+)
+
+func TestGetOrganizationMemberships(t *testing.T) {
+	mockAPI := newMockAPI(http.MethodGet, "organization_memberships.json")
+	client := newTestClient(mockAPI)
+	defer mockAPI.Close()
+
+	orgMemberships, _, err := client.GetOrganizationMemberships(ctx, &OrganizationMembershipListOptions{})
+	if err != nil {
+		t.Fatalf("Failed to get organization memberships: %s", err)
+	}
+
+	expectedOrgMemberships := 2
+
+	if len(orgMemberships) != expectedOrgMemberships {
+		t.Fatalf("expected length of organization memberships is %d, but got %d", expectedOrgMemberships, len(orgMemberships))
+	}
+}
+
+func TestCreateOrganizationMembership(t *testing.T) {
+	mockAPI := newMockAPIWithStatus(http.MethodPost, "organization_membership.json", http.StatusCreated)
+	client := newTestClient(mockAPI)
+	defer mockAPI.Close()
+
+	_, err := client.CreateOrganizationMembership(ctx, OrganizationMembershipOptions{})
+	if err != nil {
+		t.Fatalf("Failed to send request to create organization membership: %s", err)
+	}
+}
+
+func TestSetDefaultOrganization(t *testing.T) {
+	mockAPI := newMockAPIWithStatus(http.MethodPut, "organization_membership.json", http.StatusOK)
+	client := newTestClient(mockAPI)
+	defer mockAPI.Close()
+
+	orgMembership, err := client.SetDefaultOrganization(ctx, OrganizationMembershipOptions{})
+	if err != nil {
+		t.Fatalf("Failed to set the default organization for user: %s", err)
+	}
+
+	expectedDefault := true
+	if orgMembership.Default != expectedDefault {
+		t.Fatalf("Returned org membership does not have the expected default status %v. It is %v", expectedDefault, orgMembership.Default)
+	}
+}