From 7fd34a3ec2546b6a0eead39774c77452cca1ab00 Mon Sep 17 00:00:00 2001 From: Gordon Irving Date: Tue, 9 Oct 2018 10:18:23 -0700 Subject: [PATCH 1/6] add swap files to vim ignore --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index daf913b..b98422d 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 2/6] 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 0000000..d12bb3a --- /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 0000000..02b805a --- /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 8f0b4f88d174f8fe84a946306aa0ccd0b962cc1c Mon Sep 17 00:00:00 2001 From: Gordon Irving Date: Wed, 10 Oct 2018 12:58:01 -0700 Subject: [PATCH 3/6] 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 8e4d6c4..cfb1db1 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 d12bb3a..93ee85a 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 02b805a..f02f313 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 4/6] 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 93ee85a..55613c6 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 5/6] copy back folder id from meta --- dashboard.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/dashboard.go b/dashboard.go index cfb1db1..2d6418f 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 6/6] include method in debug output --- client.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client.go b/client.go index 1ab6884..d2d1266 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()) } }