From 54c6b7dca6e45a60e53f52fbbce05dbaada0a276 Mon Sep 17 00:00:00 2001 From: Martin Atkins Date: Sun, 11 Oct 2015 17:03:16 -0700 Subject: [PATCH 01/55] CRUD methods for data sources. --- datasource.go | 123 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 123 insertions(+) create mode 100644 datasource.go diff --git a/datasource.go b/datasource.go new file mode 100644 index 00000000..bb926981 --- /dev/null +++ b/datasource.go @@ -0,0 +1,123 @@ +package gapi + +import ( + "bytes" + "encoding/json" + "errors" + "fmt" + "io/ioutil" +) + +type DataSource struct { + Id int64 `json:"id,omitempty"` + Name string `json:"name"` + Type string `json:"type"` + URL string `json:"url"` + Access string `json:"access"` + + Database string `json:"database,omitempty"` + User string `json:"user,omitempty"` + Password string `json:"password,omitempty"` + + OrgId int64 `json:"orgId,omitempty"` + IsDefault bool `json:"isDefault"` + + BasicAuth bool `json:"basicAuth"` + BasicAuthUser string `json:"basicAuthUser,omitempty"` + BasicAuthPassword string `json:"basicAuthPassword,omitempty"` +} + +func (c *Client) NewDataSource(s *DataSource) (int64, error) { + data, err := json.Marshal(s) + if err != nil { + return 0, err + } + req, err := c.newRequest("POST", "/api/datasources", bytes.NewBuffer(data)) + if err != nil { + return 0, err + } + + resp, err := c.Do(req) + if err != nil { + return 0, err + } + if resp.StatusCode != 200 { + return 0, errors.New(resp.Status) + } + + data, err = ioutil.ReadAll(resp.Body) + if err != nil { + return 0, err + } + + result := struct { + Id int64 `json:"id"` + }{} + err = json.Unmarshal(data, &result) + return result.Id, err +} + +func (c *Client) UpdateDataSource(s *DataSource) error { + path := fmt.Sprintf("/api/datasources/%d", s.Id) + data, err := json.Marshal(s) + if err != nil { + return err + } + req, err := c.newRequest("PUT", path, bytes.NewBuffer(data)) + if err != nil { + return err + } + + resp, err := c.Do(req) + if err != nil { + return err + } + if resp.StatusCode != 200 { + return errors.New(resp.Status) + } + + return nil +} + +func (c *Client) DataSource(id int64) (*DataSource, error) { + path := fmt.Sprintf("/api/datasources/%d", id) + req, err := c.newRequest("GET", path, nil) + if err != nil { + return nil, err + } + + resp, err := c.Do(req) + if err != nil { + return nil, err + } + if resp.StatusCode != 200 { + return nil, errors.New(resp.Status) + } + + data, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, err + } + + result := &DataSource{} + err = json.Unmarshal(data, &result) + return result, err +} + +func (c *Client) DeleteDataSource(id int64) error { + path := fmt.Sprintf("/api/datasources/%d", id) + req, err := c.newRequest("DELETE", path, nil) + if err != nil { + return err + } + + resp, err := c.Do(req) + if err != nil { + return err + } + if resp.StatusCode != 200 { + return errors.New(resp.Status) + } + + return nil +} From d49f95c81c580a4e7a15244b9b12dce8f60750f4 Mon Sep 17 00:00:00 2001 From: Martin Atkins Date: Sun, 11 Oct 2015 19:03:32 -0700 Subject: [PATCH 02/55] CRUD methods for Dashboards. --- dashboard.go | 100 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) create mode 100644 dashboard.go diff --git a/dashboard.go b/dashboard.go new file mode 100644 index 00000000..ca45dc9a --- /dev/null +++ b/dashboard.go @@ -0,0 +1,100 @@ +package gapi + +import ( + "bytes" + "encoding/json" + "errors" + "fmt" + "io/ioutil" +) + +type DashboardMeta struct { + IsStarred bool `json:"isStarred"` + Slug string `json:"slug"` +} + +type DashboardSaveResponse struct { + Slug string `json:"slug"` + Status string `json:"status"` + Version int64 `json:"version"` +} + +type Dashboard struct { + Meta DashboardMeta `json:"meta"` + Model map[string]interface{} `json:"dashboard"` +} + +func (c *Client) SaveDashboard(model map[string]interface{}, overwrite bool) (*DashboardSaveResponse, error) { + wrapper := map[string]interface{}{ + "dashboard": model, + "overwrite": overwrite, + } + data, err := json.Marshal(wrapper) + if err != nil { + return nil, err + } + req, err := c.newRequest("POST", "/api/dashboards/db", bytes.NewBuffer(data)) + if err != nil { + return nil, err + } + + resp, err := c.Do(req) + if err != nil { + return nil, err + } + if resp.StatusCode != 200 { + return nil, errors.New(resp.Status) + } + + data, err = ioutil.ReadAll(resp.Body) + if err != nil { + return nil, err + } + + result := &DashboardSaveResponse{} + err = json.Unmarshal(data, &result) + return result, err +} + +func (c *Client) Dashboard(slug string) (*Dashboard, error) { + path := fmt.Sprintf("/api/dashboards/db/%s", slug) + req, err := c.newRequest("GET", path, nil) + if err != nil { + return nil, err + } + + resp, err := c.Do(req) + if err != nil { + return nil, err + } + if resp.StatusCode != 200 { + return nil, errors.New(resp.Status) + } + + data, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, err + } + + result := &Dashboard{} + err = json.Unmarshal(data, &result) + return result, err +} + +func (c *Client) DeleteDashboard(slug string) error { + path := fmt.Sprintf("/api/dashboards/db/%s", slug) + req, err := c.newRequest("DELETE", path, nil) + if err != nil { + return err + } + + resp, err := c.Do(req) + if err != nil { + return err + } + if resp.StatusCode != 200 { + return errors.New(resp.Status) + } + + return nil +} From 086eb9b364680893a53f41fe6173a909ebd22e1d Mon Sep 17 00:00:00 2001 From: Maxime Visonneau Date: Tue, 15 Aug 2017 17:18:14 +0100 Subject: [PATCH 03/55] Implemented alert notification management --- alertnotification.go | 112 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 112 insertions(+) create mode 100644 alertnotification.go diff --git a/alertnotification.go b/alertnotification.go new file mode 100644 index 00000000..39a32b9f --- /dev/null +++ b/alertnotification.go @@ -0,0 +1,112 @@ +package gapi + +import ( + "bytes" + "encoding/json" + "errors" + "fmt" + "io/ioutil" +) + +type AlertNotification struct { + Id int64 `json:"id,omitempty"` + Name string `json:"name"` + Type string `json:"type"` + IsDefault bool `json:"isDefault"` + Settings interface{} `json:"settings"` +} + +func (c *Client) AlertNotification(id int64) (*AlertNotification, error) { + path := fmt.Sprintf("/api/alert-notifications/%d", id) + req, err := c.newRequest("GET", path, nil) + if err != nil { + return nil, err + } + + resp, err := c.Do(req) + if err != nil { + return nil, err + } + if resp.StatusCode != 200 { + return nil, errors.New(resp.Status) + } + + data, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, err + } + + result := &AlertNotification{} + err = json.Unmarshal(data, &result) + return result, err +} + +func (c *Client) NewAlertNotification(a *AlertNotification) (int64, error) { + data, err := json.Marshal(a) + if err != nil { + return 0, err + } + req, err := c.newRequest("POST", "/api/alert-notifications", bytes.NewBuffer(data)) + if err != nil { + return 0, err + } + + resp, err := c.Do(req) + if err != nil { + return 0, err + } + if resp.StatusCode != 200 { + return 0, errors.New(resp.Status) + } + + data, err = ioutil.ReadAll(resp.Body) + if err != nil { + return 0, err + } + + result := struct { + Id int64 `json:"id"` + }{} + err = json.Unmarshal(data, &result) + return result.Id, err +} + +func (c *Client) UpdateAlertNotification(a *AlertNotification) error { + path := fmt.Sprintf("/api/alert-notifications/%d", a.Id) + data, err := json.Marshal(a) + if err != nil { + return err + } + req, err := c.newRequest("PUT", path, bytes.NewBuffer(data)) + if err != nil { + return err + } + + resp, err := c.Do(req) + if err != nil { + return err + } + if resp.StatusCode != 200 { + return errors.New(resp.Status) + } + + return nil +} + +func (c *Client) DeleteAlertNotification(id int64) error { + path := fmt.Sprintf("/api/alert-notifications/%d", id) + req, err := c.newRequest("DELETE", path, nil) + if err != nil { + return err + } + + resp, err := c.Do(req) + if err != nil { + return err + } + if resp.StatusCode != 200 { + return errors.New(resp.Status) + } + + return nil +} From 912be290f31e9dcaf41edc5e33476cfec4024cab Mon Sep 17 00:00:00 2001 From: Mike Ball Date: Wed, 20 Sep 2017 21:40:46 -0400 Subject: [PATCH 04/55] add JSONData and SecureJSONData to DataSource These are used in creating the AWS CloudWatch datasource: http://docs.grafana.org/http_api/data_source/#create-data-source --- datasource.go | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/datasource.go b/datasource.go index bb926981..27d3585a 100644 --- a/datasource.go +++ b/datasource.go @@ -25,6 +25,21 @@ type DataSource struct { BasicAuth bool `json:"basicAuth"` BasicAuthUser string `json:"basicAuthUser,omitempty"` BasicAuthPassword string `json:"basicAuthPassword,omitempty"` + + JSONData JSONData `json:"jsonData,omitempty"` + SecureJSONData SecureJSONData `json:"secureJsonData,omitempty"` +} + +// JSONData is a representation of the datasource `jsonData` property +type JSONData struct { + AuthType string `json:"authType,omitempty"` + DefaultRegion string `json:"defaultRegion,omitempty"` +} + +// SecureJSONData is a representation of the datasource `secureJsonData` property +type SecureJSONData struct { + AccessKey string `json:"accessKey,omitempty"` + SecretKey string `json:"secretKey,omitempty"` } func (c *Client) NewDataSource(s *DataSource) (int64, error) { From ed820f622963b18e6b0382faf1d69614304c264c Mon Sep 17 00:00:00 2001 From: Mike Ball Date: Wed, 20 Sep 2017 21:41:51 -0400 Subject: [PATCH 05/55] add basic NewDataSource test --- datasource_test.go | 68 ++++++++++++++++++++++++++++++++++++++++ grafana_fixtures_test.go | 5 +++ 2 files changed, 73 insertions(+) create mode 100644 datasource_test.go create mode 100644 grafana_fixtures_test.go diff --git a/datasource_test.go b/datasource_test.go new file mode 100644 index 00000000..dfb28c17 --- /dev/null +++ b/datasource_test.go @@ -0,0 +1,68 @@ +package gapi + +import ( + "fmt" + "net/http" + "net/http/httptest" + "net/url" + "testing" + + "github.com/gobs/pretty" +) + +func gapiTestTools(code int, body string) (*httptest.Server, *Client) { + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(code) + w.Header().Set("Content-Type", "application/json") + fmt.Fprintf(w, body) + })) + + tr := &http.Transport{ + Proxy: func(req *http.Request) (*url.URL, error) { + return url.Parse(server.URL) + }, + } + + httpClient := &http.Client{Transport: tr} + + url := url.URL{ + Scheme: "http", + Host: "my-grafana.com", + } + + client := &Client{"my-key", url, httpClient} + + return server, client +} + +func TestNewDataSource(t *testing.T) { + server, client := gapiTestTools(200, createdDataSourceJSON) + defer server.Close() + + ds := &DataSource{ + Name: "foo", + Type: "cloudwatch", + URL: "http://some-url.com", + Access: "access", + IsDefault: true, + JSONData: JSONData{ + AuthType: "keys", + DefaultRegion: "us-east-1", + }, + SecureJSONData: SecureJSONData{ + AccessKey: "123", + SecretKey: "456", + }, + } + + created, err := client.NewDataSource(ds) + if err != nil { + t.Error(err) + } + + t.Log(pretty.PrettyFormat(created)) + + if created != 1 { + t.Error("datasource creation response should return the created datasource ID") + } +} diff --git a/grafana_fixtures_test.go b/grafana_fixtures_test.go new file mode 100644 index 00000000..26510ccb --- /dev/null +++ b/grafana_fixtures_test.go @@ -0,0 +1,5 @@ +package gapi + +const ( + createdDataSourceJSON = `{"id":1,"message":"Datasource added", "name": "test_datasource"}` +) From caa7705d217168f9aa9a3a849f7c1cf341937cc1 Mon Sep 17 00:00:00 2001 From: Mike Ball Date: Wed, 20 Sep 2017 21:42:35 -0400 Subject: [PATCH 06/55] add test-running documentation --- README.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/README.md b/README.md index 859bd902..581af01d 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,11 @@ # grafana-api-golang-client + Grafana HTTP API Client for Go + +## Tests + +To run the tests: + +``` +go test +``` From 3bdf366f46c02eaf142f1f4728e98183056204ee Mon Sep 17 00:00:00 2001 From: Mike Ball Date: Thu, 21 Sep 2017 06:45:19 -0400 Subject: [PATCH 07/55] log request details if env var `GF_LOG` is present printing all request details in all environments creates a security vulnerability --- client.go | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/client.go b/client.go index 1e4846cc..2106c51e 100644 --- a/client.go +++ b/client.go @@ -6,6 +6,7 @@ import ( "io" "net/http" "net/url" + "os" "strings" ) @@ -46,11 +47,15 @@ func (c *Client) newRequest(method, path string, body io.Reader) (*http.Request, if c.key != "" { req.Header.Add("Authorization", c.key) } - if body == nil { - fmt.Println("request to ", url.String(), "with no body data") - } else { - fmt.Println("request to ", url.String(), "with body data", body.(*bytes.Buffer).String()) + + if os.Getenv("GF_LOG") != "" { + if body == nil { + fmt.Println("request to ", url.String(), "with no body data") + } else { + fmt.Println("request to ", url.String(), "with body data", body.(*bytes.Buffer).String()) + } } + req.Header.Add("Content-Type", "application/json") return req, err } From 35245a0ae5ef935eebb75de9bd8dfd94499f9b38 Mon Sep 17 00:00:00 2001 From: Mike Ball Date: Tue, 26 Sep 2017 20:50:11 -0400 Subject: [PATCH 08/55] use `log.Println` This was suggested per feedback from @apparentlymart --- client.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/client.go b/client.go index 2106c51e..e9bc076c 100644 --- a/client.go +++ b/client.go @@ -4,6 +4,7 @@ import ( "bytes" "fmt" "io" + "log" "net/http" "net/url" "os" @@ -50,9 +51,9 @@ func (c *Client) newRequest(method, path string, body io.Reader) (*http.Request, if os.Getenv("GF_LOG") != "" { if body == nil { - fmt.Println("request to ", url.String(), "with no body data") + log.Println("request to ", url.String(), "with no body data") } else { - fmt.Println("request to ", url.String(), "with body data", body.(*bytes.Buffer).String()) + log.Println("request to ", url.String(), "with body data", body.(*bytes.Buffer).String()) } } From 8003b0c560418e48c3da6edd6619accc0bcf648a Mon Sep 17 00:00:00 2001 From: Matt Morrison Date: Fri, 17 Nov 2017 13:33:27 +1300 Subject: [PATCH 09/55] =?UTF-8?q?If=20the=20base=20URL=20includes=20a=20pa?= =?UTF-8?q?th=20component,=20don=E2=80=99t=20overwrite=20this=20with=20the?= =?UTF-8?q?=20request=20path.=20This=20is=20necessary=20when=20Grafana=20i?= =?UTF-8?q?s=20running=20behind=20a=20reverse=20proxy=20that=20is=20doing?= =?UTF-8?q?=20path=20based=20routing.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/client.go b/client.go index e9bc076c..d92ba883 100644 --- a/client.go +++ b/client.go @@ -8,6 +8,7 @@ import ( "net/http" "net/url" "os" + "path" "strings" ) @@ -38,9 +39,9 @@ func New(auth, baseURL string) (*Client, error) { }, nil } -func (c *Client) newRequest(method, path string, body io.Reader) (*http.Request, error) { +func (c *Client) newRequest(method, requestPath string, body io.Reader) (*http.Request, error) { url := c.baseURL - url.Path = path + url.Path = path.Join(url.Path, requestPath) req, err := http.NewRequest(method, url.String(), body) if err != nil { return req, err From b18120d6d271a629602efd2a264c94df6a920f76 Mon Sep 17 00:00:00 2001 From: Vahe Sahakyan Date: Fri, 15 Dec 2017 03:13:45 +0100 Subject: [PATCH 10/55] Add assumeRoleArn into data structure --- datasource.go | 1 + datasource_test.go | 1 + 2 files changed, 2 insertions(+) diff --git a/datasource.go b/datasource.go index 27d3585a..02d9257f 100644 --- a/datasource.go +++ b/datasource.go @@ -32,6 +32,7 @@ type DataSource struct { // JSONData is a representation of the datasource `jsonData` property type JSONData struct { + AssumeRoleArn string `json:"assumeRoleArn,omitempty"` AuthType string `json:"authType,omitempty"` DefaultRegion string `json:"defaultRegion,omitempty"` } diff --git a/datasource_test.go b/datasource_test.go index dfb28c17..baf1e176 100644 --- a/datasource_test.go +++ b/datasource_test.go @@ -46,6 +46,7 @@ func TestNewDataSource(t *testing.T) { Access: "access", IsDefault: true, JSONData: JSONData{ + AssumeRoleArn: "arn:aws:iam::123:role/some-role", AuthType: "keys", DefaultRegion: "us-east-1", }, From 2967b3af48a0bba901cf724fad7c8e0b261e7ad9 Mon Sep 17 00:00:00 2001 From: Teemu Pohja Date: Thu, 22 Feb 2018 12:24:21 +0200 Subject: [PATCH 11/55] Add customMetricsNamespaces into data structure --- datasource.go | 7 ++++--- datasource_test.go | 7 ++++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/datasource.go b/datasource.go index 02d9257f..ab42b88e 100644 --- a/datasource.go +++ b/datasource.go @@ -32,9 +32,10 @@ type DataSource struct { // JSONData is a representation of the datasource `jsonData` property type JSONData struct { - AssumeRoleArn string `json:"assumeRoleArn,omitempty"` - AuthType string `json:"authType,omitempty"` - DefaultRegion string `json:"defaultRegion,omitempty"` + AssumeRoleArn string `json:"assumeRoleArn,omitempty"` + AuthType string `json:"authType,omitempty"` + CustomMetricsNamespaces string `json:"customMetricsNamespaces,omitempty"` + DefaultRegion string `json:"defaultRegion,omitempty"` } // SecureJSONData is a representation of the datasource `secureJsonData` property diff --git a/datasource_test.go b/datasource_test.go index baf1e176..f9be257d 100644 --- a/datasource_test.go +++ b/datasource_test.go @@ -46,9 +46,10 @@ func TestNewDataSource(t *testing.T) { Access: "access", IsDefault: true, JSONData: JSONData{ - AssumeRoleArn: "arn:aws:iam::123:role/some-role", - AuthType: "keys", - DefaultRegion: "us-east-1", + AssumeRoleArn: "arn:aws:iam::123:role/some-role", + AuthType: "keys", + CustomMetricsNamespaces: "SomeNamespace", + DefaultRegion: "us-east-1", }, SecureJSONData: SecureJSONData{ AccessKey: "123", From 7380665c19d6fb0b587e654f25d2604787d890c8 Mon Sep 17 00:00:00 2001 From: Teemu Pohja Date: Thu, 22 Feb 2018 12:42:15 +0200 Subject: [PATCH 12/55] Add customMetricsNamespaces into data structure (#1) --- datasource.go | 7 ++++--- datasource_test.go | 7 ++++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/datasource.go b/datasource.go index 02d9257f..ab42b88e 100644 --- a/datasource.go +++ b/datasource.go @@ -32,9 +32,10 @@ type DataSource struct { // JSONData is a representation of the datasource `jsonData` property type JSONData struct { - AssumeRoleArn string `json:"assumeRoleArn,omitempty"` - AuthType string `json:"authType,omitempty"` - DefaultRegion string `json:"defaultRegion,omitempty"` + AssumeRoleArn string `json:"assumeRoleArn,omitempty"` + AuthType string `json:"authType,omitempty"` + CustomMetricsNamespaces string `json:"customMetricsNamespaces,omitempty"` + DefaultRegion string `json:"defaultRegion,omitempty"` } // SecureJSONData is a representation of the datasource `secureJsonData` property diff --git a/datasource_test.go b/datasource_test.go index baf1e176..f9be257d 100644 --- a/datasource_test.go +++ b/datasource_test.go @@ -46,9 +46,10 @@ func TestNewDataSource(t *testing.T) { Access: "access", IsDefault: true, JSONData: JSONData{ - AssumeRoleArn: "arn:aws:iam::123:role/some-role", - AuthType: "keys", - DefaultRegion: "us-east-1", + AssumeRoleArn: "arn:aws:iam::123:role/some-role", + AuthType: "keys", + CustomMetricsNamespaces: "SomeNamespace", + DefaultRegion: "us-east-1", }, SecureJSONData: SecureJSONData{ AccessKey: "123", From a2ec15ba01fa0618c8fdbbd6e1e75e59605d018c Mon Sep 17 00:00:00 2001 From: Malcolm Jones Date: Mon, 18 Jun 2018 12:20:13 -0400 Subject: [PATCH 13/55] Add method for fetching org membership --- orgs.go | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/orgs.go b/orgs.go index 5a38732c..140ff13c 100644 --- a/orgs.go +++ b/orgs.go @@ -13,6 +13,14 @@ type Org struct { Name string } +type OrgUser struct { + OrgId int64 + UserId int64 + Email string + Login string + Role string +} + func (c *Client) Orgs() ([]Org, error) { orgs := make([]Org, 0) @@ -68,3 +76,27 @@ func (c *Client) DeleteOrg(id int64) error { } return err } + +func (c *Client) OrgUsers(id int64) ([]OrgUser, error) { + users := make([]OrgUser, 0) + req, err := c.newRequest("GET", fmt.Sprintf("/api/orgs/%d/users", id), nil) + if err != nil { + return users, err + } + resp, err := c.Do(req) + if err != nil { + return users, err + } + if resp.StatusCode != 200 { + return users, errors.New(resp.Status) + } + data, err := ioutil.ReadAll(resp.Body) + if err != nil { + return users, err + } + err = json.Unmarshal(data, &users) + if err != nil { + return users, err + } + return users, err +} From 1ad379d50054b796f4224cb58740269775e59406 Mon Sep 17 00:00:00 2001 From: Malcolm Jones Date: Mon, 18 Jun 2018 14:54:50 -0400 Subject: [PATCH 14/55] Add methods to add/update/delete org users --- orgs.go | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/orgs.go b/orgs.go index 140ff13c..3037e5a6 100644 --- a/orgs.go +++ b/orgs.go @@ -100,3 +100,57 @@ func (c *Client) OrgUsers(id int64) ([]OrgUser, error) { } return users, err } + +func (c *Client) AddOrgUser(orgId int64, user, role string) error { + dataMap := map[string]string{ + "loginOrEmail": user, + "role": role, + } + data, err := json.Marshal(dataMap) + req, err := c.newRequest("POST", fmt.Sprintf("/api/orgs/%d/users", orgId), bytes.NewBuffer(data)) + if err != nil { + return err + } + resp, err := c.Do(req) + if err != nil { + return err + } + if resp.StatusCode != 200 { + return errors.New(resp.Status) + } + return err +} + +func (c *Client) UpdateOrgUser(orgId, userId int64, role string) error { + dataMap := map[string]string{ + "role": role, + } + data, err := json.Marshal(dataMap) + req, err := c.newRequest("PATCH", fmt.Sprintf("/api/orgs/%d/users/%d", orgId, userId), bytes.NewBuffer(data)) + if err != nil { + return err + } + resp, err := c.Do(req) + if err != nil { + return err + } + if resp.StatusCode != 200 { + return errors.New(resp.Status) + } + return err +} + +func (c *Client) RemoveOrgUser(orgId, userId int64) error { + req, err := c.newRequest("DELETE", fmt.Sprintf("/api/orgs/%d/users/%d", orgId, userId), nil) + if err != nil { + return err + } + resp, err := c.Do(req) + if err != nil { + return err + } + if resp.StatusCode != 200 { + return errors.New(resp.Status) + } + return err +} From 7fbea2bd4e463f303e556f035ee6a7d66cceb2ea Mon Sep 17 00:00:00 2001 From: Malcolm Jones Date: Mon, 18 Jun 2018 14:58:46 -0400 Subject: [PATCH 15/55] Moved OrgUser methods to separate file --- org_users.go | 95 ++++++++++++++++++++++++++++++++++++++++++++++++++++ orgs.go | 86 ----------------------------------------------- 2 files changed, 95 insertions(+), 86 deletions(-) create mode 100644 org_users.go diff --git a/org_users.go b/org_users.go new file mode 100644 index 00000000..9c453c11 --- /dev/null +++ b/org_users.go @@ -0,0 +1,95 @@ +package gapi + +import ( + "bytes" + "encoding/json" + "errors" + "fmt" + "io/ioutil" +) + +type OrgUser struct { + OrgId int64 + UserId int64 + Email string + Login string + Role string +} + +func (c *Client) OrgUsers(id int64) ([]OrgUser, error) { + users := make([]OrgUser, 0) + req, err := c.newRequest("GET", fmt.Sprintf("/api/orgs/%d/users", id), nil) + if err != nil { + return users, err + } + resp, err := c.Do(req) + if err != nil { + return users, err + } + if resp.StatusCode != 200 { + return users, errors.New(resp.Status) + } + data, err := ioutil.ReadAll(resp.Body) + if err != nil { + return users, err + } + err = json.Unmarshal(data, &users) + if err != nil { + return users, err + } + return users, err +} + +func (c *Client) AddOrgUser(orgId int64, user, role string) error { + dataMap := map[string]string{ + "loginOrEmail": user, + "role": role, + } + data, err := json.Marshal(dataMap) + req, err := c.newRequest("POST", fmt.Sprintf("/api/orgs/%d/users", orgId), bytes.NewBuffer(data)) + if err != nil { + return err + } + resp, err := c.Do(req) + if err != nil { + return err + } + if resp.StatusCode != 200 { + return errors.New(resp.Status) + } + return err +} + +func (c *Client) UpdateOrgUser(orgId, userId int64, role string) error { + dataMap := map[string]string{ + "role": role, + } + data, err := json.Marshal(dataMap) + req, err := c.newRequest("PATCH", fmt.Sprintf("/api/orgs/%d/users/%d", orgId, userId), bytes.NewBuffer(data)) + if err != nil { + return err + } + resp, err := c.Do(req) + if err != nil { + return err + } + if resp.StatusCode != 200 { + return errors.New(resp.Status) + } + return err +} + +func (c *Client) RemoveOrgUser(orgId, userId int64) error { + req, err := c.newRequest("DELETE", fmt.Sprintf("/api/orgs/%d/users/%d", orgId, userId), nil) + if err != nil { + return err + } + resp, err := c.Do(req) + if err != nil { + return err + } + if resp.StatusCode != 200 { + return errors.New(resp.Status) + } + return err +} diff --git a/orgs.go b/orgs.go index 3037e5a6..5a38732c 100644 --- a/orgs.go +++ b/orgs.go @@ -13,14 +13,6 @@ type Org struct { Name string } -type OrgUser struct { - OrgId int64 - UserId int64 - Email string - Login string - Role string -} - func (c *Client) Orgs() ([]Org, error) { orgs := make([]Org, 0) @@ -76,81 +68,3 @@ func (c *Client) DeleteOrg(id int64) error { } return err } - -func (c *Client) OrgUsers(id int64) ([]OrgUser, error) { - users := make([]OrgUser, 0) - req, err := c.newRequest("GET", fmt.Sprintf("/api/orgs/%d/users", id), nil) - if err != nil { - return users, err - } - resp, err := c.Do(req) - if err != nil { - return users, err - } - if resp.StatusCode != 200 { - return users, errors.New(resp.Status) - } - data, err := ioutil.ReadAll(resp.Body) - if err != nil { - return users, err - } - err = json.Unmarshal(data, &users) - if err != nil { - return users, err - } - return users, err -} - -func (c *Client) AddOrgUser(orgId int64, user, role string) error { - dataMap := map[string]string{ - "loginOrEmail": user, - "role": role, - } - data, err := json.Marshal(dataMap) - req, err := c.newRequest("POST", fmt.Sprintf("/api/orgs/%d/users", orgId), bytes.NewBuffer(data)) - if err != nil { - return err - } - resp, err := c.Do(req) - if err != nil { - return err - } - if resp.StatusCode != 200 { - return errors.New(resp.Status) - } - return err -} - -func (c *Client) UpdateOrgUser(orgId, userId int64, role string) error { - dataMap := map[string]string{ - "role": role, - } - data, err := json.Marshal(dataMap) - req, err := c.newRequest("PATCH", fmt.Sprintf("/api/orgs/%d/users/%d", orgId, userId), bytes.NewBuffer(data)) - if err != nil { - return err - } - resp, err := c.Do(req) - if err != nil { - return err - } - if resp.StatusCode != 200 { - return errors.New(resp.Status) - } - return err -} - -func (c *Client) RemoveOrgUser(orgId, userId int64) error { - req, err := c.newRequest("DELETE", fmt.Sprintf("/api/orgs/%d/users/%d", orgId, userId), nil) - if err != nil { - return err - } - resp, err := c.Do(req) - if err != nil { - return err - } - if resp.StatusCode != 200 { - return errors.New(resp.Status) - } - return err -} From 04e16fbbebd60f6fd1838fca0c2f9e4059fa8ad1 Mon Sep 17 00:00:00 2001 From: Malcolm Jones Date: Mon, 18 Jun 2018 15:05:47 -0400 Subject: [PATCH 16/55] Fix spacing issue --- org_users.go | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/org_users.go b/org_users.go index 9c453c11..adb45f75 100644 --- a/org_users.go +++ b/org_users.go @@ -41,23 +41,23 @@ func (c *Client) OrgUsers(id int64) ([]OrgUser, error) { } func (c *Client) AddOrgUser(orgId int64, user, role string) error { - dataMap := map[string]string{ - "loginOrEmail": user, - "role": role, - } - data, err := json.Marshal(dataMap) - req, err := c.newRequest("POST", fmt.Sprintf("/api/orgs/%d/users", orgId), bytes.NewBuffer(data)) - if err != nil { - return err - } - resp, err := c.Do(req) - if err != nil { - return err - } - if resp.StatusCode != 200 { - return errors.New(resp.Status) - } + dataMap := map[string]string{ + "loginOrEmail": user, + "role": role, + } + data, err := json.Marshal(dataMap) + req, err := c.newRequest("POST", fmt.Sprintf("/api/orgs/%d/users", orgId), bytes.NewBuffer(data)) + if err != nil { + return err + } + resp, err := c.Do(req) + if err != nil { return err + } + if resp.StatusCode != 200 { + return errors.New(resp.Status) + } + return err } func (c *Client) UpdateOrgUser(orgId, userId int64, role string) error { From 47432327b58ed8fd9874435ff2b3b4064b85e5d3 Mon Sep 17 00:00:00 2001 From: Malcolm Jones Date: Mon, 18 Jun 2018 16:33:38 -0400 Subject: [PATCH 17/55] Add method to retrieve org by name --- orgs.go | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/orgs.go b/orgs.go index 5a38732c..f937c0c0 100644 --- a/orgs.go +++ b/orgs.go @@ -35,6 +35,27 @@ func (c *Client) Orgs() ([]Org, error) { return orgs, err } +func (c *Client) OrgByName(name string) (Org, error) { + org := Org{} + req, err := c.newRequest("GET", fmt.Sprintf("/api/orgs/name/%s", name), nil) + if err != nil { + return org, err + } + resp, err := c.Do(req) + if err != nil { + return org, err + } + if resp.StatusCode != 200 { + return org, errors.New(resp.Status) + } + data, err := ioutil.ReadAll(resp.Body) + if err != nil { + return org, err + } + err = json.Unmarshal(data, &org) + return org, err +} + func (c *Client) NewOrg(name string) error { settings := map[string]string{ "name": name, From 443facd23933b5027d0e4de56a8943f7fd46991a Mon Sep 17 00:00:00 2001 From: Malcolm Jones Date: Wed, 20 Jun 2018 11:15:12 -0400 Subject: [PATCH 18/55] Better naming for JSON data --- orgs.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/orgs.go b/orgs.go index f937c0c0..36af7566 100644 --- a/orgs.go +++ b/orgs.go @@ -57,10 +57,10 @@ func (c *Client) OrgByName(name string) (Org, error) { } func (c *Client) NewOrg(name string) error { - settings := map[string]string{ + dataMap := map[string]string{ "name": name, } - data, err := json.Marshal(settings) + data, err := json.Marshal(dataMap) req, err := c.newRequest("POST", "/api/orgs", bytes.NewBuffer(data)) if err != nil { return err From 0b75ce3969623816d50e4750bc15980f3a3355b8 Mon Sep 17 00:00:00 2001 From: Malcolm Jones Date: Wed, 20 Jun 2018 11:15:30 -0400 Subject: [PATCH 19/55] Add endpoint for updating orgs --- orgs.go | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/orgs.go b/orgs.go index 36af7566..c6b3c1c2 100644 --- a/orgs.go +++ b/orgs.go @@ -75,6 +75,25 @@ func (c *Client) NewOrg(name string) error { return err } +func (c *Client) UpdateOrg(id int64, name string) error { + dataMap := map[string]string{ + "name": name, + } + data, err := json.Marshal(dataMap) + req, err := c.newRequest("PUT", fmt.Sprintf("/api/orgs/%d", id), bytes.NewBuffer(data)) + if err != nil { + return err + } + resp, err := c.Do(req) + if err != nil { + return err + } + if resp.StatusCode != 200 { + return errors.New(resp.Status) + } + return err +} + func (c *Client) DeleteOrg(id int64) error { req, err := c.newRequest("DELETE", fmt.Sprintf("/api/orgs/%d", id), nil) if err != nil { From a33f220993c7a2be5f455071e67e5fec3b443e6f Mon Sep 17 00:00:00 2001 From: Malcolm Jones Date: Wed, 20 Jun 2018 17:23:28 -0400 Subject: [PATCH 20/55] Add endpoint for getting org by id --- orgs.go | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/orgs.go b/orgs.go index c6b3c1c2..a1af8b19 100644 --- a/orgs.go +++ b/orgs.go @@ -56,6 +56,27 @@ func (c *Client) OrgByName(name string) (Org, error) { return org, err } +func (c *Client) Org(id int) (Org, error) { + org := Org{} + req, err := c.newRequest("GET", fmt.Sprintf("/api/orgs/%d", id), nil) + if err != nil { + return org, err + } + resp, err := c.Do(req) + if err != nil { + return org, err + } + if resp.StatusCode != 200 { + return org, errors.New(resp.Status) + } + data, err := ioutil.ReadAll(resp.Body) + if err != nil { + return org, err + } + err = json.Unmarshal(data, &org) + return org, err +} + func (c *Client) NewOrg(name string) error { dataMap := map[string]string{ "name": name, From 9968a4a69af279f9f45db8e30e49bdf4e0462bc6 Mon Sep 17 00:00:00 2001 From: Malcolm Jones Date: Wed, 20 Jun 2018 17:28:26 -0400 Subject: [PATCH 21/55] Fix arg type --- orgs.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/orgs.go b/orgs.go index a1af8b19..0e0d0e29 100644 --- a/orgs.go +++ b/orgs.go @@ -56,7 +56,7 @@ func (c *Client) OrgByName(name string) (Org, error) { return org, err } -func (c *Client) Org(id int) (Org, error) { +func (c *Client) Org(id int64) (Org, error) { org := Org{} req, err := c.newRequest("GET", fmt.Sprintf("/api/orgs/%d", id), nil) if err != nil { From 09e688da8c466c24c24f9464d2f18108eed71554 Mon Sep 17 00:00:00 2001 From: Malcolm Jones Date: Tue, 26 Jun 2018 11:30:35 -0400 Subject: [PATCH 22/55] Add request method for supporting GET parameters --- client.go | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/client.go b/client.go index d92ba883..f5707fbf 100644 --- a/client.go +++ b/client.go @@ -61,3 +61,18 @@ func (c *Client) newRequest(method, requestPath string, body io.Reader) (*http.R req.Header.Add("Content-Type", "application/json") return req, err } + +func (c *Client) newQueryRequest(method, requestPath string, query string) (*http.Request, error) { + url := c.baseURL + url.Path = path.Join(url.Path, requestPath) + url.RawQuery = query + req, err := http.NewRequest(method, url.String(), nil) + if err != nil { + return req, err + } + if c.key != "" { + req.Header.Add("Authorization", c.key) + } + req.Header.Add("Content-Type", "application/json") + return req, err +} From e3d5e5a691f08f4238af4ecf8a70c98c6019d862 Mon Sep 17 00:00:00 2001 From: Malcolm Jones Date: Tue, 26 Jun 2018 11:30:56 -0400 Subject: [PATCH 23/55] Add method for getting a user by login or email --- user.go | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/user.go b/user.go index 13a6e6ff..ddd13fd7 100644 --- a/user.go +++ b/user.go @@ -3,6 +3,7 @@ package gapi import ( "encoding/json" "errors" + "fmt" "io/ioutil" ) @@ -37,3 +38,28 @@ func (c *Client) Users() ([]User, error) { } return users, err } + +func (c *Client) UserByEmail(email string) (User, error) { + user := User{} + req, err := c.newQueryRequest("GET", "/api/users/lookup", fmt.Sprintf("loginOrEmail=%s", email)) + if err != nil { + return user, err + } + fmt.Println(req) + resp, err := c.Do(req) + if err != nil { + return user, err + } + if resp.StatusCode != 200 { + return user, errors.New(resp.Status) + } + data, err := ioutil.ReadAll(resp.Body) + if err != nil { + return user, err + } + err = json.Unmarshal(data, &user) + if err != nil { + return user, err + } + return user, err +} From c8a681363545ed50d9a44658d7fc011005f13176 Mon Sep 17 00:00:00 2001 From: Malcolm Jones Date: Tue, 26 Jun 2018 17:27:12 -0400 Subject: [PATCH 24/55] Add logging of query parameters --- client.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/client.go b/client.go index f5707fbf..6845679f 100644 --- a/client.go +++ b/client.go @@ -73,6 +73,15 @@ func (c *Client) newQueryRequest(method, requestPath string, query string) (*htt if c.key != "" { req.Header.Add("Authorization", c.key) } + + if os.Getenv("GF_LOG") != "" { + if body == nil { + log.Println("request to ", url.String(), "with no query data") + } else { + log.Println("request to ", url.String(), "with query data", query) + } + } + req.Header.Add("Content-Type", "application/json") return req, err } From 4e1736bcb95f98adf68542b9d1ba229fb46aadec Mon Sep 17 00:00:00 2001 From: Malcolm Jones Date: Tue, 26 Jun 2018 17:36:35 -0400 Subject: [PATCH 25/55] Fix variable name --- client.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client.go b/client.go index 6845679f..de5fc3c1 100644 --- a/client.go +++ b/client.go @@ -75,7 +75,7 @@ func (c *Client) newQueryRequest(method, requestPath string, query string) (*htt } if os.Getenv("GF_LOG") != "" { - if body == nil { + if query == "" { log.Println("request to ", url.String(), "with no query data") } else { log.Println("request to ", url.String(), "with query data", query) From 9286081345ad725ee74acf1a0e7939f502afe8e5 Mon Sep 17 00:00:00 2001 From: Malcolm Jones Date: Wed, 27 Jun 2018 01:14:32 -0400 Subject: [PATCH 26/55] Add logging --- orgs.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/orgs.go b/orgs.go index 0e0d0e29..0b664480 100644 --- a/orgs.go +++ b/orgs.go @@ -91,7 +91,11 @@ func (c *Client) NewOrg(name string) error { return err } if resp.StatusCode != 200 { - return errors.New(resp.Status) + data, err := ioutil.ReadAll(resp.Body) + if err != nil { + return errors.New(resp.Status) + } + return errors.New(string(data[:len(data)])) } return err } From 7a4d445c8640aaf050a281059143cef50ec8271c Mon Sep 17 00:00:00 2001 From: Malcolm Jones Date: Wed, 27 Jun 2018 14:10:58 -0400 Subject: [PATCH 27/55] Add generic method to create a new user --- admin.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/admin.go b/admin.go index 3da1ae92..c0bfa3ef 100644 --- a/admin.go +++ b/admin.go @@ -30,6 +30,10 @@ func (c *Client) CreateUserForm(settings dtos.AdminCreateUserForm) error { return err } +func (c *Client) CreateUser(email, login, name, password string) error { + return c.CreateUserForm(dtos.AdminCreateUserForm{email, login, name, password}) +} + func (c *Client) DeleteUser(id int64) error { req, err := c.newRequest("DELETE", fmt.Sprintf("/api/admin/users/%d", id), nil) if err != nil { From 646a34a5b4e79168f101cc67d1e0efde991fe631 Mon Sep 17 00:00:00 2001 From: Malcolm Jones Date: Wed, 27 Jun 2018 18:06:16 -0400 Subject: [PATCH 28/55] Return the orgId for newly created orgs --- orgs.go | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/orgs.go b/orgs.go index 0b664480..2b54279e 100644 --- a/orgs.go +++ b/orgs.go @@ -13,6 +13,10 @@ type Org struct { Name string } +type NewOrg struct { + OrgId int64 +} + func (c *Client) Orgs() ([]Org, error) { orgs := make([]Org, 0) @@ -77,27 +81,29 @@ func (c *Client) Org(id int64) (Org, error) { return org, err } -func (c *Client) NewOrg(name string) error { +func (c *Client) NewOrg(name string) (NewOrg, error) { dataMap := map[string]string{ "name": name, } data, err := json.Marshal(dataMap) + org := NewOrg{} req, err := c.newRequest("POST", "/api/orgs", bytes.NewBuffer(data)) if err != nil { - return err + return org, err } resp, err := c.Do(req) if err != nil { - return err + return org, err } if resp.StatusCode != 200 { - data, err := ioutil.ReadAll(resp.Body) - if err != nil { - return errors.New(resp.Status) - } - return errors.New(string(data[:len(data)])) + return org, errors.New(resp.Status) } - return err + data, err = ioutil.ReadAll(resp.Body) + if err != nil { + return org, err + } + err = json.Unmarshal(data, &org) + return org, err } func (c *Client) UpdateOrg(id int64, name string) error { From a55e6879c82b1f5b2e54de798630d11b1b32eb49 Mon Sep 17 00:00:00 2001 From: Malcolm Jones Date: Wed, 27 Jun 2018 18:06:42 -0400 Subject: [PATCH 29/55] Add tests for orgs --- grafana_fixtures_test.go | 7 +++ orgs_test.go | 99 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 106 insertions(+) create mode 100644 orgs_test.go diff --git a/grafana_fixtures_test.go b/grafana_fixtures_test.go index 26510ccb..7a178c93 100644 --- a/grafana_fixtures_test.go +++ b/grafana_fixtures_test.go @@ -2,4 +2,11 @@ package gapi const ( createdDataSourceJSON = `{"id":1,"message":"Datasource added", "name": "test_datasource"}` + + getOrgsJSON = `[{"id":1,"name":"Main Org."},{"id":2,"name":"Test Org."}]` + getOrgJSON = `{"id":1,"name":"Main Org.","address":{"address1":"","address2":"","city":"","zipCode":"","state":"","country":""}}` + createdOrgJSON = `{"message":"Organization created","orgId":1}` + updatedOrgJSON = `{"message":"Organization updated"}` + deletedOrgJSON = `{"message":"Organization deleted"}` + ) diff --git a/orgs_test.go b/orgs_test.go new file mode 100644 index 00000000..04b0090d --- /dev/null +++ b/orgs_test.go @@ -0,0 +1,99 @@ +package gapi + +import ( + // "net/http" + // "net/http/httptest" + // "net/url" + "testing" + + "github.com/gobs/pretty" +) + +func TestOrgs(t *testing.T) { + server, client := gapiTestTools(200, getOrgsJSON) + defer server.Close() + + orgs, err := client.Orgs() + if err != nil { + t.Error(err) + } + + t.Log(pretty.PrettyFormat(orgs)) + + if len(orgs) != 2 { + t.Error("Length of returned orgs should be 2") + } + if orgs[0].Id != 1 || orgs[0].Name != "Main Org." { + t.Error("Not correctly parsing returned organizations.") + } +} + +func TestOrgByName(t *testing.T) { + server, client := gapiTestTools(200, getOrgJSON) + defer server.Close() + + org := "Main Org." + resp, err := client.OrgByName(org) + if err != nil { + t.Error(err) + } + + t.Log(pretty.PrettyFormat(resp)) + + if resp.Id != 1 || resp.Name != org { + t.Error("Not correctly parsing returned organization.") + } +} + +func TestOrg(t *testing.T) { + server, client := gapiTestTools(200, getOrgJSON) + defer server.Close() + + org := int64(1) + resp, err := client.Org(org) + if err != nil { + t.Error(err) + } + + t.Log(pretty.PrettyFormat(resp)) + + if resp.Id != org || resp.Name != "Main Org." { + t.Error("Not correctly parsing returned organization.") + } +} + +func TestNewOrg(t *testing.T) { + server, client := gapiTestTools(200, createdOrgJSON) + defer server.Close() + + resp, err := client.NewOrg("test-org") + if err != nil { + t.Error(err) + } + + t.Log(pretty.PrettyFormat(resp)) + + if resp.OrgId != 1 { + t.Error("Not correctly parsing returned creation message.") + } +} + +func TestUpdateOrg(t *testing.T) { + server, client := gapiTestTools(200, updatedOrgJSON) + defer server.Close() + + err := client.UpdateOrg(int64(1), "test-org") + if err != nil { + t.Error(err) + } +} + +func TestDeleteOrg(t *testing.T) { + server, client := gapiTestTools(200, deletedOrgJSON) + defer server.Close() + + err := client.DeleteOrg(int64(1)) + if err != nil { + t.Error(err) + } +} From bc8a14285b21f7beac1f5fafaaa5b43a7f12a5be Mon Sep 17 00:00:00 2001 From: Malcolm Jones Date: Thu, 28 Jun 2018 10:40:16 -0400 Subject: [PATCH 30/55] Add org_users tests --- grafana_fixtures_test.go | 4 +++ org_users_test.go | 67 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+) create mode 100644 org_users_test.go diff --git a/grafana_fixtures_test.go b/grafana_fixtures_test.go index 7a178c93..68811829 100644 --- a/grafana_fixtures_test.go +++ b/grafana_fixtures_test.go @@ -9,4 +9,8 @@ const ( updatedOrgJSON = `{"message":"Organization updated"}` deletedOrgJSON = `{"message":"Organization deleted"}` + getOrgUsersJSON = `[{"orgId":1,"userId":1,"email":"admin@localhost","avatarUrl":"/avatar/46d229b033af06a191ff2267bca9ae56","login":"admin","role":"Admin","lastSeenAt":"2018-06-28T14:16:11Z","lastSeenAtAge":"\u003c 1m"}]` + addOrgUserJSON = `{"message":"User added to organization"}` + updateOrgUserJSON = `{"message":"Organization user updated"}` + removeOrgUserJSON = `{"message":"User removed from organization"}` ) diff --git a/org_users_test.go b/org_users_test.go new file mode 100644 index 00000000..c725a9fb --- /dev/null +++ b/org_users_test.go @@ -0,0 +1,67 @@ +package gapi + +import ( + "testing" + "github.com/gobs/pretty" +) + +func TestOrgUsers(t *testing.T) { + server, client := gapiTestTools(200, getOrgUsersJSON) + defer server.Close() + + org := int64(1) + resp, err := client.OrgUsers(org) + if err != nil { + t.Error(err) + } + + t.Log(pretty.PrettyFormat(resp)) + + user := OrgUser{ + OrgId: 1, + UserId: 1, + Email: "admin@localhost", + Login: "admin", + Role: "Admin", + } + + if resp[0] != user { + t.Error("Not correctly parsing returned organization users.") + } +} + +func TestAddOrgUser(t *testing.T) { + server, client := gapiTestTools(200, addOrgUserJSON) + defer server.Close() + + orgId, user, role := int64(1), "admin@localhost", "Admin" + + err := client.AddOrgUser(orgId, user, role) + if err != nil { + t.Error(err) + } +} + +func TestUpdateOrgUser(t *testing.T) { + server, client := gapiTestTools(200, updateOrgUserJSON) + defer server.Close() + + orgId, userId, role := int64(1), int64(1), "Editor" + + err := client.UpdateOrgUser(orgId, userId, role) + if err != nil { + t.Error(err) + } +} + +func TestRemoveOrgUser(t *testing.T) { + server, client := gapiTestTools(200, removeOrgUserJSON) + defer server.Close() + + orgId, userId := int64(1), int64(1) + + err := client.RemoveOrgUser(orgId, userId) + if err != nil { + t.Error(err) + } +} From 266ab81d2c5996193e0522f8d3daa4e2f0d33810 Mon Sep 17 00:00:00 2001 From: Malcolm Jones Date: Thu, 28 Jun 2018 11:14:07 -0400 Subject: [PATCH 31/55] Fix JSON decoding --- user.go | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/user.go b/user.go index ddd13fd7..c20109b4 100644 --- a/user.go +++ b/user.go @@ -15,6 +15,14 @@ type User struct { IsAdmin bool } +type Lookup struct { + Id int64 + Email string + Name string + Login string + IsAdmin bool `json:"isGrafanaAdmin"` +} + func (c *Client) Users() ([]User, error) { users := make([]User, 0) req, err := c.newRequest("GET", "/api/users", nil) @@ -57,9 +65,11 @@ func (c *Client) UserByEmail(email string) (User, error) { if err != nil { return user, err } - err = json.Unmarshal(data, &user) + tmp := Lookup{} + err = json.Unmarshal(data, &tmp) if err != nil { return user, err } + user = User(tmp) return user, err } From 4a01512afb0fdb99db85a83620b6ea463031db45 Mon Sep 17 00:00:00 2001 From: Malcolm Jones Date: Thu, 28 Jun 2018 11:14:33 -0400 Subject: [PATCH 32/55] Add tests for user.go --- grafana_fixtures_test.go | 3 +++ user_test.go | 53 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+) create mode 100644 user_test.go diff --git a/grafana_fixtures_test.go b/grafana_fixtures_test.go index 68811829..e95ba4f5 100644 --- a/grafana_fixtures_test.go +++ b/grafana_fixtures_test.go @@ -13,4 +13,7 @@ const ( addOrgUserJSON = `{"message":"User added to organization"}` updateOrgUserJSON = `{"message":"Organization user updated"}` removeOrgUserJSON = `{"message":"User removed from organization"}` + + getUsersJSON = `[{"id":1,"name":"","login":"admin","email":"admin@localhost","avatarUrl":"/avatar/46d229b033af06a191ff2267bca9ae56","isAdmin":true,"lastSeenAt":"2018-06-28T14:42:24Z","lastSeenAtAge":"\u003c 1m"}]` + getUserByEmailJSON = `{"id":1,"email":"admin@localhost","name":"","login":"admin","theme":"","orgId":1,"isGrafanaAdmin":true}` ) diff --git a/user_test.go b/user_test.go new file mode 100644 index 00000000..9a98eef9 --- /dev/null +++ b/user_test.go @@ -0,0 +1,53 @@ +package gapi + +import ( + "testing" + "github.com/gobs/pretty" +) + +func TestUsers(t *testing.T) { + server, client := gapiTestTools(200, getUsersJSON) + defer server.Close() + + resp, err := client.Users() + if err != nil { + t.Error(err) + } + + t.Log(pretty.PrettyFormat(resp)) + + user := User{ + Id: 1, + Email: "admin@localhost", + Name: "", + Login: "admin", + IsAdmin: true, + } + + if len(resp) != 1 || resp[0] != user { + t.Error("Not correctly parsing returned users.") + } +} + +func TestUserByEmail(t *testing.T) { + server, client := gapiTestTools(200, getUserByEmailJSON) + defer server.Close() + + resp, err := client.UserByEmail("admin@localhost") + if err != nil { + t.Error(err) + } + + t.Log(pretty.PrettyFormat(resp)) + + user := User{ + Id: 1, + Email: "admin@localhost", + Name: "", + Login: "admin", + IsAdmin: true, + } + if resp != user { + t.Error("Not correctly parsing returned user.") + } +} From 5857fb34ed7f83a2a1c8949756b245343df705f1 Mon Sep 17 00:00:00 2001 From: Malcolm Jones Date: Thu, 28 Jun 2018 12:44:00 -0400 Subject: [PATCH 33/55] Better handling of create org response --- orgs.go | 27 +++++++++++++++------------ orgs_test.go | 2 +- 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/orgs.go b/orgs.go index 2b54279e..f00a2ebf 100644 --- a/orgs.go +++ b/orgs.go @@ -13,10 +13,6 @@ type Org struct { Name string } -type NewOrg struct { - OrgId int64 -} - func (c *Client) Orgs() ([]Org, error) { orgs := make([]Org, 0) @@ -81,29 +77,36 @@ func (c *Client) Org(id int64) (Org, error) { return org, err } -func (c *Client) NewOrg(name string) (NewOrg, error) { +func (c *Client) NewOrg(name string) (int64, error) { dataMap := map[string]string{ "name": name, } data, err := json.Marshal(dataMap) - org := NewOrg{} + id := int64(0) req, err := c.newRequest("POST", "/api/orgs", bytes.NewBuffer(data)) if err != nil { - return org, err + return id, err } resp, err := c.Do(req) if err != nil { - return org, err + return id, err } if resp.StatusCode != 200 { - return org, errors.New(resp.Status) + return id, errors.New(resp.Status) } data, err = ioutil.ReadAll(resp.Body) if err != nil { - return org, err + return id, err } - err = json.Unmarshal(data, &org) - return org, err + tmp := struct { + Id int64 `json:"orgId"` + }{} + err = json.Unmarshal(data, &tmp) + if err != nil { + return id, err + } + id = tmp.Id + return id, err } func (c *Client) UpdateOrg(id int64, name string) error { diff --git a/orgs_test.go b/orgs_test.go index 04b0090d..a5e266fc 100644 --- a/orgs_test.go +++ b/orgs_test.go @@ -73,7 +73,7 @@ func TestNewOrg(t *testing.T) { t.Log(pretty.PrettyFormat(resp)) - if resp.OrgId != 1 { + if resp != 1 { t.Error("Not correctly parsing returned creation message.") } } From d0e8099a357abc5ebf29b1cf5f2d755fd6a36d10 Mon Sep 17 00:00:00 2001 From: Malcolm Jones Date: Thu, 28 Jun 2018 12:45:49 -0400 Subject: [PATCH 34/55] Add JSON definitions for struct fields --- user.go | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/user.go b/user.go index c20109b4..ef012c26 100644 --- a/user.go +++ b/user.go @@ -8,19 +8,11 @@ import ( ) type User struct { - Id int64 - Email string - Name string - Login string - IsAdmin bool -} - -type Lookup struct { - Id int64 - Email string - Name string - Login string - IsAdmin bool `json:"isGrafanaAdmin"` + Id int64 `json:"id"` + Email string `json:"email"` + Name string `json:"name"` + Login string `json:"login"` + IsAdmin bool `json:"isAdmin"` } func (c *Client) Users() ([]User, error) { @@ -53,7 +45,6 @@ func (c *Client) UserByEmail(email string) (User, error) { if err != nil { return user, err } - fmt.Println(req) resp, err := c.Do(req) if err != nil { return user, err @@ -65,7 +56,13 @@ func (c *Client) UserByEmail(email string) (User, error) { if err != nil { return user, err } - tmp := Lookup{} + tmp := struct { + Id int64 `json:"id"` + Email string `json:"email"` + Name string `json:"name"` + Login string `json:"login"` + IsAdmin bool `json:"isGrafanaAdmin"` + }{} err = json.Unmarshal(data, &tmp) if err != nil { return user, err From f5ae1b67132e13a9815fe388f395866546a4505a Mon Sep 17 00:00:00 2001 From: Malcolm Jones Date: Thu, 28 Jun 2018 12:55:56 -0400 Subject: [PATCH 35/55] Return id of newly created user --- admin.go | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/admin.go b/admin.go index c0bfa3ef..70484e2c 100644 --- a/admin.go +++ b/admin.go @@ -10,27 +10,35 @@ import ( "github.com/grafana/grafana/pkg/api/dtos" ) -func (c *Client) CreateUserForm(settings dtos.AdminCreateUserForm) error { +func (c *Client) CreateUserForm(settings dtos.AdminCreateUserForm) (int64, error) { + id := int64(0) data, err := json.Marshal(settings) req, err := c.newRequest("POST", "/api/admin/users", bytes.NewBuffer(data)) if err != nil { - return err + return id, err } resp, err := c.Do(req) if err != nil { - return err + return id, err + } + if resp.StatusCode != 200 { + return id, errors.New(resp.Status) } data, err = ioutil.ReadAll(resp.Body) if err != nil { - return err + return id, err } - if resp.StatusCode != 200 { - return errors.New(resp.Status) + user := struct { + Id int64 `json:"id"` + }{} + err = json.Unmarshal(data, &user) + if err != nil { + return id, err } - return err + return user.Id, err } -func (c *Client) CreateUser(email, login, name, password string) error { +func (c *Client) CreateUser(email, login, name, password string) (int64, error) { return c.CreateUserForm(dtos.AdminCreateUserForm{email, login, name, password}) } From 2af2767573a3e14b801e32e62f23554453213e8d Mon Sep 17 00:00:00 2001 From: Malcolm Jones Date: Thu, 28 Jun 2018 12:56:41 -0400 Subject: [PATCH 36/55] Add testing output and tests for admin.go --- admin_test.go | 57 ++++++++++++++++++++++++++++++++++++++++ grafana_fixtures_test.go | 8 ++++++ 2 files changed, 65 insertions(+) create mode 100644 admin_test.go diff --git a/admin_test.go b/admin_test.go new file mode 100644 index 00000000..9043e578 --- /dev/null +++ b/admin_test.go @@ -0,0 +1,57 @@ +package gapi + +import ( + "testing" + // "github.com/gobs/pretty" + "github.com/grafana/grafana/pkg/api/dtos" +) + +func TestCreateUserForm(t *testing.T) { + server, client := gapiTestTools(200, createUserJSON) + defer server.Close() + + user := dtos.AdminCreateUserForm{ + Email: "admin@localhost", + Login: "admin", + Name: "Administrator", + Password: "password", + } + resp, err := client.CreateUserForm(user) + if err != nil { + t.Error(err) + } + + if resp != 1 { + t.Error("Not correctly parsing returned user message.") + } +} + +func TestCreateUser(t *testing.T) { + server, client := gapiTestTools(200, createUserJSON) + defer server.Close() + + user := dtos.AdminCreateUserForm{ + Email: "admin@localhost", + Login: "admin", + Name: "Administrator", + Password: "password", + } + resp, err := client.CreateUser(user.Email, user.Login, user.Email, user.Password) + if err != nil { + t.Error(err) + } + + if resp != 1 { + t.Error("Not correctly parsing returned user message.") + } +} + +func TestDeleteUser(t *testing.T) { + server, client := gapiTestTools(200, deleteUserJSON) + defer server.Close() + + err := client.DeleteUser(int64(1)) + if err != nil { + t.Error(err) + } +} diff --git a/grafana_fixtures_test.go b/grafana_fixtures_test.go index e95ba4f5..290873b8 100644 --- a/grafana_fixtures_test.go +++ b/grafana_fixtures_test.go @@ -1,19 +1,27 @@ package gapi const ( + // datasource_test.go createdDataSourceJSON = `{"id":1,"message":"Datasource added", "name": "test_datasource"}` + // orgs_test.go getOrgsJSON = `[{"id":1,"name":"Main Org."},{"id":2,"name":"Test Org."}]` getOrgJSON = `{"id":1,"name":"Main Org.","address":{"address1":"","address2":"","city":"","zipCode":"","state":"","country":""}}` createdOrgJSON = `{"message":"Organization created","orgId":1}` updatedOrgJSON = `{"message":"Organization updated"}` deletedOrgJSON = `{"message":"Organization deleted"}` + // org_users_test.go getOrgUsersJSON = `[{"orgId":1,"userId":1,"email":"admin@localhost","avatarUrl":"/avatar/46d229b033af06a191ff2267bca9ae56","login":"admin","role":"Admin","lastSeenAt":"2018-06-28T14:16:11Z","lastSeenAtAge":"\u003c 1m"}]` addOrgUserJSON = `{"message":"User added to organization"}` updateOrgUserJSON = `{"message":"Organization user updated"}` removeOrgUserJSON = `{"message":"User removed from organization"}` + // users_test.go getUsersJSON = `[{"id":1,"name":"","login":"admin","email":"admin@localhost","avatarUrl":"/avatar/46d229b033af06a191ff2267bca9ae56","isAdmin":true,"lastSeenAt":"2018-06-28T14:42:24Z","lastSeenAtAge":"\u003c 1m"}]` getUserByEmailJSON = `{"id":1,"email":"admin@localhost","name":"","login":"admin","theme":"","orgId":1,"isGrafanaAdmin":true}` + + // admin_test.go + createUserJSON = `{"id":1,"message":"User created"}` + deleteUserJSON = `{"message":"User deleted"}` ) From 11680999cb8f827fca6322574d54941a370c5d49 Mon Sep 17 00:00:00 2001 From: Malcolm Jones Date: Thu, 28 Jun 2018 14:28:06 -0400 Subject: [PATCH 37/55] Move fixtures into respective test files --- admin_test.go | 5 +++++ datasource_test.go | 4 ++++ grafana_fixtures_test.go | 27 --------------------------- org_users_test.go | 7 +++++++ orgs_test.go | 8 ++++++++ user_test.go | 5 +++++ 6 files changed, 29 insertions(+), 27 deletions(-) delete mode 100644 grafana_fixtures_test.go diff --git a/admin_test.go b/admin_test.go index 9043e578..5997b408 100644 --- a/admin_test.go +++ b/admin_test.go @@ -6,6 +6,11 @@ import ( "github.com/grafana/grafana/pkg/api/dtos" ) +const ( + createUserJSON = `{"id":1,"message":"User created"}` + deleteUserJSON = `{"message":"User deleted"}` +) + func TestCreateUserForm(t *testing.T) { server, client := gapiTestTools(200, createUserJSON) defer server.Close() diff --git a/datasource_test.go b/datasource_test.go index f9be257d..a182ea29 100644 --- a/datasource_test.go +++ b/datasource_test.go @@ -10,6 +10,10 @@ import ( "github.com/gobs/pretty" ) +const ( + createdDataSourceJSON = `{"id":1,"message":"Datasource added", "name": "test_datasource"}` +) + func gapiTestTools(code int, body string) (*httptest.Server, *Client) { server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(code) diff --git a/grafana_fixtures_test.go b/grafana_fixtures_test.go deleted file mode 100644 index 290873b8..00000000 --- a/grafana_fixtures_test.go +++ /dev/null @@ -1,27 +0,0 @@ -package gapi - -const ( - // datasource_test.go - createdDataSourceJSON = `{"id":1,"message":"Datasource added", "name": "test_datasource"}` - - // orgs_test.go - getOrgsJSON = `[{"id":1,"name":"Main Org."},{"id":2,"name":"Test Org."}]` - getOrgJSON = `{"id":1,"name":"Main Org.","address":{"address1":"","address2":"","city":"","zipCode":"","state":"","country":""}}` - createdOrgJSON = `{"message":"Organization created","orgId":1}` - updatedOrgJSON = `{"message":"Organization updated"}` - deletedOrgJSON = `{"message":"Organization deleted"}` - - // org_users_test.go - getOrgUsersJSON = `[{"orgId":1,"userId":1,"email":"admin@localhost","avatarUrl":"/avatar/46d229b033af06a191ff2267bca9ae56","login":"admin","role":"Admin","lastSeenAt":"2018-06-28T14:16:11Z","lastSeenAtAge":"\u003c 1m"}]` - addOrgUserJSON = `{"message":"User added to organization"}` - updateOrgUserJSON = `{"message":"Organization user updated"}` - removeOrgUserJSON = `{"message":"User removed from organization"}` - - // users_test.go - getUsersJSON = `[{"id":1,"name":"","login":"admin","email":"admin@localhost","avatarUrl":"/avatar/46d229b033af06a191ff2267bca9ae56","isAdmin":true,"lastSeenAt":"2018-06-28T14:42:24Z","lastSeenAtAge":"\u003c 1m"}]` - getUserByEmailJSON = `{"id":1,"email":"admin@localhost","name":"","login":"admin","theme":"","orgId":1,"isGrafanaAdmin":true}` - - // admin_test.go - createUserJSON = `{"id":1,"message":"User created"}` - deleteUserJSON = `{"message":"User deleted"}` -) diff --git a/org_users_test.go b/org_users_test.go index c725a9fb..dfbb7f49 100644 --- a/org_users_test.go +++ b/org_users_test.go @@ -5,6 +5,13 @@ import ( "github.com/gobs/pretty" ) +const ( + getOrgUsersJSON = `[{"orgId":1,"userId":1,"email":"admin@localhost","avatarUrl":"/avatar/46d229b033af06a191ff2267bca9ae56","login":"admin","role":"Admin","lastSeenAt":"2018-06-28T14:16:11Z","lastSeenAtAge":"\u003c 1m"}]` + addOrgUserJSON = `{"message":"User added to organization"}` + updateOrgUserJSON = `{"message":"Organization user updated"}` + removeOrgUserJSON = `{"message":"User removed from organization"}` +) + func TestOrgUsers(t *testing.T) { server, client := gapiTestTools(200, getOrgUsersJSON) defer server.Close() diff --git a/orgs_test.go b/orgs_test.go index a5e266fc..af54ba55 100644 --- a/orgs_test.go +++ b/orgs_test.go @@ -9,6 +9,14 @@ import ( "github.com/gobs/pretty" ) +const ( + getOrgsJSON = `[{"id":1,"name":"Main Org."},{"id":2,"name":"Test Org."}]` + getOrgJSON = `{"id":1,"name":"Main Org.","address":{"address1":"","address2":"","city":"","zipCode":"","state":"","country":""}}` + createdOrgJSON = `{"message":"Organization created","orgId":1}` + updatedOrgJSON = `{"message":"Organization updated"}` + deletedOrgJSON = `{"message":"Organization deleted"}` +) + func TestOrgs(t *testing.T) { server, client := gapiTestTools(200, getOrgsJSON) defer server.Close() diff --git a/user_test.go b/user_test.go index 9a98eef9..fa4a23b2 100644 --- a/user_test.go +++ b/user_test.go @@ -5,6 +5,11 @@ import ( "github.com/gobs/pretty" ) +const ( + getUsersJSON = `[{"id":1,"name":"","login":"admin","email":"admin@localhost","avatarUrl":"/avatar/46d229b033af06a191ff2267bca9ae56","isAdmin":true,"lastSeenAt":"2018-06-28T14:42:24Z","lastSeenAtAge":"\u003c 1m"}]` + getUserByEmailJSON = `{"id":1,"email":"admin@localhost","name":"","login":"admin","theme":"","orgId":1,"isGrafanaAdmin":true}` +) + func TestUsers(t *testing.T) { server, client := gapiTestTools(200, getUsersJSON) defer server.Close() From f63ea136dfe45bcc37f2b0d83c5f2bdf0b3635f8 Mon Sep 17 00:00:00 2001 From: Malcolm Jones Date: Thu, 28 Jun 2018 15:35:57 -0400 Subject: [PATCH 38/55] Remove unused imports --- admin_test.go | 1 - orgs_test.go | 4 ---- 2 files changed, 5 deletions(-) diff --git a/admin_test.go b/admin_test.go index 5997b408..04065d14 100644 --- a/admin_test.go +++ b/admin_test.go @@ -2,7 +2,6 @@ package gapi import ( "testing" - // "github.com/gobs/pretty" "github.com/grafana/grafana/pkg/api/dtos" ) diff --git a/orgs_test.go b/orgs_test.go index af54ba55..956d896f 100644 --- a/orgs_test.go +++ b/orgs_test.go @@ -1,11 +1,7 @@ package gapi import ( - // "net/http" - // "net/http/httptest" - // "net/url" "testing" - "github.com/gobs/pretty" ) From f0238e701a6a9f28f3cb1e7f603a5b0c04ea5f6b Mon Sep 17 00:00:00 2001 From: Malcolm Jones Date: Thu, 28 Jun 2018 15:36:18 -0400 Subject: [PATCH 39/55] Add JSON tags for field names --- org_users.go | 10 +++++----- orgs.go | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/org_users.go b/org_users.go index adb45f75..4fdc301c 100644 --- a/org_users.go +++ b/org_users.go @@ -9,11 +9,11 @@ import ( ) type OrgUser struct { - OrgId int64 - UserId int64 - Email string - Login string - Role string + OrgId int64 `json:"orgId"` + UserId int64 `json:"userId"` + Email string `json:"email"` + Login string `json:"login"` + Role string `json:"role"` } func (c *Client) OrgUsers(id int64) ([]OrgUser, error) { diff --git a/orgs.go b/orgs.go index f00a2ebf..9a4686d6 100644 --- a/orgs.go +++ b/orgs.go @@ -9,8 +9,8 @@ import ( ) type Org struct { - Id int64 - Name string + Id int64 `json:"id"` + Name string `json:"name"` } func (c *Client) Orgs() ([]Org, error) { From 3f9aece85493e3081b7d1c1953cc45b4ca578ede Mon Sep 17 00:00:00 2001 From: Malcolm Jones Date: Thu, 28 Jun 2018 16:10:07 -0400 Subject: [PATCH 40/55] Change variable name for consistency --- org_users.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/org_users.go b/org_users.go index 4fdc301c..801443c5 100644 --- a/org_users.go +++ b/org_users.go @@ -16,9 +16,9 @@ type OrgUser struct { Role string `json:"role"` } -func (c *Client) OrgUsers(id int64) ([]OrgUser, error) { +func (c *Client) OrgUsers(orgId int64) ([]OrgUser, error) { users := make([]OrgUser, 0) - req, err := c.newRequest("GET", fmt.Sprintf("/api/orgs/%d/users", id), nil) + req, err := c.newRequest("GET", fmt.Sprintf("/api/orgs/%d/users", orgId), nil) if err != nil { return users, err } From d43747902b40ec24e0a002cc00b9bffc69bae501 Mon Sep 17 00:00:00 2001 From: Malcolm Jones Date: Fri, 6 Jul 2018 11:48:49 -0400 Subject: [PATCH 41/55] Rework request method --- admin.go | 4 ++-- alertnotification.go | 8 ++++---- client.go | 3 ++- dashboard.go | 6 +++--- datasource.go | 8 ++++---- org_users.go | 8 ++++---- orgs.go | 12 ++++++------ user.go | 4 ++-- 8 files changed, 27 insertions(+), 26 deletions(-) diff --git a/admin.go b/admin.go index 70484e2c..0c59de94 100644 --- a/admin.go +++ b/admin.go @@ -13,7 +13,7 @@ import ( func (c *Client) CreateUserForm(settings dtos.AdminCreateUserForm) (int64, error) { id := int64(0) data, err := json.Marshal(settings) - req, err := c.newRequest("POST", "/api/admin/users", bytes.NewBuffer(data)) + req, err := c.newRequest("POST", "/api/admin/users", "", bytes.NewBuffer(data)) if err != nil { return id, err } @@ -43,7 +43,7 @@ func (c *Client) CreateUser(email, login, name, password string) (int64, error) } func (c *Client) DeleteUser(id int64) error { - req, err := c.newRequest("DELETE", fmt.Sprintf("/api/admin/users/%d", id), nil) + req, err := c.newRequest("DELETE", fmt.Sprintf("/api/admin/users/%d", id), "", nil) if err != nil { return err } diff --git a/alertnotification.go b/alertnotification.go index 39a32b9f..96d79ce4 100644 --- a/alertnotification.go +++ b/alertnotification.go @@ -18,7 +18,7 @@ type AlertNotification struct { func (c *Client) AlertNotification(id int64) (*AlertNotification, error) { path := fmt.Sprintf("/api/alert-notifications/%d", id) - req, err := c.newRequest("GET", path, nil) + req, err := c.newRequest("GET", path, "", nil) if err != nil { return nil, err } @@ -46,7 +46,7 @@ func (c *Client) NewAlertNotification(a *AlertNotification) (int64, error) { if err != nil { return 0, err } - req, err := c.newRequest("POST", "/api/alert-notifications", bytes.NewBuffer(data)) + req, err := c.newRequest("POST", "/api/alert-notifications", "", bytes.NewBuffer(data)) if err != nil { return 0, err } @@ -77,7 +77,7 @@ func (c *Client) UpdateAlertNotification(a *AlertNotification) error { if err != nil { return err } - req, err := c.newRequest("PUT", path, bytes.NewBuffer(data)) + req, err := c.newRequest("PUT", path, "", bytes.NewBuffer(data)) if err != nil { return err } @@ -95,7 +95,7 @@ func (c *Client) UpdateAlertNotification(a *AlertNotification) error { func (c *Client) DeleteAlertNotification(id int64) error { path := fmt.Sprintf("/api/alert-notifications/%d", id) - req, err := c.newRequest("DELETE", path, nil) + req, err := c.newRequest("DELETE", path, "", nil) if err != nil { return err } diff --git a/client.go b/client.go index de5fc3c1..be483828 100644 --- a/client.go +++ b/client.go @@ -39,9 +39,10 @@ func New(auth, baseURL string) (*Client, error) { }, nil } -func (c *Client) newRequest(method, requestPath string, body io.Reader) (*http.Request, error) { +func (c *Client) newRequest(method, requestPath, query string, body io.Reader) (*http.Request, error) { url := c.baseURL url.Path = path.Join(url.Path, requestPath) + url.RawQuery = query req, err := http.NewRequest(method, url.String(), body) if err != nil { return req, err diff --git a/dashboard.go b/dashboard.go index ca45dc9a..65deab4f 100644 --- a/dashboard.go +++ b/dashboard.go @@ -33,7 +33,7 @@ func (c *Client) SaveDashboard(model map[string]interface{}, overwrite bool) (*D if err != nil { return nil, err } - req, err := c.newRequest("POST", "/api/dashboards/db", bytes.NewBuffer(data)) + req, err := c.newRequest("POST", "/api/dashboards/db", "", bytes.NewBuffer(data)) if err != nil { return nil, err } @@ -58,7 +58,7 @@ func (c *Client) SaveDashboard(model map[string]interface{}, overwrite bool) (*D func (c *Client) Dashboard(slug string) (*Dashboard, error) { path := fmt.Sprintf("/api/dashboards/db/%s", slug) - req, err := c.newRequest("GET", path, nil) + req, err := c.newRequest("GET", path, "", nil) if err != nil { return nil, err } @@ -83,7 +83,7 @@ func (c *Client) Dashboard(slug string) (*Dashboard, error) { func (c *Client) DeleteDashboard(slug string) error { path := fmt.Sprintf("/api/dashboards/db/%s", slug) - req, err := c.newRequest("DELETE", path, nil) + req, err := c.newRequest("DELETE", path, "", nil) if err != nil { return err } diff --git a/datasource.go b/datasource.go index ab42b88e..612ec6ad 100644 --- a/datasource.go +++ b/datasource.go @@ -49,7 +49,7 @@ func (c *Client) NewDataSource(s *DataSource) (int64, error) { if err != nil { return 0, err } - req, err := c.newRequest("POST", "/api/datasources", bytes.NewBuffer(data)) + req, err := c.newRequest("POST", "/api/datasources", "", bytes.NewBuffer(data)) if err != nil { return 0, err } @@ -80,7 +80,7 @@ func (c *Client) UpdateDataSource(s *DataSource) error { if err != nil { return err } - req, err := c.newRequest("PUT", path, bytes.NewBuffer(data)) + req, err := c.newRequest("PUT", path, "", bytes.NewBuffer(data)) if err != nil { return err } @@ -98,7 +98,7 @@ func (c *Client) UpdateDataSource(s *DataSource) error { func (c *Client) DataSource(id int64) (*DataSource, error) { path := fmt.Sprintf("/api/datasources/%d", id) - req, err := c.newRequest("GET", path, nil) + req, err := c.newRequest("GET", path, "", nil) if err != nil { return nil, err } @@ -123,7 +123,7 @@ func (c *Client) DataSource(id int64) (*DataSource, error) { func (c *Client) DeleteDataSource(id int64) error { path := fmt.Sprintf("/api/datasources/%d", id) - req, err := c.newRequest("DELETE", path, nil) + req, err := c.newRequest("DELETE", path, "", nil) if err != nil { return err } diff --git a/org_users.go b/org_users.go index 801443c5..ad63ccfa 100644 --- a/org_users.go +++ b/org_users.go @@ -18,7 +18,7 @@ type OrgUser struct { func (c *Client) OrgUsers(orgId int64) ([]OrgUser, error) { users := make([]OrgUser, 0) - req, err := c.newRequest("GET", fmt.Sprintf("/api/orgs/%d/users", orgId), nil) + req, err := c.newRequest("GET", fmt.Sprintf("/api/orgs/%d/users", orgId), "", nil) if err != nil { return users, err } @@ -46,7 +46,7 @@ func (c *Client) AddOrgUser(orgId int64, user, role string) error { "role": role, } data, err := json.Marshal(dataMap) - req, err := c.newRequest("POST", fmt.Sprintf("/api/orgs/%d/users", orgId), bytes.NewBuffer(data)) + req, err := c.newRequest("POST", fmt.Sprintf("/api/orgs/%d/users", orgId), "", bytes.NewBuffer(data)) if err != nil { return err } @@ -65,7 +65,7 @@ func (c *Client) UpdateOrgUser(orgId, userId int64, role string) error { "role": role, } data, err := json.Marshal(dataMap) - req, err := c.newRequest("PATCH", fmt.Sprintf("/api/orgs/%d/users/%d", orgId, userId), bytes.NewBuffer(data)) + req, err := c.newRequest("PATCH", fmt.Sprintf("/api/orgs/%d/users/%d", orgId, userId), "", bytes.NewBuffer(data)) if err != nil { return err } @@ -80,7 +80,7 @@ func (c *Client) UpdateOrgUser(orgId, userId int64, role string) error { } func (c *Client) RemoveOrgUser(orgId, userId int64) error { - req, err := c.newRequest("DELETE", fmt.Sprintf("/api/orgs/%d/users/%d", orgId, userId), nil) + req, err := c.newRequest("DELETE", fmt.Sprintf("/api/orgs/%d/users/%d", orgId, userId), "", nil) if err != nil { return err } diff --git a/orgs.go b/orgs.go index 9a4686d6..69673a7d 100644 --- a/orgs.go +++ b/orgs.go @@ -16,7 +16,7 @@ type Org struct { func (c *Client) Orgs() ([]Org, error) { orgs := make([]Org, 0) - req, err := c.newRequest("GET", "/api/orgs/", nil) + req, err := c.newRequest("GET", "/api/orgs/", "", nil) if err != nil { return orgs, err } @@ -37,7 +37,7 @@ func (c *Client) Orgs() ([]Org, error) { func (c *Client) OrgByName(name string) (Org, error) { org := Org{} - req, err := c.newRequest("GET", fmt.Sprintf("/api/orgs/name/%s", name), nil) + req, err := c.newRequest("GET", fmt.Sprintf("/api/orgs/name/%s", name), "", nil) if err != nil { return org, err } @@ -58,7 +58,7 @@ func (c *Client) OrgByName(name string) (Org, error) { func (c *Client) Org(id int64) (Org, error) { org := Org{} - req, err := c.newRequest("GET", fmt.Sprintf("/api/orgs/%d", id), nil) + req, err := c.newRequest("GET", fmt.Sprintf("/api/orgs/%d", id), "", nil) if err != nil { return org, err } @@ -83,7 +83,7 @@ func (c *Client) NewOrg(name string) (int64, error) { } data, err := json.Marshal(dataMap) id := int64(0) - req, err := c.newRequest("POST", "/api/orgs", bytes.NewBuffer(data)) + req, err := c.newRequest("POST", "/api/orgs", "", bytes.NewBuffer(data)) if err != nil { return id, err } @@ -114,7 +114,7 @@ func (c *Client) UpdateOrg(id int64, name string) error { "name": name, } data, err := json.Marshal(dataMap) - req, err := c.newRequest("PUT", fmt.Sprintf("/api/orgs/%d", id), bytes.NewBuffer(data)) + req, err := c.newRequest("PUT", fmt.Sprintf("/api/orgs/%d", id), "", bytes.NewBuffer(data)) if err != nil { return err } @@ -129,7 +129,7 @@ func (c *Client) UpdateOrg(id int64, name string) error { } func (c *Client) DeleteOrg(id int64) error { - req, err := c.newRequest("DELETE", fmt.Sprintf("/api/orgs/%d", id), nil) + req, err := c.newRequest("DELETE", fmt.Sprintf("/api/orgs/%d", id), "", nil) if err != nil { return err } diff --git a/user.go b/user.go index ef012c26..fd57a47d 100644 --- a/user.go +++ b/user.go @@ -17,7 +17,7 @@ type User struct { func (c *Client) Users() ([]User, error) { users := make([]User, 0) - req, err := c.newRequest("GET", "/api/users", nil) + req, err := c.newRequest("GET", "/api/users", "", nil) if err != nil { return users, err } @@ -41,7 +41,7 @@ func (c *Client) Users() ([]User, error) { func (c *Client) UserByEmail(email string) (User, error) { user := User{} - req, err := c.newQueryRequest("GET", "/api/users/lookup", fmt.Sprintf("loginOrEmail=%s", email)) + req, err := c.newRequest("GET", "/api/users/lookup", fmt.Sprintf("loginOrEmail=%s", email), nil) if err != nil { return user, err } From 2f8875a387122c8b6c5a5ea255033d58b4ac3ab3 Mon Sep 17 00:00:00 2001 From: Malcolm Jones Date: Mon, 9 Jul 2018 12:02:50 -0400 Subject: [PATCH 42/55] Better request parameter handling --- admin.go | 4 ++-- alertnotification.go | 8 ++++---- client.go | 33 ++++++--------------------------- dashboard.go | 6 +++--- datasource.go | 8 ++++---- org_users.go | 8 ++++---- orgs.go | 12 ++++++------ user.go | 27 +++++++++++++++------------ 8 files changed, 44 insertions(+), 62 deletions(-) diff --git a/admin.go b/admin.go index 0c59de94..70484e2c 100644 --- a/admin.go +++ b/admin.go @@ -13,7 +13,7 @@ import ( func (c *Client) CreateUserForm(settings dtos.AdminCreateUserForm) (int64, error) { id := int64(0) data, err := json.Marshal(settings) - req, err := c.newRequest("POST", "/api/admin/users", "", bytes.NewBuffer(data)) + req, err := c.newRequest("POST", "/api/admin/users", bytes.NewBuffer(data)) if err != nil { return id, err } @@ -43,7 +43,7 @@ func (c *Client) CreateUser(email, login, name, password string) (int64, error) } func (c *Client) DeleteUser(id int64) error { - req, err := c.newRequest("DELETE", fmt.Sprintf("/api/admin/users/%d", id), "", nil) + req, err := c.newRequest("DELETE", fmt.Sprintf("/api/admin/users/%d", id), nil) if err != nil { return err } diff --git a/alertnotification.go b/alertnotification.go index 96d79ce4..39a32b9f 100644 --- a/alertnotification.go +++ b/alertnotification.go @@ -18,7 +18,7 @@ type AlertNotification struct { func (c *Client) AlertNotification(id int64) (*AlertNotification, error) { path := fmt.Sprintf("/api/alert-notifications/%d", id) - req, err := c.newRequest("GET", path, "", nil) + req, err := c.newRequest("GET", path, nil) if err != nil { return nil, err } @@ -46,7 +46,7 @@ func (c *Client) NewAlertNotification(a *AlertNotification) (int64, error) { if err != nil { return 0, err } - req, err := c.newRequest("POST", "/api/alert-notifications", "", bytes.NewBuffer(data)) + req, err := c.newRequest("POST", "/api/alert-notifications", bytes.NewBuffer(data)) if err != nil { return 0, err } @@ -77,7 +77,7 @@ func (c *Client) UpdateAlertNotification(a *AlertNotification) error { if err != nil { return err } - req, err := c.newRequest("PUT", path, "", bytes.NewBuffer(data)) + req, err := c.newRequest("PUT", path, bytes.NewBuffer(data)) if err != nil { return err } @@ -95,7 +95,7 @@ func (c *Client) UpdateAlertNotification(a *AlertNotification) error { func (c *Client) DeleteAlertNotification(id int64) error { path := fmt.Sprintf("/api/alert-notifications/%d", id) - req, err := c.newRequest("DELETE", path, "", nil) + req, err := c.newRequest("DELETE", path, nil) if err != nil { return err } diff --git a/client.go b/client.go index be483828..e6c40ac5 100644 --- a/client.go +++ b/client.go @@ -39,10 +39,13 @@ func New(auth, baseURL string) (*Client, error) { }, nil } -func (c *Client) newRequest(method, requestPath, query string, body io.Reader) (*http.Request, error) { +func (c *Client) newRequest(method, requestPath string, body io.Reader) (*http.Request, error) { url := c.baseURL - url.Path = path.Join(url.Path, requestPath) - url.RawQuery = query + sPath := strings.Split(requestPath, "?") + url.Path = path.Join(url.Path, sPath[0]) + if len(sPath) > 1 { + url.RawQuery = sPath[1] + } req, err := http.NewRequest(method, url.String(), body) if err != nil { return req, err @@ -62,27 +65,3 @@ func (c *Client) newRequest(method, requestPath, query string, body io.Reader) ( req.Header.Add("Content-Type", "application/json") return req, err } - -func (c *Client) newQueryRequest(method, requestPath string, query string) (*http.Request, error) { - url := c.baseURL - url.Path = path.Join(url.Path, requestPath) - url.RawQuery = query - req, err := http.NewRequest(method, url.String(), nil) - if err != nil { - return req, err - } - if c.key != "" { - req.Header.Add("Authorization", c.key) - } - - if os.Getenv("GF_LOG") != "" { - if query == "" { - log.Println("request to ", url.String(), "with no query data") - } else { - log.Println("request to ", url.String(), "with query data", query) - } - } - - req.Header.Add("Content-Type", "application/json") - return req, err -} diff --git a/dashboard.go b/dashboard.go index 65deab4f..ca45dc9a 100644 --- a/dashboard.go +++ b/dashboard.go @@ -33,7 +33,7 @@ func (c *Client) SaveDashboard(model map[string]interface{}, overwrite bool) (*D if err != nil { return nil, err } - req, err := c.newRequest("POST", "/api/dashboards/db", "", bytes.NewBuffer(data)) + req, err := c.newRequest("POST", "/api/dashboards/db", bytes.NewBuffer(data)) if err != nil { return nil, err } @@ -58,7 +58,7 @@ func (c *Client) SaveDashboard(model map[string]interface{}, overwrite bool) (*D func (c *Client) Dashboard(slug string) (*Dashboard, error) { path := fmt.Sprintf("/api/dashboards/db/%s", slug) - req, err := c.newRequest("GET", path, "", nil) + req, err := c.newRequest("GET", path, nil) if err != nil { return nil, err } @@ -83,7 +83,7 @@ func (c *Client) Dashboard(slug string) (*Dashboard, error) { func (c *Client) DeleteDashboard(slug string) error { path := fmt.Sprintf("/api/dashboards/db/%s", slug) - req, err := c.newRequest("DELETE", path, "", nil) + req, err := c.newRequest("DELETE", path, nil) if err != nil { return err } diff --git a/datasource.go b/datasource.go index 612ec6ad..ab42b88e 100644 --- a/datasource.go +++ b/datasource.go @@ -49,7 +49,7 @@ func (c *Client) NewDataSource(s *DataSource) (int64, error) { if err != nil { return 0, err } - req, err := c.newRequest("POST", "/api/datasources", "", bytes.NewBuffer(data)) + req, err := c.newRequest("POST", "/api/datasources", bytes.NewBuffer(data)) if err != nil { return 0, err } @@ -80,7 +80,7 @@ func (c *Client) UpdateDataSource(s *DataSource) error { if err != nil { return err } - req, err := c.newRequest("PUT", path, "", bytes.NewBuffer(data)) + req, err := c.newRequest("PUT", path, bytes.NewBuffer(data)) if err != nil { return err } @@ -98,7 +98,7 @@ func (c *Client) UpdateDataSource(s *DataSource) error { func (c *Client) DataSource(id int64) (*DataSource, error) { path := fmt.Sprintf("/api/datasources/%d", id) - req, err := c.newRequest("GET", path, "", nil) + req, err := c.newRequest("GET", path, nil) if err != nil { return nil, err } @@ -123,7 +123,7 @@ func (c *Client) DataSource(id int64) (*DataSource, error) { func (c *Client) DeleteDataSource(id int64) error { path := fmt.Sprintf("/api/datasources/%d", id) - req, err := c.newRequest("DELETE", path, "", nil) + req, err := c.newRequest("DELETE", path, nil) if err != nil { return err } diff --git a/org_users.go b/org_users.go index ad63ccfa..801443c5 100644 --- a/org_users.go +++ b/org_users.go @@ -18,7 +18,7 @@ type OrgUser struct { func (c *Client) OrgUsers(orgId int64) ([]OrgUser, error) { users := make([]OrgUser, 0) - req, err := c.newRequest("GET", fmt.Sprintf("/api/orgs/%d/users", orgId), "", nil) + req, err := c.newRequest("GET", fmt.Sprintf("/api/orgs/%d/users", orgId), nil) if err != nil { return users, err } @@ -46,7 +46,7 @@ func (c *Client) AddOrgUser(orgId int64, user, role string) error { "role": role, } data, err := json.Marshal(dataMap) - req, err := c.newRequest("POST", fmt.Sprintf("/api/orgs/%d/users", orgId), "", bytes.NewBuffer(data)) + req, err := c.newRequest("POST", fmt.Sprintf("/api/orgs/%d/users", orgId), bytes.NewBuffer(data)) if err != nil { return err } @@ -65,7 +65,7 @@ func (c *Client) UpdateOrgUser(orgId, userId int64, role string) error { "role": role, } data, err := json.Marshal(dataMap) - req, err := c.newRequest("PATCH", fmt.Sprintf("/api/orgs/%d/users/%d", orgId, userId), "", bytes.NewBuffer(data)) + req, err := c.newRequest("PATCH", fmt.Sprintf("/api/orgs/%d/users/%d", orgId, userId), bytes.NewBuffer(data)) if err != nil { return err } @@ -80,7 +80,7 @@ func (c *Client) UpdateOrgUser(orgId, userId int64, role string) error { } func (c *Client) RemoveOrgUser(orgId, userId int64) error { - req, err := c.newRequest("DELETE", fmt.Sprintf("/api/orgs/%d/users/%d", orgId, userId), "", nil) + req, err := c.newRequest("DELETE", fmt.Sprintf("/api/orgs/%d/users/%d", orgId, userId), nil) if err != nil { return err } diff --git a/orgs.go b/orgs.go index 69673a7d..9a4686d6 100644 --- a/orgs.go +++ b/orgs.go @@ -16,7 +16,7 @@ type Org struct { func (c *Client) Orgs() ([]Org, error) { orgs := make([]Org, 0) - req, err := c.newRequest("GET", "/api/orgs/", "", nil) + req, err := c.newRequest("GET", "/api/orgs/", nil) if err != nil { return orgs, err } @@ -37,7 +37,7 @@ func (c *Client) Orgs() ([]Org, error) { func (c *Client) OrgByName(name string) (Org, error) { org := Org{} - req, err := c.newRequest("GET", fmt.Sprintf("/api/orgs/name/%s", name), "", nil) + req, err := c.newRequest("GET", fmt.Sprintf("/api/orgs/name/%s", name), nil) if err != nil { return org, err } @@ -58,7 +58,7 @@ func (c *Client) OrgByName(name string) (Org, error) { func (c *Client) Org(id int64) (Org, error) { org := Org{} - req, err := c.newRequest("GET", fmt.Sprintf("/api/orgs/%d", id), "", nil) + req, err := c.newRequest("GET", fmt.Sprintf("/api/orgs/%d", id), nil) if err != nil { return org, err } @@ -83,7 +83,7 @@ func (c *Client) NewOrg(name string) (int64, error) { } data, err := json.Marshal(dataMap) id := int64(0) - req, err := c.newRequest("POST", "/api/orgs", "", bytes.NewBuffer(data)) + req, err := c.newRequest("POST", "/api/orgs", bytes.NewBuffer(data)) if err != nil { return id, err } @@ -114,7 +114,7 @@ func (c *Client) UpdateOrg(id int64, name string) error { "name": name, } data, err := json.Marshal(dataMap) - req, err := c.newRequest("PUT", fmt.Sprintf("/api/orgs/%d", id), "", bytes.NewBuffer(data)) + req, err := c.newRequest("PUT", fmt.Sprintf("/api/orgs/%d", id), bytes.NewBuffer(data)) if err != nil { return err } @@ -129,7 +129,7 @@ func (c *Client) UpdateOrg(id int64, name string) error { } func (c *Client) DeleteOrg(id int64) error { - req, err := c.newRequest("DELETE", fmt.Sprintf("/api/orgs/%d", id), "", nil) + req, err := c.newRequest("DELETE", fmt.Sprintf("/api/orgs/%d", id), nil) if err != nil { return err } diff --git a/user.go b/user.go index fd57a47d..2034e02a 100644 --- a/user.go +++ b/user.go @@ -8,16 +8,17 @@ import ( ) type User struct { - Id int64 `json:"id"` - Email string `json:"email"` - Name string `json:"name"` - Login string `json:"login"` - IsAdmin bool `json:"isAdmin"` + Id int64 `json:"id,omitempty"` + Email string `json:"email,omitempty"` + Name string `json:"name,omitempty"` + Login string `json:"login,omitempty"` + Password string `json:"password,omitempty"` + IsAdmin bool `json:"isAdmin,omitempty"` } func (c *Client) Users() ([]User, error) { users := make([]User, 0) - req, err := c.newRequest("GET", "/api/users", "", nil) + req, err := c.newRequest("GET", "/api/users", nil) if err != nil { return users, err } @@ -41,7 +42,8 @@ func (c *Client) Users() ([]User, error) { func (c *Client) UserByEmail(email string) (User, error) { user := User{} - req, err := c.newRequest("GET", "/api/users/lookup", fmt.Sprintf("loginOrEmail=%s", email), nil) + req, err := c.newRequest("GET", fmt.Sprintf("/api/users/lookup?loginOrEmail=%s", email), nil) + return User{}, errors.New(req.URL.String()) if err != nil { return user, err } @@ -57,11 +59,12 @@ func (c *Client) UserByEmail(email string) (User, error) { return user, err } tmp := struct { - Id int64 `json:"id"` - Email string `json:"email"` - Name string `json:"name"` - Login string `json:"login"` - IsAdmin bool `json:"isGrafanaAdmin"` + Id int64 `json:"id,omitempty"` + Email string `json:"email,omitempty"` + Name string `json:"name,omitempty"` + Login string `json:"login,omitempty"` + Password string `json:"password,omitempty"` + IsAdmin bool `json:"isGrafanaAdmin,omitempty"` }{} err = json.Unmarshal(data, &tmp) if err != nil { From a7599ef75f8eb200d2468bcddfd740ec74c90016 Mon Sep 17 00:00:00 2001 From: Malcolm Jones Date: Mon, 9 Jul 2018 12:06:25 -0400 Subject: [PATCH 43/55] Formatting fix --- admin_test.go | 13 ++++++------- user_test.go | 2 +- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/admin_test.go b/admin_test.go index 04065d14..24b8c48c 100644 --- a/admin_test.go +++ b/admin_test.go @@ -2,22 +2,21 @@ package gapi import ( "testing" - "github.com/grafana/grafana/pkg/api/dtos" + "github.com/grafana/grafana/pkg/api/dtos" ) const ( - createUserJSON = `{"id":1,"message":"User created"}` + createUserJSON = `{"id":1,"message":"User created"}` deleteUserJSON = `{"message":"User deleted"}` ) func TestCreateUserForm(t *testing.T) { server, client := gapiTestTools(200, createUserJSON) defer server.Close() - - user := dtos.AdminCreateUserForm{ + user := dtos.AdminCreateUserForm{ Email: "admin@localhost", Login: "admin", - Name: "Administrator", + Name: "Administrator", Password: "password", } resp, err := client.CreateUserForm(user) @@ -34,10 +33,10 @@ func TestCreateUser(t *testing.T) { server, client := gapiTestTools(200, createUserJSON) defer server.Close() - user := dtos.AdminCreateUserForm{ + user := dtos.AdminCreateUserForm{ Email: "admin@localhost", Login: "admin", - Name: "Administrator", + Name: "Administrator", Password: "password", } resp, err := client.CreateUser(user.Email, user.Login, user.Email, user.Password) diff --git a/user_test.go b/user_test.go index fa4a23b2..49814b1b 100644 --- a/user_test.go +++ b/user_test.go @@ -42,7 +42,7 @@ func TestUserByEmail(t *testing.T) { if err != nil { t.Error(err) } - + t.Log(pretty.PrettyFormat(resp)) user := User{ From 9ac7c4a023aab2923246015d48ccd37a2aa6fc92 Mon Sep 17 00:00:00 2001 From: Malcolm Jones Date: Tue, 10 Jul 2018 10:54:48 -0400 Subject: [PATCH 44/55] Updated method for handling query parameters --- admin.go | 4 ++-- alertnotification.go | 8 ++++---- client.go | 9 +++------ dashboard.go | 6 +++--- datasource.go | 8 ++++---- org_users.go | 8 ++++---- orgs.go | 12 ++++++------ user.go | 9 +++++---- user_test.go | 4 ++-- 9 files changed, 33 insertions(+), 35 deletions(-) diff --git a/admin.go b/admin.go index 70484e2c..4d99a622 100644 --- a/admin.go +++ b/admin.go @@ -13,7 +13,7 @@ import ( func (c *Client) CreateUserForm(settings dtos.AdminCreateUserForm) (int64, error) { id := int64(0) data, err := json.Marshal(settings) - req, err := c.newRequest("POST", "/api/admin/users", bytes.NewBuffer(data)) + req, err := c.newRequest("POST", "/api/admin/users", nil, bytes.NewBuffer(data)) if err != nil { return id, err } @@ -43,7 +43,7 @@ func (c *Client) CreateUser(email, login, name, password string) (int64, error) } func (c *Client) DeleteUser(id int64) error { - req, err := c.newRequest("DELETE", fmt.Sprintf("/api/admin/users/%d", id), nil) + req, err := c.newRequest("DELETE", fmt.Sprintf("/api/admin/users/%d", id), nil, nil) if err != nil { return err } diff --git a/alertnotification.go b/alertnotification.go index 39a32b9f..6c8cdc69 100644 --- a/alertnotification.go +++ b/alertnotification.go @@ -18,7 +18,7 @@ type AlertNotification struct { func (c *Client) AlertNotification(id int64) (*AlertNotification, error) { path := fmt.Sprintf("/api/alert-notifications/%d", id) - req, err := c.newRequest("GET", path, nil) + req, err := c.newRequest("GET", path, nil, nil) if err != nil { return nil, err } @@ -46,7 +46,7 @@ func (c *Client) NewAlertNotification(a *AlertNotification) (int64, error) { if err != nil { return 0, err } - req, err := c.newRequest("POST", "/api/alert-notifications", bytes.NewBuffer(data)) + req, err := c.newRequest("POST", "/api/alert-notifications", nil, bytes.NewBuffer(data)) if err != nil { return 0, err } @@ -77,7 +77,7 @@ func (c *Client) UpdateAlertNotification(a *AlertNotification) error { if err != nil { return err } - req, err := c.newRequest("PUT", path, bytes.NewBuffer(data)) + req, err := c.newRequest("PUT", path, nil, bytes.NewBuffer(data)) if err != nil { return err } @@ -95,7 +95,7 @@ func (c *Client) UpdateAlertNotification(a *AlertNotification) error { func (c *Client) DeleteAlertNotification(id int64) error { path := fmt.Sprintf("/api/alert-notifications/%d", id) - req, err := c.newRequest("DELETE", path, nil) + req, err := c.newRequest("DELETE", path, nil, nil) if err != nil { return err } diff --git a/client.go b/client.go index e6c40ac5..1ab6884d 100644 --- a/client.go +++ b/client.go @@ -39,13 +39,10 @@ func New(auth, baseURL string) (*Client, error) { }, nil } -func (c *Client) newRequest(method, requestPath string, body io.Reader) (*http.Request, error) { +func (c *Client) newRequest(method, requestPath string, query url.Values, body io.Reader) (*http.Request, error) { url := c.baseURL - sPath := strings.Split(requestPath, "?") - url.Path = path.Join(url.Path, sPath[0]) - if len(sPath) > 1 { - url.RawQuery = sPath[1] - } + url.Path = path.Join(url.Path, requestPath) + url.RawQuery = query.Encode() req, err := http.NewRequest(method, url.String(), body) if err != nil { return req, err diff --git a/dashboard.go b/dashboard.go index ca45dc9a..8e4d6c47 100644 --- a/dashboard.go +++ b/dashboard.go @@ -33,7 +33,7 @@ func (c *Client) SaveDashboard(model map[string]interface{}, overwrite bool) (*D if err != nil { return nil, err } - req, err := c.newRequest("POST", "/api/dashboards/db", bytes.NewBuffer(data)) + req, err := c.newRequest("POST", "/api/dashboards/db", nil, bytes.NewBuffer(data)) if err != nil { return nil, err } @@ -58,7 +58,7 @@ func (c *Client) SaveDashboard(model map[string]interface{}, overwrite bool) (*D func (c *Client) Dashboard(slug string) (*Dashboard, error) { path := fmt.Sprintf("/api/dashboards/db/%s", slug) - req, err := c.newRequest("GET", path, nil) + req, err := c.newRequest("GET", path, nil, nil) if err != nil { return nil, err } @@ -83,7 +83,7 @@ func (c *Client) Dashboard(slug string) (*Dashboard, error) { func (c *Client) DeleteDashboard(slug string) error { path := fmt.Sprintf("/api/dashboards/db/%s", slug) - req, err := c.newRequest("DELETE", path, nil) + req, err := c.newRequest("DELETE", path, nil, nil) if err != nil { return err } diff --git a/datasource.go b/datasource.go index ab42b88e..5e2d014f 100644 --- a/datasource.go +++ b/datasource.go @@ -49,7 +49,7 @@ func (c *Client) NewDataSource(s *DataSource) (int64, error) { if err != nil { return 0, err } - req, err := c.newRequest("POST", "/api/datasources", bytes.NewBuffer(data)) + req, err := c.newRequest("POST", "/api/datasources", nil, bytes.NewBuffer(data)) if err != nil { return 0, err } @@ -80,7 +80,7 @@ func (c *Client) UpdateDataSource(s *DataSource) error { if err != nil { return err } - req, err := c.newRequest("PUT", path, bytes.NewBuffer(data)) + req, err := c.newRequest("PUT", path, nil, bytes.NewBuffer(data)) if err != nil { return err } @@ -98,7 +98,7 @@ func (c *Client) UpdateDataSource(s *DataSource) error { func (c *Client) DataSource(id int64) (*DataSource, error) { path := fmt.Sprintf("/api/datasources/%d", id) - req, err := c.newRequest("GET", path, nil) + req, err := c.newRequest("GET", path, nil, nil) if err != nil { return nil, err } @@ -123,7 +123,7 @@ func (c *Client) DataSource(id int64) (*DataSource, error) { func (c *Client) DeleteDataSource(id int64) error { path := fmt.Sprintf("/api/datasources/%d", id) - req, err := c.newRequest("DELETE", path, nil) + req, err := c.newRequest("DELETE", path, nil, nil) if err != nil { return err } diff --git a/org_users.go b/org_users.go index 801443c5..9921dfd2 100644 --- a/org_users.go +++ b/org_users.go @@ -18,7 +18,7 @@ type OrgUser struct { func (c *Client) OrgUsers(orgId int64) ([]OrgUser, error) { users := make([]OrgUser, 0) - req, err := c.newRequest("GET", fmt.Sprintf("/api/orgs/%d/users", orgId), nil) + req, err := c.newRequest("GET", fmt.Sprintf("/api/orgs/%d/users", orgId), nil, nil) if err != nil { return users, err } @@ -46,7 +46,7 @@ func (c *Client) AddOrgUser(orgId int64, user, role string) error { "role": role, } data, err := json.Marshal(dataMap) - req, err := c.newRequest("POST", fmt.Sprintf("/api/orgs/%d/users", orgId), bytes.NewBuffer(data)) + req, err := c.newRequest("POST", fmt.Sprintf("/api/orgs/%d/users", orgId), nil, bytes.NewBuffer(data)) if err != nil { return err } @@ -65,7 +65,7 @@ func (c *Client) UpdateOrgUser(orgId, userId int64, role string) error { "role": role, } data, err := json.Marshal(dataMap) - req, err := c.newRequest("PATCH", fmt.Sprintf("/api/orgs/%d/users/%d", orgId, userId), bytes.NewBuffer(data)) + req, err := c.newRequest("PATCH", fmt.Sprintf("/api/orgs/%d/users/%d", orgId, userId), nil, bytes.NewBuffer(data)) if err != nil { return err } @@ -80,7 +80,7 @@ func (c *Client) UpdateOrgUser(orgId, userId int64, role string) error { } func (c *Client) RemoveOrgUser(orgId, userId int64) error { - req, err := c.newRequest("DELETE", fmt.Sprintf("/api/orgs/%d/users/%d", orgId, userId), nil) + req, err := c.newRequest("DELETE", fmt.Sprintf("/api/orgs/%d/users/%d", orgId, userId), nil, nil) if err != nil { return err } diff --git a/orgs.go b/orgs.go index 9a4686d6..e4d47316 100644 --- a/orgs.go +++ b/orgs.go @@ -16,7 +16,7 @@ type Org struct { func (c *Client) Orgs() ([]Org, error) { orgs := make([]Org, 0) - req, err := c.newRequest("GET", "/api/orgs/", nil) + req, err := c.newRequest("GET", "/api/orgs/", nil, nil) if err != nil { return orgs, err } @@ -37,7 +37,7 @@ func (c *Client) Orgs() ([]Org, error) { func (c *Client) OrgByName(name string) (Org, error) { org := Org{} - req, err := c.newRequest("GET", fmt.Sprintf("/api/orgs/name/%s", name), nil) + req, err := c.newRequest("GET", fmt.Sprintf("/api/orgs/name/%s", name), nil, nil) if err != nil { return org, err } @@ -58,7 +58,7 @@ func (c *Client) OrgByName(name string) (Org, error) { func (c *Client) Org(id int64) (Org, error) { org := Org{} - req, err := c.newRequest("GET", fmt.Sprintf("/api/orgs/%d", id), nil) + req, err := c.newRequest("GET", fmt.Sprintf("/api/orgs/%d", id), nil, nil) if err != nil { return org, err } @@ -83,7 +83,7 @@ func (c *Client) NewOrg(name string) (int64, error) { } data, err := json.Marshal(dataMap) id := int64(0) - req, err := c.newRequest("POST", "/api/orgs", bytes.NewBuffer(data)) + req, err := c.newRequest("POST", "/api/orgs", nil, bytes.NewBuffer(data)) if err != nil { return id, err } @@ -114,7 +114,7 @@ func (c *Client) UpdateOrg(id int64, name string) error { "name": name, } data, err := json.Marshal(dataMap) - req, err := c.newRequest("PUT", fmt.Sprintf("/api/orgs/%d", id), bytes.NewBuffer(data)) + req, err := c.newRequest("PUT", fmt.Sprintf("/api/orgs/%d", id), nil, bytes.NewBuffer(data)) if err != nil { return err } @@ -129,7 +129,7 @@ func (c *Client) UpdateOrg(id int64, name string) error { } func (c *Client) DeleteOrg(id int64) error { - req, err := c.newRequest("DELETE", fmt.Sprintf("/api/orgs/%d", id), nil) + req, err := c.newRequest("DELETE", fmt.Sprintf("/api/orgs/%d", id), nil, nil) if err != nil { return err } diff --git a/user.go b/user.go index 2034e02a..17c879ae 100644 --- a/user.go +++ b/user.go @@ -3,8 +3,8 @@ package gapi import ( "encoding/json" "errors" - "fmt" "io/ioutil" + "net/url" ) type User struct { @@ -18,7 +18,7 @@ type User struct { func (c *Client) Users() ([]User, error) { users := make([]User, 0) - req, err := c.newRequest("GET", "/api/users", nil) + req, err := c.newRequest("GET", "/api/users", nil, nil) if err != nil { return users, err } @@ -42,8 +42,9 @@ func (c *Client) Users() ([]User, error) { func (c *Client) UserByEmail(email string) (User, error) { user := User{} - req, err := c.newRequest("GET", fmt.Sprintf("/api/users/lookup?loginOrEmail=%s", email), nil) - return User{}, errors.New(req.URL.String()) + query := url.Values{} + query.Add("loginOrEmail", email) + req, err := c.newRequest("GET", "/api/users/lookup", query, nil) if err != nil { return user, err } diff --git a/user_test.go b/user_test.go index 49814b1b..0ee1d88c 100644 --- a/user_test.go +++ b/user_test.go @@ -42,13 +42,13 @@ func TestUserByEmail(t *testing.T) { if err != nil { t.Error(err) } - + t.Log(pretty.PrettyFormat(resp)) user := User{ Id: 1, Email: "admin@localhost", - Name: "", + Name: "", Login: "admin", IsAdmin: true, } From d1dd660ebbc65be73403ffcf7b57389ef35d661b Mon Sep 17 00:00:00 2001 From: Malcolm Jones Date: Tue, 10 Jul 2018 11:09:07 -0400 Subject: [PATCH 45/55] Remove dtos data struct --- admin.go | 16 +++++----------- admin_test.go | 25 ++----------------------- 2 files changed, 7 insertions(+), 34 deletions(-) diff --git a/admin.go b/admin.go index 4d99a622..1caf0c3c 100644 --- a/admin.go +++ b/admin.go @@ -6,13 +6,11 @@ import ( "errors" "fmt" "io/ioutil" - - "github.com/grafana/grafana/pkg/api/dtos" ) -func (c *Client) CreateUserForm(settings dtos.AdminCreateUserForm) (int64, error) { +func (c *Client) CreateUser(user User) (int64, error) { id := int64(0) - data, err := json.Marshal(settings) + data, err := json.Marshal(user) req, err := c.newRequest("POST", "/api/admin/users", nil, bytes.NewBuffer(data)) if err != nil { return id, err @@ -28,18 +26,14 @@ func (c *Client) CreateUserForm(settings dtos.AdminCreateUserForm) (int64, error if err != nil { return id, err } - user := struct { + created := struct { Id int64 `json:"id"` }{} - err = json.Unmarshal(data, &user) + err = json.Unmarshal(data, &created) if err != nil { return id, err } - return user.Id, err -} - -func (c *Client) CreateUser(email, login, name, password string) (int64, error) { - return c.CreateUserForm(dtos.AdminCreateUserForm{email, login, name, password}) + return created.Id, err } func (c *Client) DeleteUser(id int64) error { diff --git a/admin_test.go b/admin_test.go index 24b8c48c..2dec7262 100644 --- a/admin_test.go +++ b/admin_test.go @@ -2,7 +2,6 @@ package gapi import ( "testing" - "github.com/grafana/grafana/pkg/api/dtos" ) const ( @@ -10,36 +9,16 @@ const ( deleteUserJSON = `{"message":"User deleted"}` ) -func TestCreateUserForm(t *testing.T) { - server, client := gapiTestTools(200, createUserJSON) - defer server.Close() - user := dtos.AdminCreateUserForm{ - Email: "admin@localhost", - Login: "admin", - Name: "Administrator", - Password: "password", - } - resp, err := client.CreateUserForm(user) - if err != nil { - t.Error(err) - } - - if resp != 1 { - t.Error("Not correctly parsing returned user message.") - } -} - func TestCreateUser(t *testing.T) { server, client := gapiTestTools(200, createUserJSON) defer server.Close() - - user := dtos.AdminCreateUserForm{ + user := User{ Email: "admin@localhost", Login: "admin", Name: "Administrator", Password: "password", } - resp, err := client.CreateUser(user.Email, user.Login, user.Email, user.Password) + resp, err := client.CreateUser(user) if err != nil { t.Error(err) } From 0a6231105a68b8e36740344c16fc7734db7aebdd Mon Sep 17 00:00:00 2001 From: Malcolm Jones Date: Thu, 12 Jul 2018 14:48:12 -0400 Subject: [PATCH 46/55] Go formatting --- admin_test.go | 22 +++++++++++----------- alertnotification.go | 10 +++++----- org_users.go | 12 ++++++------ org_users_test.go | 14 +++++++------- orgs.go | 8 ++++---- orgs_test.go | 6 +++--- user.go | 16 ++++++++-------- user_test.go | 42 +++++++++++++++++++++--------------------- 8 files changed, 65 insertions(+), 65 deletions(-) diff --git a/admin_test.go b/admin_test.go index 2dec7262..5a836b81 100644 --- a/admin_test.go +++ b/admin_test.go @@ -5,17 +5,17 @@ import ( ) const ( - createUserJSON = `{"id":1,"message":"User created"}` + createUserJSON = `{"id":1,"message":"User created"}` deleteUserJSON = `{"message":"User deleted"}` ) func TestCreateUser(t *testing.T) { server, client := gapiTestTools(200, createUserJSON) defer server.Close() - user := User{ - Email: "admin@localhost", - Login: "admin", - Name: "Administrator", + user := User{ + Email: "admin@localhost", + Login: "admin", + Name: "Administrator", Password: "password", } resp, err := client.CreateUser(user) @@ -29,11 +29,11 @@ func TestCreateUser(t *testing.T) { } func TestDeleteUser(t *testing.T) { - server, client := gapiTestTools(200, deleteUserJSON) - defer server.Close() + server, client := gapiTestTools(200, deleteUserJSON) + defer server.Close() - err := client.DeleteUser(int64(1)) - if err != nil { - t.Error(err) - } + err := client.DeleteUser(int64(1)) + if err != nil { + t.Error(err) + } } diff --git a/alertnotification.go b/alertnotification.go index 6c8cdc69..bd99db9f 100644 --- a/alertnotification.go +++ b/alertnotification.go @@ -9,11 +9,11 @@ import ( ) type AlertNotification struct { - Id int64 `json:"id,omitempty"` - Name string `json:"name"` - Type string `json:"type"` - IsDefault bool `json:"isDefault"` - Settings interface{} `json:"settings"` + Id int64 `json:"id,omitempty"` + Name string `json:"name"` + Type string `json:"type"` + IsDefault bool `json:"isDefault"` + Settings interface{} `json:"settings"` } func (c *Client) AlertNotification(id int64) (*AlertNotification, error) { diff --git a/org_users.go b/org_users.go index 9921dfd2..69d8e0d4 100644 --- a/org_users.go +++ b/org_users.go @@ -9,11 +9,11 @@ import ( ) type OrgUser struct { - OrgId int64 `json:"orgId"` - UserId int64 `json:"userId"` - Email string `json:"email"` - Login string `json:"login"` - Role string `json:"role"` + OrgId int64 `json:"orgId"` + UserId int64 `json:"userId"` + Email string `json:"email"` + Login string `json:"login"` + Role string `json:"role"` } func (c *Client) OrgUsers(orgId int64) ([]OrgUser, error) { @@ -43,7 +43,7 @@ func (c *Client) OrgUsers(orgId int64) ([]OrgUser, error) { func (c *Client) AddOrgUser(orgId int64, user, role string) error { dataMap := map[string]string{ "loginOrEmail": user, - "role": role, + "role": role, } data, err := json.Marshal(dataMap) req, err := c.newRequest("POST", fmt.Sprintf("/api/orgs/%d/users", orgId), nil, bytes.NewBuffer(data)) diff --git a/org_users_test.go b/org_users_test.go index dfbb7f49..b03a9c2a 100644 --- a/org_users_test.go +++ b/org_users_test.go @@ -1,13 +1,13 @@ package gapi import ( - "testing" "github.com/gobs/pretty" + "testing" ) const ( - getOrgUsersJSON = `[{"orgId":1,"userId":1,"email":"admin@localhost","avatarUrl":"/avatar/46d229b033af06a191ff2267bca9ae56","login":"admin","role":"Admin","lastSeenAt":"2018-06-28T14:16:11Z","lastSeenAtAge":"\u003c 1m"}]` - addOrgUserJSON = `{"message":"User added to organization"}` + getOrgUsersJSON = `[{"orgId":1,"userId":1,"email":"admin@localhost","avatarUrl":"/avatar/46d229b033af06a191ff2267bca9ae56","login":"admin","role":"Admin","lastSeenAt":"2018-06-28T14:16:11Z","lastSeenAtAge":"\u003c 1m"}]` + addOrgUserJSON = `{"message":"User added to organization"}` updateOrgUserJSON = `{"message":"Organization user updated"}` removeOrgUserJSON = `{"message":"User removed from organization"}` ) @@ -25,11 +25,11 @@ func TestOrgUsers(t *testing.T) { t.Log(pretty.PrettyFormat(resp)) user := OrgUser{ - OrgId: 1, + OrgId: 1, UserId: 1, - Email: "admin@localhost", - Login: "admin", - Role: "Admin", + Email: "admin@localhost", + Login: "admin", + Role: "Admin", } if resp[0] != user { diff --git a/orgs.go b/orgs.go index e4d47316..2ef4e2d5 100644 --- a/orgs.go +++ b/orgs.go @@ -9,8 +9,8 @@ import ( ) type Org struct { - Id int64 `json:"id"` - Name string `json:"name"` + Id int64 `json:"id"` + Name string `json:"name"` } func (c *Client) Orgs() ([]Org, error) { @@ -37,7 +37,7 @@ func (c *Client) Orgs() ([]Org, error) { func (c *Client) OrgByName(name string) (Org, error) { org := Org{} - req, err := c.newRequest("GET", fmt.Sprintf("/api/orgs/name/%s", name), nil, nil) + req, err := c.newRequest("GET", fmt.Sprintf("/api/orgs/name/%s", name), nil, nil) if err != nil { return org, err } @@ -58,7 +58,7 @@ func (c *Client) OrgByName(name string) (Org, error) { func (c *Client) Org(id int64) (Org, error) { org := Org{} - req, err := c.newRequest("GET", fmt.Sprintf("/api/orgs/%d", id), nil, nil) + req, err := c.newRequest("GET", fmt.Sprintf("/api/orgs/%d", id), nil, nil) if err != nil { return org, err } diff --git a/orgs_test.go b/orgs_test.go index 956d896f..ca81ab43 100644 --- a/orgs_test.go +++ b/orgs_test.go @@ -1,13 +1,13 @@ package gapi import ( - "testing" "github.com/gobs/pretty" + "testing" ) const ( - getOrgsJSON = `[{"id":1,"name":"Main Org."},{"id":2,"name":"Test Org."}]` - getOrgJSON = `{"id":1,"name":"Main Org.","address":{"address1":"","address2":"","city":"","zipCode":"","state":"","country":""}}` + getOrgsJSON = `[{"id":1,"name":"Main Org."},{"id":2,"name":"Test Org."}]` + getOrgJSON = `{"id":1,"name":"Main Org.","address":{"address1":"","address2":"","city":"","zipCode":"","state":"","country":""}}` createdOrgJSON = `{"message":"Organization created","orgId":1}` updatedOrgJSON = `{"message":"Organization updated"}` deletedOrgJSON = `{"message":"Organization deleted"}` diff --git a/user.go b/user.go index 17c879ae..66f56349 100644 --- a/user.go +++ b/user.go @@ -8,10 +8,10 @@ import ( ) type User struct { - Id int64 `json:"id,omitempty"` - Email string `json:"email,omitempty"` - Name string `json:"name,omitempty"` - Login string `json:"login,omitempty"` + Id int64 `json:"id,omitempty"` + Email string `json:"email,omitempty"` + Name string `json:"name,omitempty"` + Login string `json:"login,omitempty"` Password string `json:"password,omitempty"` IsAdmin bool `json:"isAdmin,omitempty"` } @@ -60,10 +60,10 @@ func (c *Client) UserByEmail(email string) (User, error) { return user, err } tmp := struct { - Id int64 `json:"id,omitempty"` - Email string `json:"email,omitempty"` - Name string `json:"name,omitempty"` - Login string `json:"login,omitempty"` + Id int64 `json:"id,omitempty"` + Email string `json:"email,omitempty"` + Name string `json:"name,omitempty"` + Login string `json:"login,omitempty"` Password string `json:"password,omitempty"` IsAdmin bool `json:"isGrafanaAdmin,omitempty"` }{} diff --git a/user_test.go b/user_test.go index 0ee1d88c..dee17397 100644 --- a/user_test.go +++ b/user_test.go @@ -1,12 +1,12 @@ package gapi import ( - "testing" "github.com/gobs/pretty" + "testing" ) const ( - getUsersJSON = `[{"id":1,"name":"","login":"admin","email":"admin@localhost","avatarUrl":"/avatar/46d229b033af06a191ff2267bca9ae56","isAdmin":true,"lastSeenAt":"2018-06-28T14:42:24Z","lastSeenAtAge":"\u003c 1m"}]` + getUsersJSON = `[{"id":1,"name":"","login":"admin","email":"admin@localhost","avatarUrl":"/avatar/46d229b033af06a191ff2267bca9ae56","isAdmin":true,"lastSeenAt":"2018-06-28T14:42:24Z","lastSeenAtAge":"\u003c 1m"}]` getUserByEmailJSON = `{"id":1,"email":"admin@localhost","name":"","login":"admin","theme":"","orgId":1,"isGrafanaAdmin":true}` ) @@ -22,10 +22,10 @@ func TestUsers(t *testing.T) { t.Log(pretty.PrettyFormat(resp)) user := User{ - Id: 1, - Email: "admin@localhost", - Name: "", - Login: "admin", + Id: 1, + Email: "admin@localhost", + Name: "", + Login: "admin", IsAdmin: true, } @@ -35,24 +35,24 @@ func TestUsers(t *testing.T) { } func TestUserByEmail(t *testing.T) { - server, client := gapiTestTools(200, getUserByEmailJSON) - defer server.Close() + server, client := gapiTestTools(200, getUserByEmailJSON) + defer server.Close() - resp, err := client.UserByEmail("admin@localhost") - if err != nil { - t.Error(err) - } + resp, err := client.UserByEmail("admin@localhost") + if err != nil { + t.Error(err) + } - t.Log(pretty.PrettyFormat(resp)) + t.Log(pretty.PrettyFormat(resp)) - user := User{ - Id: 1, - Email: "admin@localhost", - Name: "", - Login: "admin", + user := User{ + Id: 1, + Email: "admin@localhost", + Name: "", + Login: "admin", IsAdmin: true, } - if resp != user { - t.Error("Not correctly parsing returned user.") - } + if resp != user { + t.Error("Not correctly parsing returned user.") + } } From 0ee96e2d774f991709159a86cb50eaf74cd5c403 Mon Sep 17 00:00:00 2001 From: Tony Li Date: Wed, 5 Sep 2018 14:32:28 -0700 Subject: [PATCH 47/55] Update issue templates --- .github/ISSUE_TEMPLATE/bug_report.md | 24 +++++++++++++++++++++++ .github/ISSUE_TEMPLATE/feature_request.md | 17 ++++++++++++++++ 2 files changed, 41 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/bug_report.md create mode 100644 .github/ISSUE_TEMPLATE/feature_request.md diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 00000000..0c8ea5c9 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,24 @@ +--- +name: Bug report +about: Create a report to help us improve + +--- + +**Describe the bug** +A clear and concise description of what the bug is. + +**To reproduce** +Steps to reproduce the behavior: +1. Go to '...' +2. Click on '....' +3. Scroll down to '....' +4. See error + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**Additional context** +Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 00000000..c6d8ecf1 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,17 @@ +--- +name: Feature request +about: Suggest an idea for this project + +--- + +**Is your feature request related to a problem?** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** +Add any other context or screenshots about the feature request here. From 7fd34a3ec2546b6a0eead39774c77452cca1ab00 Mon Sep 17 00:00:00 2001 From: Gordon Irving Date: Tue, 9 Oct 2018 10:18:23 -0700 Subject: [PATCH 48/55] add swap files to vim ignore --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index daf913b1..b98422d4 100644 --- a/.gitignore +++ b/.gitignore @@ -22,3 +22,6 @@ _testmain.go *.exe *.test *.prof + +# vim swap files +.*.sw? From aaaf5905ca852c3e65efe5fbb3bc8b3d757ae2fb Mon Sep 17 00:00:00 2001 From: Gordon Irving Date: Tue, 9 Oct 2018 10:21:41 -0700 Subject: [PATCH 49/55] add folder support --- folder.go | 123 ++++++++++++++++++++++++++++++++++++++ folder_test.go | 156 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 279 insertions(+) create mode 100644 folder.go create mode 100644 folder_test.go diff --git a/folder.go b/folder.go new file mode 100644 index 00000000..d12bb3a4 --- /dev/null +++ b/folder.go @@ -0,0 +1,123 @@ +package gapi + +import ( + "bytes" + "encoding/json" + "errors" + "fmt" + "io/ioutil" +) + +type Folder struct { + Id int64 `json:"id"` + Title string `json:"title"` +} + +func (c *Client) Folders() ([]Folder, error) { + folders := make([]Folder, 0) + + req, err := c.newRequest("GET", "/api/folders/", nil, nil) + if err != nil { + return folders, err + } + resp, err := c.Do(req) + if err != nil { + return folders, err + } + if resp.StatusCode != 200 { + return folders, errors.New(resp.Status) + } + data, err := ioutil.ReadAll(resp.Body) + if err != nil { + return folders, err + } + err = json.Unmarshal(data, &folders) + return folders, err +} + +func (c *Client) Folder(id int64) (Folder, error) { + folder := Folder{} + req, err := c.newRequest("GET", fmt.Sprintf("/api/folders/%d", id), nil, nil) + if err != nil { + return folder, err + } + resp, err := c.Do(req) + if err != nil { + return folder, err + } + if resp.StatusCode != 200 { + return folder, errors.New(resp.Status) + } + data, err := ioutil.ReadAll(resp.Body) + if err != nil { + return folder, err + } + err = json.Unmarshal(data, &folder) + return folder, err +} + +func (c *Client) NewFolder(name string) (int64, error) { + dataMap := map[string]string{ + "name": name, + } + data, err := json.Marshal(dataMap) + id := int64(0) + req, err := c.newRequest("POST", "/api/folders", nil, bytes.NewBuffer(data)) + if err != nil { + return id, err + } + resp, err := c.Do(req) + if err != nil { + return id, err + } + if resp.StatusCode != 200 { + return id, errors.New(resp.Status) + } + data, err = ioutil.ReadAll(resp.Body) + if err != nil { + return id, err + } + tmp := struct { + Id int64 `json:"id"` + }{} + err = json.Unmarshal(data, &tmp) + if err != nil { + return id, err + } + id = tmp.Id + return id, err +} + +func (c *Client) UpdateFolder(id int64, name string) error { + dataMap := map[string]string{ + "name": name, + } + data, err := json.Marshal(dataMap) + req, err := c.newRequest("PUT", fmt.Sprintf("/api/folders/%d", id), nil, bytes.NewBuffer(data)) + if err != nil { + return err + } + resp, err := c.Do(req) + if err != nil { + return err + } + if resp.StatusCode != 200 { + return errors.New(resp.Status) + } + return err +} + +func (c *Client) DeleteFolder(id int64) error { + req, err := c.newRequest("DELETE", fmt.Sprintf("/api/folders/%d", id), nil, nil) + if err != nil { + return err + } + resp, err := c.Do(req) + if err != nil { + return err + } + if resp.StatusCode != 200 { + return errors.New(resp.Status) + } + return err +} diff --git a/folder_test.go b/folder_test.go new file mode 100644 index 00000000..02b805a0 --- /dev/null +++ b/folder_test.go @@ -0,0 +1,156 @@ +package gapi + +import ( + "github.com/gobs/pretty" + "testing" +) + +const ( + getFoldersJSON = ` +[ + { + "id":1, + "uid": "nErXDvCkzz", + "title": "Departmenet ABC", + "url": "/dashboards/f/nErXDvCkzz/department-abc", + "hasAcl": false, + "canSave": true, + "canEdit": true, + "canAdmin": true, + "createdBy": "admin", + "created": "2018-01-31T17:43:12+01:00", + "updatedBy": "admin", + "updated": "2018-01-31T17:43:12+01:00", + "version": 1 + } +] + ` + getFolderJSON = ` +{ + "id":1, + "uid": "nErXDvCkzz", + "title": "Departmenet ABC", + "url": "/dashboards/f/nErXDvCkzz/department-abc", + "hasAcl": false, + "canSave": true, + "canEdit": true, + "canAdmin": true, + "createdBy": "admin", + "created": "2018-01-31T17:43:12+01:00", + "updatedBy": "admin", + "updated": "2018-01-31T17:43:12+01:00", + "version": 1 +} +` + createdFolderJSON = ` +{ + "id":1, + "uid": "nErXDvCkzz", + "title": "Departmenet ABC", + "url": "/dashboards/f/nErXDvCkzz/department-abc", + "hasAcl": false, + "canSave": true, + "canEdit": true, + "canAdmin": true, + "createdBy": "admin", + "created": "2018-01-31T17:43:12+01:00", + "updatedBy": "admin", + "updated": "2018-01-31T17:43:12+01:00", + "version": 1 +} +` + updatedFolderJSON = ` +{ + "id":1, + "uid": "nErXDvCkzz", + "title": "Departmenet DEF", + "url": "/dashboards/f/nErXDvCkzz/department-def", + "hasAcl": false, + "canSave": true, + "canEdit": true, + "canAdmin": true, + "createdBy": "admin", + "created": "2018-01-31T17:43:12+01:00", + "updatedBy": "admin", + "updated": "2018-01-31T17:43:12+01:00", + "version": 1 +} +` + deletedFolderJSON = ` +{ + "message":"Folder deleted" +} +` +) + +func TestFolders(t *testing.T) { + server, client := gapiTestTools(200, getFoldersJSON) + defer server.Close() + + folders, err := client.Folders() + if err != nil { + t.Error(err) + } + + t.Log(pretty.PrettyFormat(folders)) + + if len(folders) != 1 { + t.Error("Length of returned folders should be 1") + } + if folders[0].Id != 1 || folders[0].Title != "Departmenet ABC" { + t.Error("Not correctly parsing returned folders.") + } +} + +func TestFolder(t *testing.T) { + server, client := gapiTestTools(200, getFolderJSON) + defer server.Close() + + folder := int64(1) + resp, err := client.Folder(folder) + if err != nil { + t.Error(err) + } + + t.Log(pretty.PrettyFormat(resp)) + + if resp.Id != folder || resp.Title != "Departmenet ABC" { + t.Error("Not correctly parsing returned folder.") + } +} + +func TestNewFolder(t *testing.T) { + server, client := gapiTestTools(200, createdFolderJSON) + defer server.Close() + + resp, err := client.NewFolder("test-folder") + if err != nil { + t.Error(err) + } + + t.Log(pretty.PrettyFormat(resp)) + + if resp != 1 { + t.Error("Not correctly parsing returned creation message.") + } +} + +func TestUpdateFolder(t *testing.T) { + server, client := gapiTestTools(200, updatedFolderJSON) + defer server.Close() + + err := client.UpdateFolder(int64(1), "test-folder") + if err != nil { + t.Error(err) + } +} + +func TestDeleteFolder(t *testing.T) { + server, client := gapiTestTools(200, deletedFolderJSON) + defer server.Close() + + err := client.DeleteFolder(int64(1)) + if err != nil { + t.Error(err) + } +} From 806385851d8453ec65b09f31d4e144cdd0273ffd Mon Sep 17 00:00:00 2001 From: Max Ramqvist Date: Wed, 10 Oct 2018 15:07:34 +0200 Subject: [PATCH 50/55] Implement skipping TLS certificate verification that is available through the Grafana HTTP API. --- datasource.go | 1 + datasource_test.go | 1 + 2 files changed, 2 insertions(+) diff --git a/datasource.go b/datasource.go index 5e2d014f..a5b40dea 100644 --- a/datasource.go +++ b/datasource.go @@ -36,6 +36,7 @@ type JSONData struct { AuthType string `json:"authType,omitempty"` CustomMetricsNamespaces string `json:"customMetricsNamespaces,omitempty"` DefaultRegion string `json:"defaultRegion,omitempty"` + TlsSkipVerify bool `json:"tlsSkipVerify,omitempty"` } // SecureJSONData is a representation of the datasource `secureJsonData` property diff --git a/datasource_test.go b/datasource_test.go index a182ea29..c2ee1b79 100644 --- a/datasource_test.go +++ b/datasource_test.go @@ -54,6 +54,7 @@ func TestNewDataSource(t *testing.T) { AuthType: "keys", CustomMetricsNamespaces: "SomeNamespace", DefaultRegion: "us-east-1", + TlsSkipVerify: true, }, SecureJSONData: SecureJSONData{ AccessKey: "123", From 8f0b4f88d174f8fe84a946306aa0ccd0b962cc1c Mon Sep 17 00:00:00 2001 From: Gordon Irving Date: Wed, 10 Oct 2018 12:58:01 -0700 Subject: [PATCH 51/55] expose uid and id on folder, add NewDashboard method to accept folderId --- dashboard.go | 38 ++++++++++++++++++++++++++++++++++++-- folder.go | 33 +++++++++++++++------------------ folder_test.go | 6 +++--- 3 files changed, 54 insertions(+), 23 deletions(-) diff --git a/dashboard.go b/dashboard.go index 8e4d6c47..cfb1db19 100644 --- a/dashboard.go +++ b/dashboard.go @@ -15,15 +15,20 @@ type DashboardMeta struct { type DashboardSaveResponse struct { Slug string `json:"slug"` + Id int64 `json:"id"` + Uid string `json:"uid"` Status string `json:"status"` Version int64 `json:"version"` } type Dashboard struct { - Meta DashboardMeta `json:"meta"` - Model map[string]interface{} `json:"dashboard"` + Meta DashboardMeta `json:"meta"` + Model map[string]interface{} `json:"dashboard"` + Folder int64 `json:"folderId"` + Overwrite bool `json:overwrite` } +// Deprecated: use NewDashboard instead func (c *Client) SaveDashboard(model map[string]interface{}, overwrite bool) (*DashboardSaveResponse, error) { wrapper := map[string]interface{}{ "dashboard": model, @@ -38,6 +43,35 @@ func (c *Client) SaveDashboard(model map[string]interface{}, overwrite bool) (*D return nil, err } + resp, err := c.Do(req) + if err != nil { + return nil, err + } + if resp.StatusCode != 200 { + data, _ = ioutil.ReadAll(resp.Body) + return nil, fmt.Errorf("status: %d, body: %s", resp.StatusCode, data) + } + + data, err = ioutil.ReadAll(resp.Body) + if err != nil { + return nil, err + } + + result := &DashboardSaveResponse{} + err = json.Unmarshal(data, &result) + return result, err +} + +func (c *Client) NewDashboard(dashboard Dashboard) (*DashboardSaveResponse, error) { + data, err := json.Marshal(dashboard) + if err != nil { + return nil, err + } + req, err := c.newRequest("POST", "/api/dashboards/db", nil, bytes.NewBuffer(data)) + if err != nil { + return nil, err + } + resp, err := c.Do(req) if err != nil { return nil, err diff --git a/folder.go b/folder.go index d12bb3a4..93ee85ac 100644 --- a/folder.go +++ b/folder.go @@ -10,6 +10,7 @@ import ( type Folder struct { Id int64 `json:"id"` + Uid string `json:"uid"` Title string `json:"title"` } @@ -56,44 +57,40 @@ func (c *Client) Folder(id int64) (Folder, error) { return folder, err } -func (c *Client) NewFolder(name string) (int64, error) { +func (c *Client) NewFolder(title string) (Folder, error) { + folder := Folder{} dataMap := map[string]string{ - "name": name, + "title": title, } data, err := json.Marshal(dataMap) - id := int64(0) req, err := c.newRequest("POST", "/api/folders", nil, bytes.NewBuffer(data)) if err != nil { - return id, err + return folder, err } resp, err := c.Do(req) if err != nil { - return id, err + return folder, err } if resp.StatusCode != 200 { - return id, errors.New(resp.Status) + return folder, errors.New(resp.Status) } data, err = ioutil.ReadAll(resp.Body) if err != nil { - return id, err + return folder, err } - tmp := struct { - Id int64 `json:"id"` - }{} - err = json.Unmarshal(data, &tmp) + err = json.Unmarshal(data, &folder) if err != nil { - return id, err + return folder, err } - id = tmp.Id - return id, err + return folder, err } -func (c *Client) UpdateFolder(id int64, name string) error { +func (c *Client) UpdateFolder(id string, name string) error { dataMap := map[string]string{ "name": name, } data, err := json.Marshal(dataMap) - req, err := c.newRequest("PUT", fmt.Sprintf("/api/folders/%d", id), nil, bytes.NewBuffer(data)) + req, err := c.newRequest("PUT", fmt.Sprintf("/api/folders/%s", id), nil, bytes.NewBuffer(data)) if err != nil { return err } @@ -107,8 +104,8 @@ func (c *Client) UpdateFolder(id int64, name string) error { return err } -func (c *Client) DeleteFolder(id int64) error { - req, err := c.newRequest("DELETE", fmt.Sprintf("/api/folders/%d", id), nil, nil) +func (c *Client) DeleteFolder(id string) error { + req, err := c.newRequest("DELETE", fmt.Sprintf("/api/folders/%s", id), nil, nil) if err != nil { return err } diff --git a/folder_test.go b/folder_test.go index 02b805a0..f02f313d 100644 --- a/folder_test.go +++ b/folder_test.go @@ -130,7 +130,7 @@ func TestNewFolder(t *testing.T) { t.Log(pretty.PrettyFormat(resp)) - if resp != 1 { + if resp.Uid != "nErXDvCkzz" { t.Error("Not correctly parsing returned creation message.") } } @@ -139,7 +139,7 @@ func TestUpdateFolder(t *testing.T) { server, client := gapiTestTools(200, updatedFolderJSON) defer server.Close() - err := client.UpdateFolder(int64(1), "test-folder") + err := client.UpdateFolder("nErXDvCkzz", "test-folder") if err != nil { t.Error(err) } @@ -149,7 +149,7 @@ func TestDeleteFolder(t *testing.T) { server, client := gapiTestTools(200, deletedFolderJSON) defer server.Close() - err := client.DeleteFolder(int64(1)) + err := client.DeleteFolder("nErXDvCkzz") if err != nil { t.Error(err) } From 42c903f0a587be03981b24790032d94653bf0efc Mon Sep 17 00:00:00 2001 From: Gordon Irving Date: Wed, 10 Oct 2018 18:40:51 -0700 Subject: [PATCH 52/55] use folder id api endpoint for finding folder by id --- folder.go | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/folder.go b/folder.go index 93ee85ac..55613c60 100644 --- a/folder.go +++ b/folder.go @@ -36,9 +36,9 @@ func (c *Client) Folders() ([]Folder, error) { return folders, err } -func (c *Client) Folder(id int64) (Folder, error) { - folder := Folder{} - req, err := c.newRequest("GET", fmt.Sprintf("/api/folders/%d", id), nil, nil) +func (c *Client) Folder(id int64) (*Folder, error) { + folder := &Folder{} + req, err := c.newRequest("GET", fmt.Sprintf("/api/folders/id/%d", id), nil, nil) if err != nil { return folder, err } @@ -72,7 +72,8 @@ func (c *Client) NewFolder(title string) (Folder, error) { return folder, err } if resp.StatusCode != 200 { - return folder, errors.New(resp.Status) + data, _ = ioutil.ReadAll(resp.Body) + return folder, fmt.Errorf("status: %s body: %s", resp.Status, data) } data, err = ioutil.ReadAll(resp.Body) if err != nil { From 8ef34fa3d2c3bf2c45e690edbda00efabe6209a1 Mon Sep 17 00:00:00 2001 From: Gordon Irving Date: Wed, 10 Oct 2018 18:41:29 -0700 Subject: [PATCH 53/55] copy back folder id from meta --- dashboard.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/dashboard.go b/dashboard.go index cfb1db19..2d6418f1 100644 --- a/dashboard.go +++ b/dashboard.go @@ -6,11 +6,14 @@ import ( "errors" "fmt" "io/ioutil" + "log" + "os" ) type DashboardMeta struct { IsStarred bool `json:"isStarred"` Slug string `json:"slug"` + Folder int64 `json:"folderId"` } type DashboardSaveResponse struct { @@ -112,6 +115,10 @@ func (c *Client) Dashboard(slug string) (*Dashboard, error) { result := &Dashboard{} err = json.Unmarshal(data, &result) + result.Folder = result.Meta.Folder + if os.Getenv("GF_LOG") != "" { + log.Printf("got back dashboard response %s", data) + } return result, err } From cebdee9127596d60be97958298235c8c72d51079 Mon Sep 17 00:00:00 2001 From: Gordon Irving Date: Wed, 10 Oct 2018 18:41:52 -0700 Subject: [PATCH 54/55] include method in debug output --- client.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client.go b/client.go index 1ab6884d..d2d12669 100644 --- a/client.go +++ b/client.go @@ -53,9 +53,9 @@ func (c *Client) newRequest(method, requestPath string, query url.Values, body i if os.Getenv("GF_LOG") != "" { if body == nil { - log.Println("request to ", url.String(), "with no body data") + log.Printf("request (%s) to %s with no body data", method, url.String()) } else { - log.Println("request to ", url.String(), "with body data", body.(*bytes.Buffer).String()) + log.Printf("request (%s) to %s with body data: %s", method, url.String(), body.(*bytes.Buffer).String()) } } From 984accf70d057b6ffe9d0df8cc6ad8f6de748e08 Mon Sep 17 00:00:00 2001 From: Juan Esteban Colcombet Date: Thu, 5 Sep 2019 23:12:15 -0300 Subject: [PATCH 55/55] Update alert notification and test has been added --- alertnotification.go | 38 +++++++-- alertnotification_test.go | 171 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 204 insertions(+), 5 deletions(-) create mode 100644 alertnotification_test.go diff --git a/alertnotification.go b/alertnotification.go index bd99db9f..ce9ccb36 100644 --- a/alertnotification.go +++ b/alertnotification.go @@ -9,11 +9,39 @@ import ( ) type AlertNotification struct { - Id int64 `json:"id,omitempty"` - Name string `json:"name"` - Type string `json:"type"` - IsDefault bool `json:"isDefault"` - Settings interface{} `json:"settings"` + Id int64 `json:"id,omitempty"` + Name string `json:"name"` + Type string `json:"type"` + IsDefault bool `json:"isDefault"` + DisableResolveMessage bool `json:"disableResolveMessage"` + SendReminder bool `json:"sendReminder"` + Frequency string `json:"frequency"` + Settings interface{} `json:"settings"` +} + +func (c *Client) AlertNotifications() ([]AlertNotification, error) { + alertnotifications := make([]AlertNotification, 0) + + req, err := c.newRequest("GET", "/api/alert-notifications/", nil, nil) + if err != nil { + return nil, err + } + + resp, err := c.Do(req) + if err != nil { + return nil, err + } + if resp.StatusCode != 200 { + return nil, errors.New(resp.Status) + } + + data, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, err + } + + err = json.Unmarshal(data, &alertnotifications) + return alertnotifications, err } func (c *Client) AlertNotification(id int64) (*AlertNotification, error) { diff --git a/alertnotification_test.go b/alertnotification_test.go new file mode 100644 index 00000000..05763546 --- /dev/null +++ b/alertnotification_test.go @@ -0,0 +1,171 @@ +package gapi + +import ( + "github.com/gobs/pretty" + "testing" +) + +const ( + getAlertNotificationsJSON = ` +[ + { + "id": 1, + "uid": "team-a-email-notifier", + "name": "Team A", + "type": "email", + "isDefault": false, + "sendReminder": false, + "disableResolveMessage": false, + "settings": { + "addresses": "dev@grafana.com" + }, + "created": "2018-04-23T14:44:09+02:00", + "updated": "2018-08-20T15:47:49+02:00" + } +] + ` + getAlertNotificationJSON = ` +{ + "id": 1, + "uid": "team-a-email-notifier", + "name": "Team A", + "type": "email", + "isDefault": false, + "sendReminder": false, + "disableResolveMessage": false, + "settings": { + "addresses": "dev@grafana.com" + }, + "created": "2018-04-23T14:44:09+02:00", + "updated": "2018-08-20T15:47:49+02:00" +} +` + createdAlertNotificationJSON = ` +{ + "id": 1, + "uid": "new-alert-notification", + "name": "Team A", + "type": "email", + "isDefault": false, + "sendReminder": true, + "frequency": "15m", + "settings": { + "addresses": "dev@grafana.com" + } +} +` + updatedAlertNotificationJSON = ` +{ + "uid": "new-alert-notification", + "name": "Team A", + "type": "email", + "isDefault": false, + "sendReminder": true, + "frequency": "15m", + "settings": { + "addresses": "dev@grafana.com" + } +} +` + deletedAlertNotificationJSON = ` +{ + "message":"Notification deleted" +} +` +) + +func TestAlertNotifications(t *testing.T) { + server, client := gapiTestTools(200, getAlertNotificationsJSON) + defer server.Close() + + alertnotifications, err := client.AlertNotifications() + if err != nil { + t.Error(err) + } + + t.Log(pretty.PrettyFormat(alertnotifications)) + + if len(alertnotifications) != 1 { + t.Error("Length of returned alert notifications should be 1") + } + if alertnotifications[0].Id != 1 || alertnotifications[0].Name != "Team A" { + t.Error("Not correctly parsing returned alert notifications.") + } +} + +func TestAlertNotification(t *testing.T) { + server, client := gapiTestTools(200, getAlertNotificationJSON) + defer server.Close() + + alertnotification := int64(1) + resp, err := client.AlertNotification(alertnotification) + if err != nil { + t.Error(err) + } + + t.Log(pretty.PrettyFormat(resp)) + + if resp.Id != alertnotification || resp.Name != "Team A" { + t.Error("Not correctly parsing returned alert notification.") + } +} + +func TestNewAlertNotification(t *testing.T) { + server, client := gapiTestTools(200, createdAlertNotificationJSON) + defer server.Close() + + an := &AlertNotification{ + Name: "Team A", + Type: "email", + IsDefault: false, + DisableResolveMessage: true, + SendReminder: true, + Frequency: "15m", + Settings: map[string]string{ + "addresses": "dev@grafana.com", + }, + } + resp, err := client.NewAlertNotification(an) + if err != nil { + t.Error(err) + } + + t.Log(pretty.PrettyFormat(resp)) + + if resp != 1 { + t.Error("Not correctly parsing returned creation message.") + } +} + +func TestUpdateAlertNotification(t *testing.T) { + server, client := gapiTestTools(200, updatedAlertNotificationJSON) + defer server.Close() + + an := &AlertNotification{ + Id: 1, + Name: "Team A", + Type: "email", + IsDefault: false, + DisableResolveMessage: true, + SendReminder: true, + Frequency: "15m", + Settings: map[string]string{ + "addresses": "dev@grafana.com", + }, + } + + err := client.UpdateAlertNotification(an) + if err != nil { + t.Error(err) + } +} + +func TestDeleteAlertNotification(t *testing.T) { + server, client := gapiTestTools(200, deletedAlertNotificationJSON) + defer server.Close() + + err := client.DeleteAlertNotification(1) + if err != nil { + t.Error(err) + } +}