1package cfclient
2
3import (
4	"bytes"
5	"encoding/json"
6	"fmt"
7	"io/ioutil"
8	"net/http"
9	"net/url"
10
11	"github.com/pkg/errors"
12)
13
14type OrgResponse struct {
15	Count     int           `json:"total_results"`
16	Pages     int           `json:"total_pages"`
17	NextUrl   string        `json:"next_url"`
18	Resources []OrgResource `json:"resources"`
19}
20
21type OrgResource struct {
22	Meta   Meta `json:"metadata"`
23	Entity Org  `json:"entity"`
24}
25
26type OrgUserResponse struct {
27	Count     int            `json:"total_results"`
28	Pages     int            `json:"total_pages"`
29	NextURL   string         `json:"next_url"`
30	Resources []UserResource `json:"resources"`
31}
32
33type Org struct {
34	Guid                        string `json:"guid"`
35	CreatedAt                   string `json:"created_at"`
36	UpdatedAt                   string `json:"updated_at"`
37	Name                        string `json:"name"`
38	Status                      string `json:"status"`
39	QuotaDefinitionGuid         string `json:"quota_definition_guid"`
40	DefaultIsolationSegmentGuid string `json:"default_isolation_segment_guid"`
41	c                           *Client
42}
43
44type OrgSummary struct {
45	Guid   string             `json:"guid"`
46	Name   string             `json:"name"`
47	Status string             `json:"status"`
48	Spaces []OrgSummarySpaces `json:"spaces"`
49}
50
51type OrgSummarySpaces struct {
52	Guid         string `json:"guid"`
53	Name         string `json:"name"`
54	ServiceCount int    `json:"service_count"`
55	AppCount     int    `json:"app_count"`
56	MemDevTotal  int    `json:"mem_dev_total"`
57	MemProdTotal int    `json:"mem_prod_total"`
58}
59
60type OrgRequest struct {
61	Name                        string `json:"name"`
62	Status                      string `json:"status,omitempty"`
63	QuotaDefinitionGuid         string `json:"quota_definition_guid,omitempty"`
64	DefaultIsolationSegmentGuid string `json:"default_isolation_segment_guid,omitempty"`
65}
66
67func (c *Client) ListOrgsByQuery(query url.Values) ([]Org, error) {
68	var orgs []Org
69	requestURL := "/v2/organizations?" + query.Encode()
70	for {
71		orgResp, err := c.getOrgResponse(requestURL)
72		if err != nil {
73			return []Org{}, err
74		}
75		for _, org := range orgResp.Resources {
76			orgs = append(orgs, c.mergeOrgResource(org))
77		}
78		requestURL = orgResp.NextUrl
79		if requestURL == "" {
80			break
81		}
82	}
83	return orgs, nil
84}
85
86func (c *Client) ListOrgs() ([]Org, error) {
87	return c.ListOrgsByQuery(nil)
88}
89
90func (c *Client) GetOrgByName(name string) (Org, error) {
91	var org Org
92	q := url.Values{}
93	q.Set("q", "name:"+name)
94	orgs, err := c.ListOrgsByQuery(q)
95	if err != nil {
96		return org, err
97	}
98	if len(orgs) == 0 {
99		return org, fmt.Errorf("Unable to find org %s", name)
100	}
101	return orgs[0], nil
102}
103
104func (c *Client) GetOrgByGuid(guid string) (Org, error) {
105	var orgRes OrgResource
106	r := c.NewRequest("GET", "/v2/organizations/"+guid)
107	resp, err := c.DoRequest(r)
108	if err != nil {
109		return Org{}, err
110	}
111	body, err := ioutil.ReadAll(resp.Body)
112	defer resp.Body.Close()
113	if err != nil {
114		return Org{}, err
115	}
116	err = json.Unmarshal(body, &orgRes)
117	if err != nil {
118		return Org{}, err
119	}
120	return c.mergeOrgResource(orgRes), nil
121}
122
123func (c *Client) OrgSpaces(guid string) ([]Space, error) {
124	return c.fetchSpaces(fmt.Sprintf("/v2/organizations/%s/spaces", guid))
125}
126
127func (o *Org) Summary() (OrgSummary, error) {
128	var orgSummary OrgSummary
129	requestURL := fmt.Sprintf("/v2/organizations/%s/summary", o.Guid)
130	r := o.c.NewRequest("GET", requestURL)
131	resp, err := o.c.DoRequest(r)
132	if err != nil {
133		return OrgSummary{}, errors.Wrap(err, "Error requesting org summary")
134	}
135	resBody, err := ioutil.ReadAll(resp.Body)
136	defer resp.Body.Close()
137	if err != nil {
138		return OrgSummary{}, errors.Wrap(err, "Error reading org summary body")
139	}
140	err = json.Unmarshal(resBody, &orgSummary)
141	if err != nil {
142		return OrgSummary{}, errors.Wrap(err, "Error unmarshalling org summary")
143	}
144	return orgSummary, nil
145}
146
147func (o *Org) Quota() (*OrgQuota, error) {
148	var orgQuota *OrgQuota
149	var orgQuotaResource OrgQuotasResource
150	if o.QuotaDefinitionGuid == "" {
151		return nil, nil
152	}
153	requestURL := fmt.Sprintf("/v2/quota_definitions/%s", o.QuotaDefinitionGuid)
154	r := o.c.NewRequest("GET", requestURL)
155	resp, err := o.c.DoRequest(r)
156	if err != nil {
157		return &OrgQuota{}, errors.Wrap(err, "Error requesting org quota")
158	}
159	resBody, err := ioutil.ReadAll(resp.Body)
160	defer resp.Body.Close()
161	if err != nil {
162		return &OrgQuota{}, errors.Wrap(err, "Error reading org quota body")
163	}
164	err = json.Unmarshal(resBody, &orgQuotaResource)
165	if err != nil {
166		return &OrgQuota{}, errors.Wrap(err, "Error unmarshalling org quota")
167	}
168	orgQuota = &orgQuotaResource.Entity
169	orgQuota.Guid = orgQuotaResource.Meta.Guid
170	orgQuota.c = o.c
171	return orgQuota, nil
172}
173
174func (c *Client) ListOrgUsersByQuery(orgGUID string, query url.Values) ([]User, error) {
175	var users []User
176	requestURL := fmt.Sprintf("/v2/organizations/%s/users?%s", orgGUID, query.Encode())
177	for {
178		omResp, err := c.getOrgUserResponse(requestURL)
179		if err != nil {
180			return []User{}, err
181		}
182		for _, u := range omResp.Resources {
183			users = append(users, c.mergeUserResource(u))
184		}
185		requestURL = omResp.NextURL
186		if requestURL == "" {
187			break
188		}
189	}
190	return users, nil
191}
192
193func (c *Client) ListOrgUsers(orgGUID string) ([]User, error) {
194	return c.ListOrgUsersByQuery(orgGUID, nil)
195}
196
197func (c *Client) listOrgRolesByQuery(orgGUID, role string, query url.Values) ([]User, error) {
198	var users []User
199	requestURL := fmt.Sprintf("/v2/organizations/%s/%s?%s", orgGUID, role, query.Encode())
200	for {
201		omResp, err := c.getOrgUserResponse(requestURL)
202		if err != nil {
203			return []User{}, err
204		}
205		for _, u := range omResp.Resources {
206			users = append(users, c.mergeUserResource(u))
207		}
208		requestURL = omResp.NextURL
209		if requestURL == "" {
210			break
211		}
212	}
213	return users, nil
214}
215
216func (c *Client) ListOrgManagersByQuery(orgGUID string, query url.Values) ([]User, error) {
217	return c.listOrgRolesByQuery(orgGUID, "managers", query)
218}
219
220func (c *Client) ListOrgManagers(orgGUID string) ([]User, error) {
221	return c.ListOrgManagersByQuery(orgGUID, nil)
222}
223
224func (c *Client) ListOrgAuditorsByQuery(orgGUID string, query url.Values) ([]User, error) {
225	return c.listOrgRolesByQuery(orgGUID, "auditors", query)
226}
227
228func (c *Client) ListOrgAuditors(orgGUID string) ([]User, error) {
229	return c.ListOrgAuditorsByQuery(orgGUID, nil)
230}
231
232func (c *Client) ListOrgBillingManagersByQuery(orgGUID string, query url.Values) ([]User, error) {
233	return c.listOrgRolesByQuery(orgGUID, "billing_managers", query)
234}
235
236func (c *Client) ListOrgBillingManagers(orgGUID string) ([]User, error) {
237	return c.ListOrgBillingManagersByQuery(orgGUID, nil)
238}
239
240func (c *Client) AssociateOrgManager(orgGUID, userGUID string) (Org, error) {
241	org := Org{Guid: orgGUID, c: c}
242	return org.AssociateManager(userGUID)
243}
244
245func (c *Client) AssociateOrgManagerByUsername(orgGUID, name string) (Org, error) {
246	org := Org{Guid: orgGUID, c: c}
247	return org.AssociateManagerByUsername(name)
248}
249
250func (c *Client) AssociateOrgManagerByUsernameAndOrigin(orgGUID, name, origin string) (Org, error) {
251	org := Org{Guid: orgGUID, c: c}
252	return org.AssociateManagerByUsernameAndOrigin(name, origin)
253}
254
255func (c *Client) AssociateOrgUser(orgGUID, userGUID string) (Org, error) {
256	org := Org{Guid: orgGUID, c: c}
257	return org.AssociateUser(userGUID)
258}
259
260func (c *Client) AssociateOrgAuditor(orgGUID, userGUID string) (Org, error) {
261	org := Org{Guid: orgGUID, c: c}
262	return org.AssociateAuditor(userGUID)
263}
264
265func (c *Client) AssociateOrgUserByUsername(orgGUID, name string) (Org, error) {
266	org := Org{Guid: orgGUID, c: c}
267	return org.AssociateUserByUsername(name)
268}
269
270func (c *Client) AssociateOrgUserByUsernameAndOrigin(orgGUID, name, origin string) (Org, error) {
271	org := Org{Guid: orgGUID, c: c}
272	return org.AssociateUserByUsernameAndOrigin(name, origin)
273}
274
275func (c *Client) AssociateOrgAuditorByUsername(orgGUID, name string) (Org, error) {
276	org := Org{Guid: orgGUID, c: c}
277	return org.AssociateAuditorByUsername(name)
278}
279
280func (c *Client) AssociateOrgAuditorByUsernameAndOrigin(orgGUID, name, origin string) (Org, error) {
281	org := Org{Guid: orgGUID, c: c}
282	return org.AssociateAuditorByUsernameAndOrigin(name, origin)
283}
284
285func (c *Client) AssociateOrgBillingManager(orgGUID, userGUID string) (Org, error) {
286	org := Org{Guid: orgGUID, c: c}
287	return org.AssociateBillingManager(userGUID)
288}
289
290func (c *Client) AssociateOrgBillingManagerByUsername(orgGUID, name string) (Org, error) {
291	org := Org{Guid: orgGUID, c: c}
292	return org.AssociateBillingManagerByUsername(name)
293}
294
295func (c *Client) AssociateOrgBillingManagerByUsernameAndOrigin(orgGUID, name, origin string) (Org, error) {
296	org := Org{Guid: orgGUID, c: c}
297	return org.AssociateBillingManagerByUsernameAndOrigin(name, origin)
298}
299
300func (c *Client) RemoveOrgManager(orgGUID, userGUID string) error {
301	org := Org{Guid: orgGUID, c: c}
302	return org.RemoveManager(userGUID)
303}
304
305func (c *Client) RemoveOrgManagerByUsername(orgGUID, name string) error {
306	org := Org{Guid: orgGUID, c: c}
307	return org.RemoveManagerByUsername(name)
308}
309
310func (c *Client) RemoveOrgManagerByUsernameAndOrigin(orgGUID, name, origin string) error {
311	org := Org{Guid: orgGUID, c: c}
312	return org.RemoveManagerByUsernameAndOrigin(name, origin)
313}
314
315func (c *Client) RemoveOrgUser(orgGUID, userGUID string) error {
316	org := Org{Guid: orgGUID, c: c}
317	return org.RemoveUser(userGUID)
318}
319
320func (c *Client) RemoveOrgAuditor(orgGUID, userGUID string) error {
321	org := Org{Guid: orgGUID, c: c}
322	return org.RemoveAuditor(userGUID)
323}
324
325func (c *Client) RemoveOrgUserByUsername(orgGUID, name string) error {
326	org := Org{Guid: orgGUID, c: c}
327	return org.RemoveUserByUsername(name)
328}
329
330func (c *Client) RemoveOrgUserByUsernameAndOrigin(orgGUID, name, origin string) error {
331	org := Org{Guid: orgGUID, c: c}
332	return org.RemoveUserByUsernameAndOrigin(name, origin)
333}
334
335func (c *Client) RemoveOrgAuditorByUsername(orgGUID, name string) error {
336	org := Org{Guid: orgGUID, c: c}
337	return org.RemoveAuditorByUsername(name)
338}
339
340func (c *Client) RemoveOrgAuditorByUsernameAndOrigin(orgGUID, name, origin string) error {
341	org := Org{Guid: orgGUID, c: c}
342	return org.RemoveAuditorByUsernameAndOrigin(name, origin)
343}
344
345func (c *Client) RemoveOrgBillingManager(orgGUID, userGUID string) error {
346	org := Org{Guid: orgGUID, c: c}
347	return org.RemoveBillingManager(userGUID)
348}
349
350func (c *Client) RemoveOrgBillingManagerByUsername(orgGUID, name string) error {
351	org := Org{Guid: orgGUID, c: c}
352	return org.RemoveBillingManagerByUsername(name)
353}
354
355func (c *Client) RemoveOrgBillingManagerByUsernameAndOrigin(orgGUID, name, origin string) error {
356	org := Org{Guid: orgGUID, c: c}
357	return org.RemoveBillingManagerByUsernameAndOrigin(name, origin)
358}
359
360func (c *Client) ListOrgSpaceQuotas(orgGUID string) ([]SpaceQuota, error) {
361	org := Org{Guid: orgGUID, c: c}
362	return org.ListSpaceQuotas()
363}
364
365func (c *Client) ListOrgPrivateDomains(orgGUID string) ([]Domain, error) {
366	org := Org{Guid: orgGUID, c: c}
367	return org.ListPrivateDomains()
368}
369
370func (c *Client) ShareOrgPrivateDomain(orgGUID, privateDomainGUID string) (*Domain, error) {
371	org := Org{Guid: orgGUID, c: c}
372	return org.SharePrivateDomain(privateDomainGUID)
373}
374
375func (c *Client) UnshareOrgPrivateDomain(orgGUID, privateDomainGUID string) error {
376	org := Org{Guid: orgGUID, c: c}
377	return org.UnsharePrivateDomain(privateDomainGUID)
378}
379
380func (o *Org) ListSpaceQuotas() ([]SpaceQuota, error) {
381	var spaceQuotas []SpaceQuota
382	requestURL := fmt.Sprintf("/v2/organizations/%s/space_quota_definitions", o.Guid)
383	for {
384		spaceQuotasResp, err := o.c.getSpaceQuotasResponse(requestURL)
385		if err != nil {
386			return []SpaceQuota{}, err
387		}
388		for _, resource := range spaceQuotasResp.Resources {
389			spaceQuotas = append(spaceQuotas, *o.c.mergeSpaceQuotaResource(resource))
390		}
391		requestURL = spaceQuotasResp.NextUrl
392		if requestURL == "" {
393			break
394		}
395	}
396	return spaceQuotas, nil
397}
398
399func (o *Org) ListPrivateDomains() ([]Domain, error) {
400	var domains []Domain
401	requestURL := fmt.Sprintf("/v2/organizations/%s/private_domains", o.Guid)
402	for {
403		domainsResp, err := o.c.getDomainsResponse(requestURL)
404		if err != nil {
405			return []Domain{}, err
406		}
407		for _, resource := range domainsResp.Resources {
408			domains = append(domains, *o.c.mergeDomainResource(resource))
409		}
410		requestURL = domainsResp.NextUrl
411		if requestURL == "" {
412			break
413		}
414	}
415	return domains, nil
416}
417
418func (o *Org) SharePrivateDomain(privateDomainGUID string) (*Domain, error) {
419	requestURL := fmt.Sprintf("/v2/organizations/%s/private_domains/%s", o.Guid, privateDomainGUID)
420	r := o.c.NewRequest("PUT", requestURL)
421	resp, err := o.c.DoRequest(r)
422	if err != nil {
423		return nil, err
424	}
425	if resp.StatusCode != http.StatusCreated {
426		return nil, errors.Wrapf(err, "Error sharing domain %s for org %s, response code: %d", privateDomainGUID, o.Guid, resp.StatusCode)
427	}
428	return o.c.handleDomainResp(resp)
429}
430
431func (o *Org) UnsharePrivateDomain(privateDomainGUID string) error {
432	requestURL := fmt.Sprintf("/v2/organizations/%s/private_domains/%s", o.Guid, privateDomainGUID)
433	r := o.c.NewRequest("DELETE", requestURL)
434	resp, err := o.c.DoRequest(r)
435	if err != nil {
436		return err
437	}
438	if resp.StatusCode != http.StatusNoContent {
439		return errors.Wrapf(err, "Error unsharing domain %s for org %s, response code: %d", privateDomainGUID, o.Guid, resp.StatusCode)
440	}
441	return nil
442}
443
444func (o *Org) associateRole(userGUID, role string) (Org, error) {
445	requestURL := fmt.Sprintf("/v2/organizations/%s/%s/%s", o.Guid, role, userGUID)
446	r := o.c.NewRequest("PUT", requestURL)
447	resp, err := o.c.DoRequest(r)
448	if err != nil {
449		return Org{}, err
450	}
451	if resp.StatusCode != http.StatusCreated {
452		return Org{}, errors.Wrapf(err, "Error associating %s %s, response code: %d", role, userGUID, resp.StatusCode)
453	}
454	return o.c.handleOrgResp(resp)
455}
456
457func (o *Org) associateRoleByUsernameAndOrigin(name, role, origin string) (Org, error) {
458	requestURL := fmt.Sprintf("/v2/organizations/%s/%s", o.Guid, role)
459	buf := bytes.NewBuffer(nil)
460	payload := make(map[string]string)
461	payload["username"] = name
462	if origin != "" {
463		payload["origin"] = origin
464	}
465	err := json.NewEncoder(buf).Encode(payload)
466	if err != nil {
467		return Org{}, err
468	}
469	r := o.c.NewRequestWithBody("PUT", requestURL, buf)
470	resp, err := o.c.DoRequest(r)
471	if err != nil {
472		return Org{}, err
473	}
474	if resp.StatusCode != http.StatusCreated {
475		return Org{}, errors.Wrapf(err, "Error associating %s %s, response code: %d", role, name, resp.StatusCode)
476	}
477	return o.c.handleOrgResp(resp)
478}
479
480func (o *Org) AssociateManager(userGUID string) (Org, error) {
481	return o.associateRole(userGUID, "managers")
482}
483
484func (o *Org) AssociateManagerByUsername(name string) (Org, error) {
485	return o.associateRoleByUsernameAndOrigin(name, "managers", "")
486}
487
488func (o *Org) AssociateManagerByUsernameAndOrigin(name, origin string) (Org, error) {
489	return o.associateRoleByUsernameAndOrigin(name, "managers", origin)
490}
491
492func (o *Org) AssociateUser(userGUID string) (Org, error) {
493	requestURL := fmt.Sprintf("/v2/organizations/%s/users/%s", o.Guid, userGUID)
494	r := o.c.NewRequest("PUT", requestURL)
495	resp, err := o.c.DoRequest(r)
496	if err != nil {
497		return Org{}, err
498	}
499	if resp.StatusCode != http.StatusCreated {
500		return Org{}, errors.Wrapf(err, "Error associating user %s, response code: %d", userGUID, resp.StatusCode)
501	}
502	return o.c.handleOrgResp(resp)
503}
504
505func (o *Org) AssociateAuditor(userGUID string) (Org, error) {
506	return o.associateRole(userGUID, "auditors")
507}
508
509func (o *Org) AssociateAuditorByUsername(name string) (Org, error) {
510	return o.associateRoleByUsernameAndOrigin(name, "auditors", "")
511}
512
513func (o *Org) AssociateAuditorByUsernameAndOrigin(name, origin string) (Org, error) {
514	return o.associateRoleByUsernameAndOrigin(name, "auditors", origin)
515}
516
517func (o *Org) AssociateBillingManager(userGUID string) (Org, error) {
518	return o.associateRole(userGUID, "billing_managers")
519}
520
521func (o *Org) AssociateBillingManagerByUsername(name string) (Org, error) {
522	return o.associateRoleByUsernameAndOrigin(name, "billing_managers", "")
523}
524func (o *Org) AssociateBillingManagerByUsernameAndOrigin(name, origin string) (Org, error) {
525	return o.associateRoleByUsernameAndOrigin(name, "billing_managers", origin)
526}
527
528func (o *Org) AssociateUserByUsername(name string) (Org, error) {
529	return o.associateUserByUsernameAndOrigin(name, "")
530}
531
532func (o *Org) AssociateUserByUsernameAndOrigin(name, origin string) (Org, error) {
533	return o.associateUserByUsernameAndOrigin(name, origin)
534}
535
536func (o *Org) associateUserByUsernameAndOrigin(name, origin string) (Org, error) {
537	requestURL := fmt.Sprintf("/v2/organizations/%s/users", o.Guid)
538	buf := bytes.NewBuffer(nil)
539	payload := make(map[string]string)
540	payload["username"] = name
541	if origin != "" {
542		payload["origin"] = origin
543	}
544	err := json.NewEncoder(buf).Encode(payload)
545	if err != nil {
546		return Org{}, err
547	}
548	r := o.c.NewRequestWithBody("PUT", requestURL, buf)
549	resp, err := o.c.DoRequest(r)
550	if err != nil {
551		return Org{}, err
552	}
553	if resp.StatusCode != http.StatusCreated {
554		return Org{}, errors.Wrapf(err, "Error associating user %s, response code: %d", name, resp.StatusCode)
555	}
556	return o.c.handleOrgResp(resp)
557}
558
559func (o *Org) removeRole(userGUID, role string) error {
560	requestURL := fmt.Sprintf("/v2/organizations/%s/%s/%s", o.Guid, role, userGUID)
561	r := o.c.NewRequest("DELETE", requestURL)
562	resp, err := o.c.DoRequest(r)
563	if err != nil {
564		return err
565	}
566	if resp.StatusCode != http.StatusNoContent {
567		return errors.Wrapf(err, "Error removing %s %s, response code: %d", role, userGUID, resp.StatusCode)
568	}
569	return nil
570}
571
572func (o *Org) removeRoleByUsernameAndOrigin(name, role, origin string) error {
573	var requestURL string
574	var method string
575	buf := bytes.NewBuffer(nil)
576	payload := make(map[string]string)
577	payload["username"] = name
578	if origin != "" {
579		requestURL = fmt.Sprintf("/v2/organizations/%s/%s/remove", o.Guid, role)
580		method = "POST"
581		payload["origin"] = origin
582	} else {
583		requestURL = fmt.Sprintf("/v2/organizations/%s/%s", o.Guid, role)
584		method = "DELETE"
585	}
586	err := json.NewEncoder(buf).Encode(payload)
587	if err != nil {
588		return err
589	}
590
591	r := o.c.NewRequestWithBody(method, requestURL, buf)
592	resp, err := o.c.DoRequest(r)
593	if err != nil {
594		return err
595	}
596	if resp.StatusCode != http.StatusNoContent {
597		return errors.Wrapf(err, "Error removing manager %s, response code: %d", name, resp.StatusCode)
598	}
599	return nil
600}
601
602func (o *Org) RemoveManager(userGUID string) error {
603	return o.removeRole(userGUID, "managers")
604}
605
606func (o *Org) RemoveManagerByUsername(name string) error {
607	return o.removeRoleByUsernameAndOrigin(name, "managers", "")
608}
609func (o *Org) RemoveManagerByUsernameAndOrigin(name, origin string) error {
610	return o.removeRoleByUsernameAndOrigin(name, "managers", origin)
611}
612
613func (o *Org) RemoveAuditor(userGUID string) error {
614	return o.removeRole(userGUID, "auditors")
615}
616
617func (o *Org) RemoveAuditorByUsername(name string) error {
618	return o.removeRoleByUsernameAndOrigin(name, "auditors", "")
619}
620func (o *Org) RemoveAuditorByUsernameAndOrigin(name, origin string) error {
621	return o.removeRoleByUsernameAndOrigin(name, "auditors", origin)
622}
623
624func (o *Org) RemoveBillingManager(userGUID string) error {
625	return o.removeRole(userGUID, "billing_managers")
626}
627
628func (o *Org) RemoveBillingManagerByUsername(name string) error {
629	return o.removeRoleByUsernameAndOrigin(name, "billing_managers", "")
630}
631
632func (o *Org) RemoveBillingManagerByUsernameAndOrigin(name, origin string) error {
633	return o.removeRoleByUsernameAndOrigin(name, "billing_managers", origin)
634}
635
636func (o *Org) RemoveUser(userGUID string) error {
637	requestURL := fmt.Sprintf("/v2/organizations/%s/users/%s", o.Guid, userGUID)
638	r := o.c.NewRequest("DELETE", requestURL)
639	resp, err := o.c.DoRequest(r)
640	if err != nil {
641		return err
642	}
643	if resp.StatusCode != http.StatusNoContent {
644		return errors.Wrapf(err, "Error removing user %s, response code: %d", userGUID, resp.StatusCode)
645	}
646	return nil
647}
648
649func (o *Org) RemoveUserByUsername(name string) error {
650	return o.removeUserByUsernameAndOrigin(name, "")
651}
652
653func (o *Org) RemoveUserByUsernameAndOrigin(name, origin string) error {
654	return o.removeUserByUsernameAndOrigin(name, origin)
655}
656
657func (o *Org) removeUserByUsernameAndOrigin(name, origin string) error {
658	var requestURL string
659	var method string
660	buf := bytes.NewBuffer(nil)
661	payload := make(map[string]string)
662	payload["username"] = name
663	if origin != "" {
664		payload["origin"] = origin
665		requestURL = fmt.Sprintf("/v2/organizations/%s/users/remove", o.Guid)
666		method = "POST"
667	} else {
668		requestURL = fmt.Sprintf("/v2/organizations/%s/users", o.Guid)
669		method = "DELETE"
670	}
671	err := json.NewEncoder(buf).Encode(payload)
672	if err != nil {
673		return err
674	}
675	r := o.c.NewRequestWithBody(method, requestURL, buf)
676	resp, err := o.c.DoRequest(r)
677	if err != nil {
678		return err
679	}
680	if resp.StatusCode != http.StatusNoContent {
681		return errors.Wrapf(err, "Error removing user %s, response code: %d", name, resp.StatusCode)
682	}
683	return nil
684}
685
686func (c *Client) CreateOrg(req OrgRequest) (Org, error) {
687	buf := bytes.NewBuffer(nil)
688	err := json.NewEncoder(buf).Encode(req)
689	if err != nil {
690		return Org{}, err
691	}
692	r := c.NewRequestWithBody("POST", "/v2/organizations", buf)
693	resp, err := c.DoRequest(r)
694	if err != nil {
695		return Org{}, err
696	}
697	if resp.StatusCode != http.StatusCreated {
698		return Org{}, errors.Wrapf(err, "Error creating organization, response code: %d", resp.StatusCode)
699	}
700	return c.handleOrgResp(resp)
701}
702
703func (c *Client) UpdateOrg(orgGUID string, orgRequest OrgRequest) (Org, error) {
704	buf := bytes.NewBuffer(nil)
705	err := json.NewEncoder(buf).Encode(orgRequest)
706	if err != nil {
707		return Org{}, err
708	}
709	r := c.NewRequestWithBody("PUT", fmt.Sprintf("/v2/organizations/%s", orgGUID), buf)
710	resp, err := c.DoRequest(r)
711	if err != nil {
712		return Org{}, err
713	}
714	if resp.StatusCode != http.StatusCreated {
715		return Org{}, errors.Wrapf(err, "Error updating organization, response code: %d", resp.StatusCode)
716	}
717	return c.handleOrgResp(resp)
718}
719
720func (c *Client) DeleteOrg(guid string, recursive, async bool) error {
721	resp, err := c.DoRequest(c.NewRequest("DELETE", fmt.Sprintf("/v2/organizations/%s?recursive=%t&async=%t", guid, recursive, async)))
722	if err != nil {
723		return err
724	}
725	if resp.StatusCode != http.StatusNoContent {
726		return errors.Wrapf(err, "Error deleting organization %s, response code: %d", guid, resp.StatusCode)
727	}
728	return nil
729}
730
731func (c *Client) getOrgResponse(requestURL string) (OrgResponse, error) {
732	var orgResp OrgResponse
733	r := c.NewRequest("GET", requestURL)
734	resp, err := c.DoRequest(r)
735	if err != nil {
736		return OrgResponse{}, errors.Wrap(err, "Error requesting orgs")
737	}
738	resBody, err := ioutil.ReadAll(resp.Body)
739	defer resp.Body.Close()
740	if err != nil {
741		return OrgResponse{}, errors.Wrap(err, "Error reading org request")
742	}
743	err = json.Unmarshal(resBody, &orgResp)
744	if err != nil {
745		return OrgResponse{}, errors.Wrap(err, "Error unmarshalling org")
746	}
747	return orgResp, nil
748}
749
750func (c *Client) fetchOrgs(requestURL string) ([]Org, error) {
751	var orgs []Org
752	for {
753		orgResp, err := c.getOrgResponse(requestURL)
754		if err != nil {
755			return []Org{}, err
756		}
757		for _, org := range orgResp.Resources {
758			orgs = append(orgs, c.mergeOrgResource(org))
759		}
760		requestURL = orgResp.NextUrl
761		if requestURL == "" {
762			break
763		}
764	}
765	return orgs, nil
766}
767
768func (c *Client) handleOrgResp(resp *http.Response) (Org, error) {
769	body, err := ioutil.ReadAll(resp.Body)
770	defer resp.Body.Close()
771	if err != nil {
772		return Org{}, err
773	}
774	var orgResource OrgResource
775	err = json.Unmarshal(body, &orgResource)
776	if err != nil {
777		return Org{}, err
778	}
779	return c.mergeOrgResource(orgResource), nil
780}
781
782func (c *Client) getOrgUserResponse(requestURL string) (OrgUserResponse, error) {
783	var omResp OrgUserResponse
784	r := c.NewRequest("GET", requestURL)
785	resp, err := c.DoRequest(r)
786	if err != nil {
787		return OrgUserResponse{}, errors.Wrap(err, "error requesting org managers")
788	}
789	defer resp.Body.Close()
790	resBody, err := ioutil.ReadAll(resp.Body)
791	if err != nil {
792		return OrgUserResponse{}, errors.Wrap(err, "error reading org managers response body")
793	}
794	if err := json.Unmarshal(resBody, &omResp); err != nil {
795		return OrgUserResponse{}, errors.Wrap(err, "error unmarshaling org managers")
796	}
797	return omResp, nil
798}
799
800func (c *Client) mergeOrgResource(org OrgResource) Org {
801	org.Entity.Guid = org.Meta.Guid
802	org.Entity.CreatedAt = org.Meta.CreatedAt
803	org.Entity.UpdatedAt = org.Meta.UpdatedAt
804	org.Entity.c = c
805	return org.Entity
806}
807
808func (c *Client) DefaultIsolationSegmentForOrg(orgGUID, isolationSegmentGUID string) error {
809	return c.updateOrgDefaultIsolationSegment(orgGUID, map[string]interface{}{"guid": isolationSegmentGUID})
810}
811
812func (c *Client) ResetDefaultIsolationSegmentForOrg(orgGUID string) error {
813	return c.updateOrgDefaultIsolationSegment(orgGUID, nil)
814}
815
816func (c *Client) updateOrgDefaultIsolationSegment(orgGUID string, data interface{}) error {
817	requestURL := fmt.Sprintf("/v3/organizations/%s/relationships/default_isolation_segment", orgGUID)
818	buf := bytes.NewBuffer(nil)
819	err := json.NewEncoder(buf).Encode(map[string]interface{}{"data": data})
820	if err != nil {
821		return err
822	}
823	r := c.NewRequestWithBody("PATCH", requestURL, buf)
824	resp, err := c.DoRequest(r)
825	if err != nil {
826		return err
827	}
828	if resp.StatusCode != http.StatusOK {
829		return errors.Wrapf(err, "Error setting default isolation segment for org %s, response code: %d", orgGUID, resp.StatusCode)
830	}
831	return nil
832}
833