From dd2fdfd0f04776b5316aacff043b5eaf70fcc835 Mon Sep 17 00:00:00 2001 From: Kump3r Date: Wed, 2 Oct 2024 15:40:33 +0300 Subject: [PATCH 1/6] Switching to CloudFoundry v3 API Signed-off-by: Kump3r --- connector/cloudfoundry/cloudfoundry.go | 8 ++++---- connector/cloudfoundry/cloudfoundry_test.go | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/connector/cloudfoundry/cloudfoundry.go b/connector/cloudfoundry/cloudfoundry.go index faa86bbab1..3e3592c02f 100644 --- a/connector/cloudfoundry/cloudfoundry.go +++ b/connector/cloudfoundry/cloudfoundry.go @@ -349,10 +349,10 @@ func (c *cloudfoundryConnector) HandleCallback(s connector.Scopes, r *http.Reque identity.EmailVerified, _ = userInfoResult["email_verified"].(bool) var ( - devPath = fmt.Sprintf("/v2/users/%s/spaces", identity.UserID) - auditorPath = fmt.Sprintf("/v2/users/%s/audited_spaces", identity.UserID) - managerPath = fmt.Sprintf("/v2/users/%s/managed_spaces", identity.UserID) - orgsPath = fmt.Sprintf("/v2/users/%s/organizations", identity.UserID) + devPath = fmt.Sprintf("/v3/users/%s/spaces", identity.UserID) + auditorPath = fmt.Sprintf("/v3/users/%s/audited_spaces", identity.UserID) + managerPath = fmt.Sprintf("/v3/users/%s/managed_spaces", identity.UserID) + orgsPath = fmt.Sprintf("/v3/users/%s/organizations", identity.UserID) ) if s.Groups { diff --git a/connector/cloudfoundry/cloudfoundry_test.go b/connector/cloudfoundry/cloudfoundry_test.go index 1e6af394de..fb53b9bc52 100644 --- a/connector/cloudfoundry/cloudfoundry_test.go +++ b/connector/cloudfoundry/cloudfoundry_test.go @@ -109,7 +109,7 @@ func testSpaceHandler(reqURL, spaceAPIEndpoint string) (result map[string]interf }, } } else { - nextURL := fmt.Sprintf("/v2/users/12345/%s?order-direction=asc&page=2&results-per-page=50", spaceAPIEndpoint) + nextURL := fmt.Sprintf("/v3/users/12345/%s?order-direction=asc&page=2&results-per-page=50", spaceAPIEndpoint) result = map[string]interface{}{ "next_url": nextURL, "resources": []map[string]interface{}{ @@ -139,7 +139,7 @@ func testOrgHandler(reqURL string) (result map[string]interface{}) { } } else { result = map[string]interface{}{ - "next_url": "/v2/users/12345/organizations?order-direction=asc&page=2&results-per-page=50", + "next_url": "/v3/users/12345/organizations?order-direction=asc&page=2&results-per-page=50", "resources": []map[string]interface{}{ { "metadata": map[string]string{"guid": "some-org-guid-1"}, @@ -165,7 +165,7 @@ func testSetup() *httptest.Server { }) }) - mux.HandleFunc("/v2/info", func(w http.ResponseWriter, r *http.Request) { + mux.HandleFunc("/v3/info", func(w http.ResponseWriter, r *http.Request) { url := fmt.Sprintf("http://%s", r.Host) json.NewEncoder(w).Encode(map[string]string{ @@ -194,7 +194,7 @@ func testSetup() *httptest.Server { }) }) - mux.HandleFunc("/v2/users/", func(w http.ResponseWriter, r *http.Request) { + mux.HandleFunc("/v3/users/", func(w http.ResponseWriter, r *http.Request) { var result map[string]interface{} reqURL := r.URL.String() From d307066ed0a249e2e99090b6930cdc449af0e8f4 Mon Sep 17 00:00:00 2001 From: Kump3r Date: Fri, 3 Jan 2025 11:25:51 +0200 Subject: [PATCH 2/6] Add missing endpoint Signed-off-by: Kump3r --- connector/cloudfoundry/cloudfoundry.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/connector/cloudfoundry/cloudfoundry.go b/connector/cloudfoundry/cloudfoundry.go index 3e3592c02f..942988387a 100644 --- a/connector/cloudfoundry/cloudfoundry.go +++ b/connector/cloudfoundry/cloudfoundry.go @@ -94,7 +94,7 @@ func (c *Config) Open(id string, logger log.Logger) (connector.Connector, error) } apiURL := strings.TrimRight(c.APIURL, "/") - apiResp, err := cloudfoundryConn.httpClient.Get(fmt.Sprintf("%s/v2/info", apiURL)) + apiResp, err := cloudfoundryConn.httpClient.Get(fmt.Sprintf("%s/v3/info", apiURL)) if err != nil { logger.Errorf("failed-to-send-request-to-cloud-controller-api", err) return nil, err From 5336dc961c33011e812bcac0e43dc5168d6f843b Mon Sep 17 00:00:00 2001 From: Kump3r Date: Tue, 7 Jan 2025 12:28:51 +0200 Subject: [PATCH 3/6] Refactor CloudFoundry API request handling to use updated response structure Signed-off-by: Kump3r --- connector/cloudfoundry/cloudfoundry.go | 13 ++++++++++--- connector/cloudfoundry/cloudfoundry_test.go | 10 +++++++--- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/connector/cloudfoundry/cloudfoundry.go b/connector/cloudfoundry/cloudfoundry.go index 942988387a..7bd539ac11 100644 --- a/connector/cloudfoundry/cloudfoundry.go +++ b/connector/cloudfoundry/cloudfoundry.go @@ -94,7 +94,7 @@ func (c *Config) Open(id string, logger log.Logger) (connector.Connector, error) } apiURL := strings.TrimRight(c.APIURL, "/") - apiResp, err := cloudfoundryConn.httpClient.Get(fmt.Sprintf("%s/v3/info", apiURL)) + apiResp, err := cloudfoundryConn.httpClient.Get(apiURL) if err != nil { logger.Errorf("failed-to-send-request-to-cloud-controller-api", err) return nil, err @@ -108,10 +108,17 @@ func (c *Config) Open(id string, logger log.Logger) (connector.Connector, error) return nil, err } - var apiResult map[string]interface{} + var apiResult struct { + Links struct { + Login struct { + Href string `json:"href"` + } `json:"login"` + } `json:"links"` + } + json.NewDecoder(apiResp.Body).Decode(&apiResult) - uaaURL := strings.TrimRight(apiResult["authorization_endpoint"].(string), "/") + uaaURL := strings.TrimRight(apiResult.Links.Login.Href, "/") uaaResp, err := cloudfoundryConn.httpClient.Get(fmt.Sprintf("%s/.well-known/openid-configuration", uaaURL)) if err != nil { logger.Errorf("failed-to-send-request-to-uaa-api", err) diff --git a/connector/cloudfoundry/cloudfoundry_test.go b/connector/cloudfoundry/cloudfoundry_test.go index fb53b9bc52..85e87d609e 100644 --- a/connector/cloudfoundry/cloudfoundry_test.go +++ b/connector/cloudfoundry/cloudfoundry_test.go @@ -165,11 +165,15 @@ func testSetup() *httptest.Server { }) }) - mux.HandleFunc("/v3/info", func(w http.ResponseWriter, r *http.Request) { + mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { url := fmt.Sprintf("http://%s", r.Host) - json.NewEncoder(w).Encode(map[string]string{ - "authorization_endpoint": url, + json.NewEncoder(w).Encode(map[string]interface{}{ + "links": map[string]interface{}{ + "login": map[string]string{ + "href": url, + }, + }, }) }) From 9b2fe7b09310045b4509c47179ac2738a23519db Mon Sep 17 00:00:00 2001 From: Kump3r Date: Thu, 9 Jan 2025 15:35:04 +0200 Subject: [PATCH 4/6] Use simple structures for the apiResult Signed-off-by: Kump3r --- connector/cloudfoundry/cloudfoundry.go | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/connector/cloudfoundry/cloudfoundry.go b/connector/cloudfoundry/cloudfoundry.go index 7bd539ac11..f60c51518a 100644 --- a/connector/cloudfoundry/cloudfoundry.go +++ b/connector/cloudfoundry/cloudfoundry.go @@ -77,6 +77,18 @@ type org struct { GUID string } +type infoResp struct { + Links links `json:"links"` +} + +type links struct { + Login login `json:"login"` +} + +type login struct { + Href string `json:"href"` +} + func (c *Config) Open(id string, logger log.Logger) (connector.Connector, error) { var err error @@ -108,13 +120,7 @@ func (c *Config) Open(id string, logger log.Logger) (connector.Connector, error) return nil, err } - var apiResult struct { - Links struct { - Login struct { - Href string `json:"href"` - } `json:"login"` - } `json:"links"` - } + var apiResult infoResp json.NewDecoder(apiResp.Body).Decode(&apiResult) From 50012b25874b49e20becfa030d9e74d4088ed545 Mon Sep 17 00:00:00 2001 From: IvanChalukov Date: Thu, 9 Jan 2025 16:58:54 +0200 Subject: [PATCH 5/6] Switching to CF API V3 endpoints Signed-off-by: IvanChalukov --- connector/cloudfoundry/cloudfoundry.go | 119 ++++++++++++++----------- 1 file changed, 65 insertions(+), 54 deletions(-) diff --git a/connector/cloudfoundry/cloudfoundry.go b/connector/cloudfoundry/cloudfoundry.go index f60c51518a..69a1e20fd5 100644 --- a/connector/cloudfoundry/cloudfoundry.go +++ b/connector/cloudfoundry/cloudfoundry.go @@ -46,25 +46,43 @@ type Config struct { } type ccResponse struct { - NextURL string `json:"next_url"` - Resources []resource `json:"resources"` - TotalResults int `json:"total_results"` + Pagination pagination `json:"pagination"` + Resources []resource `json:"resources"` } -type resource struct { - Metadata metadata `json:"metadata"` - Entity entity `json:"entity"` +type pagination struct { + Next href `json:"next"` +} + +type href struct { + Href string `json:"href"` } -type metadata struct { +type resource struct { GUID string `json:"guid"` + Name string `json:"name,omitempty"` + Type string `json:"type,omitempty"` + Relationships relationships `json:"relationships"` } -type entity struct { - Name string `json:"name"` - OrganizationGUID string `json:"organization_guid"` +type relationships struct { + Organization relOrganization `json:"organization"` + Space relSpace `json:"space"` } +type relOrganization struct { + Data data `json:"data"` +} + +type relSpace struct { + Data data `json:"data"` +} + +type data struct { + GUID string `json:"guid"` +} + + type space struct { Name string GUID string @@ -204,40 +222,39 @@ func (c *cloudfoundryConnector) LoginURL(scopes connector.Scopes, callbackURL, s return oauth2Config.AuthCodeURL(state), nil } -func fetchRoleSpaces(baseURL, path, role string, client *http.Client) ([]space, error) { - resources, err := fetchResources(baseURL, path, client) - if err != nil { - return nil, fmt.Errorf("failed to fetch resources: %v", err) - } +func filterUserOrgsSpaces(userOrgsSpaces []resource, orgs []resource, spaces []resource) ([]org, []space) { + var filteredOrgs []org + var filteredSpaces []space + + orgMap := make(map[string]org) + spaceMap := make(map[string]space) - spaces := make([]space, len(resources)) - for i, resource := range resources { - spaces[i] = space{ - Name: resource.Entity.Name, - GUID: resource.Metadata.GUID, - OrgGUID: resource.Entity.OrganizationGUID, - Role: role, + for _, org_resource := range orgs { + orgMap[org_resource.GUID] = org{ + Name: org_resource.Name, + GUID: org_resource.GUID, } } - return spaces, nil -} - -func fetchOrgs(baseURL, path string, client *http.Client) ([]org, error) { - resources, err := fetchResources(baseURL, path, client) - if err != nil { - return nil, fmt.Errorf("failed to fetch resources: %v", err) + for _, space_resource := range spaces { + spaceMap[space_resource.GUID] = space{ + Name: space_resource.Name, + GUID: space_resource.GUID, + OrgGUID: space_resource.Relationships.Organization.Data.GUID, + } } - orgs := make([]org, len(resources)) - for i, resource := range resources { - orgs[i] = org{ - Name: resource.Entity.Name, - GUID: resource.Metadata.GUID, + for _, userOrgSpace := range userOrgsSpaces { + if space, ok := spaceMap[userOrgSpace.Relationships.Space.Data.GUID]; ok { + space.Role = strings.TrimPrefix(userOrgSpace.Type, "space_") + filteredSpaces = append(filteredSpaces, space) + } + if org, ok := orgMap[userOrgSpace.Relationships.Organization.Data.GUID]; ok { + filteredOrgs = append(filteredOrgs, org) } } - return orgs, nil + return filteredOrgs, filteredSpaces } func fetchResources(baseURL, path string, client *http.Client) ([]resource, error) { @@ -262,12 +279,12 @@ func fetchResources(baseURL, path string, client *http.Client) ([]resource, erro response := ccResponse{} err = json.NewDecoder(resp.Body).Decode(&response) if err != nil { - return nil, fmt.Errorf("failed to parse spaces: %v", err) + return nil, fmt.Errorf("failed to parse response: %v", err) } resources = append(resources, response.Resources...) - path = response.NextURL + path = strings.TrimPrefix(response.Pagination.Next.Href, baseURL) if path == "" { break } @@ -362,36 +379,30 @@ func (c *cloudfoundryConnector) HandleCallback(s connector.Scopes, r *http.Reque identity.EmailVerified, _ = userInfoResult["email_verified"].(bool) var ( - devPath = fmt.Sprintf("/v3/users/%s/spaces", identity.UserID) - auditorPath = fmt.Sprintf("/v3/users/%s/audited_spaces", identity.UserID) - managerPath = fmt.Sprintf("/v3/users/%s/managed_spaces", identity.UserID) - orgsPath = fmt.Sprintf("/v3/users/%s/organizations", identity.UserID) + orgsPath = fmt.Sprintf("/v3/organizations") + spacesPath = fmt.Sprintf("/v3/spaces") + userOrgsSpacesPath = fmt.Sprintf("/v3/roles?user_guids=%s&types=space_developer,space_manager,space_auditor,organization_user", identity.UserID) ) if s.Groups { - orgs, err := fetchOrgs(c.apiURL, orgsPath, client) - if err != nil { - return identity, fmt.Errorf("failed to fetch organizaitons: %v", err) - } - - developerSpaces, err := fetchRoleSpaces(c.apiURL, devPath, "developer", client) + userOrgsSpaces, err := fetchResources(c.apiURL, userOrgsSpacesPath, client) if err != nil { - return identity, fmt.Errorf("failed to fetch spaces for developer roles: %v", err) + return identity, fmt.Errorf("failed to fetch user organizations: %v", err) } - auditorSpaces, err := fetchRoleSpaces(c.apiURL, auditorPath, "auditor", client) + orgs, err := fetchResources(c.apiURL, orgsPath, client) if err != nil { - return identity, fmt.Errorf("failed to fetch spaces for developer roles: %v", err) + return identity, fmt.Errorf("failed to fetch organizaitons: %v", err) } - managerSpaces, err := fetchRoleSpaces(c.apiURL, managerPath, "manager", client) + spaces, err := fetchResources(c.apiURL, spacesPath, client) if err != nil { - return identity, fmt.Errorf("failed to fetch spaces for developer roles: %v", err) + return identity, fmt.Errorf("failed to fetch spaces: %v", err) } - developerSpaces = append(developerSpaces, append(auditorSpaces, managerSpaces...)...) + developerOrgs, developerSpaces := filterUserOrgsSpaces(userOrgsSpaces, orgs, spaces) - identity.Groups = getGroupsClaims(orgs, developerSpaces) + identity.Groups = getGroupsClaims(developerOrgs, developerSpaces) } if s.OfflineAccess { From 4efbde349cc227566fa96c19600c023f5dc0e648 Mon Sep 17 00:00:00 2001 From: Kump3r Date: Fri, 10 Jan 2025 16:20:58 +0200 Subject: [PATCH 6/6] Addapt cloudfoundry_test.go acceptance tests for CF API v3 Signed-off-by: Kump3r --- connector/cloudfoundry/cloudfoundry.go | 19 +- connector/cloudfoundry/cloudfoundry_test.go | 351 +++++++++++++++++--- 2 files changed, 322 insertions(+), 48 deletions(-) diff --git a/connector/cloudfoundry/cloudfoundry.go b/connector/cloudfoundry/cloudfoundry.go index 69a1e20fd5..813472252d 100644 --- a/connector/cloudfoundry/cloudfoundry.go +++ b/connector/cloudfoundry/cloudfoundry.go @@ -47,27 +47,27 @@ type Config struct { type ccResponse struct { Pagination pagination `json:"pagination"` - Resources []resource `json:"resources"` + Resources []resource `json:"resources"` } type pagination struct { - Next href `json:"next"` + Next href `json:"next"` } type href struct { - Href string `json:"href"` + Href string `json:"href"` } type resource struct { - GUID string `json:"guid"` - Name string `json:"name,omitempty"` - Type string `json:"type,omitempty"` + GUID string `json:"guid"` + Name string `json:"name,omitempty"` + Type string `json:"type,omitempty"` Relationships relationships `json:"relationships"` } type relationships struct { Organization relOrganization `json:"organization"` - Space relSpace `json:"space"` + Space relSpace `json:"space"` } type relOrganization struct { @@ -82,7 +82,6 @@ type data struct { GUID string `json:"guid"` } - type space struct { Name string GUID string @@ -379,8 +378,8 @@ func (c *cloudfoundryConnector) HandleCallback(s connector.Scopes, r *http.Reque identity.EmailVerified, _ = userInfoResult["email_verified"].(bool) var ( - orgsPath = fmt.Sprintf("/v3/organizations") - spacesPath = fmt.Sprintf("/v3/spaces") + orgsPath = "/v3/organizations" + spacesPath = "/v3/spaces" userOrgsSpacesPath = fmt.Sprintf("/v3/roles?user_guids=%s&types=space_developer,space_manager,space_auditor,organization_user", identity.UserID) ) diff --git a/connector/cloudfoundry/cloudfoundry_test.go b/connector/cloudfoundry/cloudfoundry_test.go index 85e87d609e..ceb1aa519e 100644 --- a/connector/cloudfoundry/cloudfoundry_test.go +++ b/connector/cloudfoundry/cloudfoundry_test.go @@ -97,25 +97,51 @@ func TestHandleCallback(t *testing.T) { }) } -func testSpaceHandler(reqURL, spaceAPIEndpoint string) (result map[string]interface{}) { - fullURL := fmt.Sprintf("%s?order-direction=asc&page=2&results-per-page=50", spaceAPIEndpoint) - if strings.Contains(reqURL, fullURL) { +func testSpaceHandler(reqURL string) (result map[string]interface{}) { + if strings.Contains(reqURL, "spaces?page=2&per_page=50") { result = map[string]interface{}{ + "pagination": map[string]interface{}{ + "next": map[string]interface{}{ + "href": nil, + }, + }, "resources": []map[string]interface{}{ { - "metadata": map[string]string{"guid": "some-space-guid-2"}, - "entity": map[string]string{"name": "some-space-name-2", "organization_guid": "some-org-guid-2"}, + "guid": "some-space-guid-2", + "name": "some-space-name-2", + "relationships": map[string]interface{}{ + "user": nil, + "organization": map[string]interface{}{ + "data": map[string]interface{}{ + "guid": "some-org-guid-2", + }, + }, + "space": nil, + }, }, }, } } else { - nextURL := fmt.Sprintf("/v3/users/12345/%s?order-direction=asc&page=2&results-per-page=50", spaceAPIEndpoint) + nextURL := fmt.Sprintf("%s?page=2&per_page=50", reqURL) result = map[string]interface{}{ - "next_url": nextURL, + "pagination": map[string]interface{}{ + "next": map[string]interface{}{ + "href": nextURL, + }, + }, "resources": []map[string]interface{}{ { - "metadata": map[string]string{"guid": "some-space-guid-1"}, - "entity": map[string]string{"name": "some-space-name-1", "organization_guid": "some-org-guid-1"}, + "guid": "some-space-guid-1", + "name": "some-space-name-1", + "relationships": map[string]interface{}{ + "user": nil, + "organization": map[string]interface{}{ + "data": map[string]interface{}{ + "guid": "some-org-guid-1", + }, + }, + "space": nil, + }, }, }, } @@ -124,30 +150,290 @@ func testSpaceHandler(reqURL, spaceAPIEndpoint string) (result map[string]interf } func testOrgHandler(reqURL string) (result map[string]interface{}) { - if strings.Contains(reqURL, "organizations?order-direction=asc&page=2&results-per-page=50") { + if strings.Contains(reqURL, "organizations?page=2&per_page=50") { + result = map[string]interface{}{ + "pagination": map[string]interface{}{ + "next": map[string]interface{}{ + "href": nil, + }, + }, + "resources": []map[string]interface{}{ + { + "guid": "some-org-guid-3", + "name": "some-org-name-3", + "relationships": map[string]interface{}{ + "user": nil, + "organization": nil, + "space": nil, + }, + }, + { + "guid": "some-org-guid-4", + "name": "some-org-name-4", + "relationships": map[string]interface{}{ + "user": nil, + "organization": nil, + "space": nil, + }, + }, + }, + } + } else { + nextURL := fmt.Sprintf("%s?page=2&per_page=50", reqURL) + result = map[string]interface{}{ + "pagination": map[string]interface{}{ + "next": map[string]interface{}{ + "href": nextURL, + }, + }, + "resources": []map[string]interface{}{ + { + "guid": "some-org-guid-1", + "name": "some-org-name-1", + "relationships": map[string]interface{}{ + "user": nil, + "organization": nil, + "space": map[string]interface{}{ + "data": map[string]interface{}{ + "guid": "some-space-guid-1", + }, + }, + }, + }, + { + "guid": "some-org-guid-2", + "name": "some-org-name-2", + "relationships": map[string]interface{}{ + "user": nil, + "organization": nil, + "space": map[string]interface{}{ + "data": map[string]interface{}{ + "guid": "some-space-guid-2", + }, + }, + }, + }, + }, + } + } + return result +} + +func testUserOrgsSpacesHandler(reqURL string) (result map[string]interface{}) { + if strings.Contains(reqURL, "page=2&per_page=50") { result = map[string]interface{}{ + "pagination": map[string]interface{}{ + "next": map[string]interface{}{ + "href": nil, + }, + }, "resources": []map[string]interface{}{ { - "metadata": map[string]string{"guid": "some-org-guid-3"}, - "entity": map[string]string{"name": "some-org-name-3"}, + "guid": "some-type-guid-3", + "type": "organization_user", + "relationships": map[string]interface{}{ + "user": nil, + "organization": map[string]interface{}{ + "data": map[string]interface{}{ + "guid": "some-org-guid-3", + }, + }, + "space": nil, + }, + }, + { + "guid": "some-type-guid-4", + "type": "organization_user", + "relationships": map[string]interface{}{ + "user": nil, + "organization": map[string]interface{}{ + "data": map[string]interface{}{ + "guid": "some-org-guid-4", + }, + }, + "space": nil, + }, + }, + { + "guid": "some-type-guid-1", + "type": "space_manager", + "relationships": map[string]interface{}{ + "user": nil, + "organization": map[string]interface{}{ + "data": map[string]interface{}{ + "guid": "some-org-guid-1", + }, + }, + "space": map[string]interface{}{ + "data": map[string]interface{}{ + "guid": "some-space-guid-1", + }, + }, + }, + }, + { + "guid": "some-type-guid-2", + "type": "space_developer", + "relationships": map[string]interface{}{ + "user": nil, + "organization": map[string]interface{}{ + "data": map[string]interface{}{ + "guid": "some-org-guid-2", + }, + }, + "space": map[string]interface{}{ + "data": map[string]interface{}{ + "guid": "some-space-guid-2", + }, + }, + }, }, { - "metadata": map[string]string{"guid": "some-org-guid-4"}, - "entity": map[string]string{"name": "some-org-name-4"}, + "guid": "some-type-guid-2", + "type": "space_auditor", + "relationships": map[string]interface{}{ + "user": nil, + "organization": map[string]interface{}{ + "data": map[string]interface{}{ + "guid": "some-org-guid-2", + }, + }, + "space": map[string]interface{}{ + "data": map[string]interface{}{ + "guid": "some-space-guid-2", + }, + }, + }, + }, + { + "guid": "some-type-guid-2", + "type": "space_manager", + "relationships": map[string]interface{}{ + "user": nil, + "organization": map[string]interface{}{ + "data": map[string]interface{}{ + "guid": "some-org-guid-2", + }, + }, + "space": map[string]interface{}{ + "data": map[string]interface{}{ + "guid": "some-space-guid-2", + }, + }, + }, }, }, } } else { + nextURL := fmt.Sprintf("%s?page=2&per_page=50", reqURL) result = map[string]interface{}{ - "next_url": "/v3/users/12345/organizations?order-direction=asc&page=2&results-per-page=50", + "pagination": map[string]interface{}{ + "next": map[string]interface{}{ + "href": nextURL, + }, + }, "resources": []map[string]interface{}{ { - "metadata": map[string]string{"guid": "some-org-guid-1"}, - "entity": map[string]string{"name": "some-org-name-1"}, + "guid": "some-type-guid-1", + "type": "space_developer", + "relationships": map[string]interface{}{ + "user": nil, + "organization": map[string]interface{}{ + "data": map[string]interface{}{ + "guid": "some-org-guid-1", + }, + }, + "space": map[string]interface{}{ + "data": map[string]interface{}{ + "guid": "some-space-guid-1", + }, + }, + }, }, { - "metadata": map[string]string{"guid": "some-org-guid-2"}, - "entity": map[string]string{"name": "some-org-name-2"}, + "guid": "some-type-guid-1", + "type": "space_auditor", + "relationships": map[string]interface{}{ + "user": nil, + "organization": map[string]interface{}{ + "data": map[string]interface{}{ + "guid": "some-org-guid-1", + }, + }, + "space": map[string]interface{}{ + "data": map[string]interface{}{ + "guid": "some-space-guid-1", + }, + }, + }, + }, + { + "guid": "some-type-guid-1", + "type": "space_manager", + "relationships": map[string]interface{}{ + "user": nil, + "organization": map[string]interface{}{ + "data": map[string]interface{}{ + "guid": "some-org-guid-1", + }, + }, + "space": map[string]interface{}{ + "data": map[string]interface{}{ + "guid": "some-space-guid-1", + }, + }, + }, + }, + { + "guid": "some-type-guid-2", + "type": "space_developer", + "relationships": map[string]interface{}{ + "user": nil, + "organization": map[string]interface{}{ + "data": map[string]interface{}{ + "guid": "some-org-guid-2", + }, + }, + "space": map[string]interface{}{ + "data": map[string]interface{}{ + "guid": "some-space-guid-2", + }, + }, + }, + }, + { + "guid": "some-type-guid-2", + "type": "space_auditor", + "relationships": map[string]interface{}{ + "user": nil, + "organization": map[string]interface{}{ + "data": map[string]interface{}{ + "guid": "some-org-guid-2", + }, + }, + "space": map[string]interface{}{ + "data": map[string]interface{}{ + "guid": "some-space-guid-2", + }, + }, + }, + }, + { + "guid": "some-type-guid-2", + "type": "space_manager", + "relationships": map[string]interface{}{ + "user": nil, + "organization": map[string]interface{}{ + "data": map[string]interface{}{ + "guid": "some-org-guid-2", + }, + }, + "space": map[string]interface{}{ + "data": map[string]interface{}{ + "guid": "some-space-guid-2", + }, + }, + }, }, }, } @@ -198,27 +484,16 @@ func testSetup() *httptest.Server { }) }) - mux.HandleFunc("/v3/users/", func(w http.ResponseWriter, r *http.Request) { - var result map[string]interface{} - - reqURL := r.URL.String() - if strings.Contains(reqURL, "/spaces") { - result = testSpaceHandler(reqURL, "spaces") - } - - if strings.Contains(reqURL, "/audited_spaces") { - result = testSpaceHandler(reqURL, "audited_spaces") - } - - if strings.Contains(reqURL, "/managed_spaces") { - result = testSpaceHandler(reqURL, "managed_spaces") - } + mux.HandleFunc("/v3/organizations", func(w http.ResponseWriter, r *http.Request) { + json.NewEncoder(w).Encode(testOrgHandler(r.URL.String())) + }) - if strings.Contains(reqURL, "organizations") { - result = testOrgHandler(reqURL) - } + mux.HandleFunc("/v3/spaces", func(w http.ResponseWriter, r *http.Request) { + json.NewEncoder(w).Encode(testSpaceHandler(r.URL.String())) + }) - json.NewEncoder(w).Encode(result) + mux.HandleFunc("/v3/roles", func(w http.ResponseWriter, r *http.Request) { + json.NewEncoder(w).Encode(testUserOrgsSpacesHandler(r.URL.String())) }) return httptest.NewServer(mux)