Repository: cloudflare/cloudflare-go
Pull request #338 (2019-08-20 00:58:10)

Add support for Access Organization
Creates support for configuring the Access Organization details. This is
essentially the login page you receive when a service is sitting behind
Cloudflare Access.

API documentation: https://api.cloudflare.com/#access-organizations-properties


Patch:
diff --git a/access_organization.go b/access_organization.go
new file mode 100644
index 000000000..5bc4a16aa
--- /dev/null
+++ b/access_organization.go
@@ -0,0 +1,101 @@
+package cloudflare
+
+import (
+	"encoding/json"
+	"time"
+
+	"github.com/pkg/errors"
+)
+
+// AccessOrganization represents an Access organization.
+type AccessOrganization struct {
+	CreatedAt   *time.Time                    `json:"created_at"`
+	UpdatedAt   *time.Time                    `json:"updated_at"`
+	Name        string                        `json:"name"`
+	AuthDomain  string                        `json:"auth_domain"`
+	LoginDesign AccessOrganizationLoginDesign `json:"login_design"`
+}
+
+// AccessOrganizationLoginDesign represents the login design options.
+type AccessOrganizationLoginDesign struct {
+	BackgroundColor string `json:"background_color"`
+	TextColor       string `json:"text_color"`
+	LogoPath        string `json:"logo_path"`
+}
+
+// AccessOrganizationListResponse represents the response from the list
+// access organization endpoint.
+type AccessOrganizationListResponse struct {
+	Result AccessOrganization `json:"result"`
+	Response
+	ResultInfo `json:"result_info"`
+}
+
+// AccessOrganizationDetailResponse is the API response, containing a
+// single access organization.
+type AccessOrganizationDetailResponse struct {
+	Success  bool               `json:"success"`
+	Errors   []string           `json:"errors"`
+	Messages []string           `json:"messages"`
+	Result   AccessOrganization `json:"result"`
+}
+
+// AccessOrganization returns the Access organisation details.
+//
+// API reference: https://api.cloudflare.com/#access-organizations-access-organization-details
+func (api *API) AccessOrganization(accountID string) (AccessOrganization, ResultInfo, error) {
+	uri := "/accounts/" + accountID + "/access/organizations"
+
+	res, err := api.makeRequest("GET", uri, nil)
+	if err != nil {
+		return AccessOrganization{}, ResultInfo{}, errors.Wrap(err, errMakeRequestError)
+	}
+
+	var accessOrganizationListResponse AccessOrganizationListResponse
+	err = json.Unmarshal(res, &accessOrganizationListResponse)
+	if err != nil {
+		return AccessOrganization{}, ResultInfo{}, errors.Wrap(err, errUnmarshalError)
+	}
+
+	return accessOrganizationListResponse.Result, accessOrganizationListResponse.ResultInfo, nil
+}
+
+// CreateAccessOrganization creates the Access organisation details.
+//
+// API reference: https://api.cloudflare.com/#access-organizations-create-access-organization
+func (api *API) CreateAccessOrganization(accountID string, accessOrganization AccessOrganization) (AccessOrganization, error) {
+	uri := "/accounts/" + accountID + "/access/organizations"
+
+	res, err := api.makeRequest("POST", uri, accessOrganization)
+	if err != nil {
+		return AccessOrganization{}, errors.Wrap(err, errMakeRequestError)
+	}
+
+	var accessOrganizationDetailResponse AccessOrganizationDetailResponse
+	err = json.Unmarshal(res, &accessOrganizationDetailResponse)
+	if err != nil {
+		return AccessOrganization{}, errors.Wrap(err, errUnmarshalError)
+	}
+
+	return accessOrganizationDetailResponse.Result, nil
+}
+
+// UpdateAccessOrganization creates the Access organisation details.
+//
+// API reference: https://api.cloudflare.com/#access-organizations-update-access-organization
+func (api *API) UpdateAccessOrganization(accountID string, accessOrganization AccessOrganization) (AccessOrganization, error) {
+	uri := "/accounts/" + accountID + "/access/organizations"
+
+	res, err := api.makeRequest("PUT", uri, accessOrganization)
+	if err != nil {
+		return AccessOrganization{}, errors.Wrap(err, errMakeRequestError)
+	}
+
+	var accessOrganizationDetailResponse AccessOrganizationDetailResponse
+	err = json.Unmarshal(res, &accessOrganizationDetailResponse)
+	if err != nil {
+		return AccessOrganization{}, errors.Wrap(err, errUnmarshalError)
+	}
+
+	return accessOrganizationDetailResponse.Result, nil
+}


Test patch:
diff --git a/access_organization_test.go b/access_organization_test.go
new file mode 100644
index 000000000..cc6c11a72
--- /dev/null
+++ b/access_organization_test.go
@@ -0,0 +1,157 @@
+package cloudflare
+
+import (
+	"fmt"
+	"net/http"
+	"testing"
+	"time"
+
+	"github.com/stretchr/testify/assert"
+)
+
+func TestAccessOrganization(t *testing.T) {
+	setup()
+	defer teardown()
+
+	handler := func(w http.ResponseWriter, r *http.Request) {
+		assert.Equal(t, r.Method, "GET", "Expected method 'GET', got %s", r.Method)
+		w.Header().Set("content-type", "application/json")
+		fmt.Fprintf(w, `{
+			"success": true,
+			"errors": [],
+			"messages": [],
+			"result": {
+				"created_at": "2014-01-01T05:20:00.12345Z",
+				"updated_at": "2014-01-01T05:20:00.12345Z",
+				"name": "Widget Corps Internal Applications",
+				"auth_domain": "test.cloudflareaccess.com",
+				"login_design": {
+					"background_color": "#c5ed1b",
+					"text_color": "#c5ed1b",
+					"logo_path": "https://example.com/logo.png"
+				}
+			}
+		}
+		`)
+	}
+
+	mux.HandleFunc("/accounts/01a7362d577a6c3019a474fd6f485823/access/organizations", handler)
+	createdAt, _ := time.Parse(time.RFC3339, "2014-01-01T05:20:00.12345Z")
+	updatedAt, _ := time.Parse(time.RFC3339, "2014-01-01T05:20:00.12345Z")
+
+	want := AccessOrganization{
+		Name:       "Widget Corps Internal Applications",
+		CreatedAt:  &createdAt,
+		UpdatedAt:  &updatedAt,
+		AuthDomain: "test.cloudflareaccess.com",
+		LoginDesign: AccessOrganizationLoginDesign{
+			BackgroundColor: "#c5ed1b",
+			TextColor:       "#c5ed1b",
+			LogoPath:        "https://example.com/logo.png",
+		},
+	}
+
+	actual, _, err := client.AccessOrganization("01a7362d577a6c3019a474fd6f485823")
+
+	if assert.NoError(t, err) {
+		assert.Equal(t, want, actual)
+	}
+}
+
+func TestCreateAccessOrganization(t *testing.T) {
+	setup()
+	defer teardown()
+
+	handler := func(w http.ResponseWriter, r *http.Request) {
+		assert.Equal(t, r.Method, "POST", "Expected method 'POST', got %s", r.Method)
+		w.Header().Set("content-type", "application/json")
+		fmt.Fprintf(w, `{
+			"success": true,
+			"errors": [],
+			"messages": [],
+			"result": {
+				"created_at": "2014-01-01T05:20:00.12345Z",
+				"updated_at": "2014-01-01T05:20:00.12345Z",
+				"name": "Widget Corps Internal Applications",
+				"auth_domain": "test.cloudflareaccess.com",
+				"login_design": {
+					"background_color": "#c5ed1b",
+					"text_color": "#c5ed1b",
+					"logo_path": "https://example.com/logo.png"
+				}
+			}
+		}
+		`)
+	}
+
+	mux.HandleFunc("/accounts/01a7362d577a6c3019a474fd6f485823/access/organizations", handler)
+	createdAt, _ := time.Parse(time.RFC3339, "2014-01-01T05:20:00.12345Z")
+	updatedAt, _ := time.Parse(time.RFC3339, "2014-01-01T05:20:00.12345Z")
+
+	want := AccessOrganization{
+		Name:       "Widget Corps Internal Applications",
+		CreatedAt:  &createdAt,
+		UpdatedAt:  &updatedAt,
+		AuthDomain: "test.cloudflareaccess.com",
+		LoginDesign: AccessOrganizationLoginDesign{
+			BackgroundColor: "#c5ed1b",
+			TextColor:       "#c5ed1b",
+			LogoPath:        "https://example.com/logo.png",
+		},
+	}
+
+	actual, err := client.CreateAccessOrganization("01a7362d577a6c3019a474fd6f485823", want)
+
+	if assert.NoError(t, err) {
+		assert.Equal(t, want, actual)
+	}
+}
+
+func TestUpdateAccessOrganization(t *testing.T) {
+	setup()
+	defer teardown()
+
+	handler := func(w http.ResponseWriter, r *http.Request) {
+		assert.Equal(t, r.Method, "PUT", "Expected method 'PUT', got %s", r.Method)
+		w.Header().Set("content-type", "application/json")
+		fmt.Fprintf(w, `{
+			"success": true,
+			"errors": [],
+			"messages": [],
+			"result": {
+				"created_at": "2014-01-01T05:20:00.12345Z",
+				"updated_at": "2014-01-01T05:20:00.12345Z",
+				"name": "Widget Corps Internal Applications",
+				"auth_domain": "test.cloudflareaccess.com",
+				"login_design": {
+					"background_color": "#c5ed1b",
+					"text_color": "#c5ed1b",
+					"logo_path": "https://example.com/logo.png"
+				}
+			}
+		}
+		`)
+	}
+
+	mux.HandleFunc("/accounts/01a7362d577a6c3019a474fd6f485823/access/organizations", handler)
+	createdAt, _ := time.Parse(time.RFC3339, "2014-01-01T05:20:00.12345Z")
+	updatedAt, _ := time.Parse(time.RFC3339, "2014-01-01T05:20:00.12345Z")
+
+	want := AccessOrganization{
+		Name:       "Widget Corps Internal Applications",
+		CreatedAt:  &createdAt,
+		UpdatedAt:  &updatedAt,
+		AuthDomain: "test.cloudflareaccess.com",
+		LoginDesign: AccessOrganizationLoginDesign{
+			BackgroundColor: "#c5ed1b",
+			TextColor:       "#c5ed1b",
+			LogoPath:        "https://example.com/logo.png",
+		},
+	}
+
+	actual, err := client.UpdateAccessOrganization("01a7362d577a6c3019a474fd6f485823", want)
+
+	if assert.NoError(t, err) {
+		assert.Equal(t, want, actual)
+	}
+}