From bff7b9082997ed8e39b8e2a4420c4c66e79889ed Mon Sep 17 00:00:00 2001 From: Kelvin Wang Date: Tue, 16 Apr 2019 18:06:39 -0400 Subject: [PATCH] fix(http): create view --- dashboard.go | 15 ++-- http/dashboard_service.go | 63 ++++++++++++----- http/dashboard_test.go | 142 +++++++++++++++++++++++++++++--------- http/swagger.yml | 3 - testing/dashboards.go | 28 ++++++-- 5 files changed, 185 insertions(+), 66 deletions(-) diff --git a/dashboard.go b/dashboard.go index 073da1bb87a..afefd5fc71a 100644 --- a/dashboard.go +++ b/dashboard.go @@ -122,11 +122,16 @@ func SortDashboards(opts FindOptions, ds []*Dashboard) { // Cell holds positional information about a cell on dashboard and a reference to a cell. type Cell struct { - ID ID `json:"id,omitempty"` - X int32 `json:"x"` - Y int32 `json:"y"` - W int32 `json:"w"` - H int32 `json:"h"` + ID ID `json:"id,omitempty"` + CellProperty +} + +// CellProperty contains the properties of a cell. +type CellProperty struct { + X int32 `json:"x"` + Y int32 `json:"y"` + W int32 `json:"w"` + H int32 `json:"h"` } // DashboardFilter is a filter for dashboards. diff --git a/http/dashboard_service.go b/http/dashboard_service.go index f3a1746f4fd..864460b0433 100644 --- a/http/dashboard_service.go +++ b/http/dashboard_service.go @@ -5,7 +5,6 @@ import ( "context" "encoding/json" "fmt" - "io/ioutil" "net/http" "path" @@ -691,13 +690,13 @@ func (r *patchDashboardRequest) Valid() error { type postDashboardCellRequest struct { dashboardID platform.ID - cell *platform.Cell - opts platform.AddDashboardCellOptions + *platform.CellProperty + UsingView *platform.ID `json:"usingView"` + Name *string `json:"name"` } func decodePostDashboardCellRequest(ctx context.Context, r *http.Request) (*postDashboardCellRequest, error) { req := &postDashboardCellRequest{} - params := httprouter.ParamsFromContext(ctx) id := params.ByName("id") if id == "" { @@ -706,21 +705,21 @@ func decodePostDashboardCellRequest(ctx context.Context, r *http.Request) (*post Msg: "url missing id", } } - if err := req.dashboardID.DecodeFromString(id); err != nil { - return nil, err - } - bs, err := ioutil.ReadAll(r.Body) - if err != nil { - return nil, err + if err := json.NewDecoder(r.Body).Decode(req); err != nil { + return nil, &platform.Error{ + Code: platform.EInvalid, + Msg: "bad request json body", + Err: err, + } } - req.cell = &platform.Cell{} - if err := json.NewDecoder(bytes.NewReader(bs)).Decode(req.cell); err != nil { - return nil, err - } - if err := json.NewDecoder(bytes.NewReader(bs)).Decode(&req.opts); err != nil { - return nil, err + if err := req.dashboardID.DecodeFromString(id); err != nil { + return nil, &platform.Error{ + Code: platform.EInvalid, + Msg: "invalid dashboard id", + Err: err, + } } return req, nil @@ -735,12 +734,40 @@ func (h *DashboardHandler) handlePostDashboardCell(w http.ResponseWriter, r *htt EncodeError(ctx, err, w) return } - if err := h.DashboardService.AddDashboardCell(ctx, req.dashboardID, req.cell, req.opts); err != nil { + cell := new(platform.Cell) + + opts := new(platform.AddDashboardCellOptions) + if req.UsingView != nil || req.Name != nil { + opts.View = new(platform.View) + if req.UsingView != nil { + // load the view + opts.View, err = h.DashboardService.GetDashboardCellView(ctx, req.dashboardID, *req.UsingView) + if err != nil { + EncodeError(ctx, err, w) + return + } + } + if req.Name != nil { + opts.View.Name = *req.Name + } + } else if req.CellProperty == nil { + EncodeError(ctx, &platform.Error{ + Code: platform.EInvalid, + Msg: "req body is empty", + }, w) + return + } + + if req.CellProperty != nil { + cell.CellProperty = *req.CellProperty + } + + if err := h.DashboardService.AddDashboardCell(ctx, req.dashboardID, cell, *opts); err != nil { EncodeError(ctx, err, w) return } - if err := encodeResponse(ctx, w, http.StatusCreated, newDashboardCellResponse(req.dashboardID, req.cell)); err != nil { + if err := encodeResponse(ctx, w, http.StatusCreated, newDashboardCellResponse(req.dashboardID, cell)); err != nil { logEncodingError(h.Logger, r, err) return } diff --git a/http/dashboard_test.go b/http/dashboard_test.go index d73f7a8d96d..6ef2cfeca29 100644 --- a/http/dashboard_test.go +++ b/http/dashboard_test.go @@ -74,10 +74,12 @@ func TestService_handleGetDashboards(t *testing.T) { Cells: []*platform.Cell{ { ID: platformtesting.MustIDBase16("da7aba5e5d81e550"), - X: 1, - Y: 2, - W: 3, - H: 4, + CellProperty: platform.CellProperty{ + X: 1, + Y: 2, + W: 3, + H: 4, + }, }, }, }, @@ -238,10 +240,12 @@ func TestService_handleGetDashboards(t *testing.T) { Cells: []*platform.Cell{ { ID: platformtesting.MustIDBase16("da7aba5e5d81e550"), - X: 1, - Y: 2, - W: 3, - H: 4, + CellProperty: platform.CellProperty{ + X: 1, + Y: 2, + W: 3, + H: 4, + }, }, }, }, @@ -399,10 +403,12 @@ func TestService_handleGetDashboard(t *testing.T) { Cells: []*platform.Cell{ { ID: platformtesting.MustIDBase16("da7aba5e5d81e550"), - X: 1, - Y: 2, - W: 3, - H: 4, + CellProperty: platform.CellProperty{ + X: 1, + Y: 2, + W: 3, + H: 4, + }, }, }, }, nil @@ -557,10 +563,12 @@ func TestService_handlePostDashboard(t *testing.T) { Cells: []*platform.Cell{ { ID: platformtesting.MustIDBase16("da7aba5e5d81e550"), - X: 1, - Y: 2, - W: 3, - H: 4, + CellProperty: platform.CellProperty{ + X: 1, + Y: 2, + W: 3, + H: 4, + }, }, }, }, @@ -776,10 +784,12 @@ func TestService_handlePatchDashboard(t *testing.T) { Cells: []*platform.Cell{ { ID: platformtesting.MustIDBase16("da7aba5e5d81e550"), - X: 1, - Y: 2, - W: 3, - H: 4, + CellProperty: platform.CellProperty{ + X: 1, + Y: 2, + W: 3, + H: 4, + }, }, }, } @@ -932,7 +942,7 @@ func TestService_handlePostDashboardCell(t *testing.T) { } type args struct { id string - cell *platform.Cell + body string } type wants struct { statusCode int @@ -947,7 +957,7 @@ func TestService_handlePostDashboardCell(t *testing.T) { wants wants }{ { - name: "create a dashboard cell", + name: "empty body", fields: fields{ &mock.DashboardService{ AddDashboardCellF: func(ctx context.Context, id platform.ID, c *platform.Cell, opt platform.AddDashboardCellOptions) error { @@ -958,12 +968,82 @@ func TestService_handlePostDashboardCell(t *testing.T) { }, args: args{ id: "020f755c3c082000", - cell: &platform.Cell{ - ID: platformtesting.MustIDBase16("020f755c3c082000"), - X: 10, - Y: 11, + }, + wants: wants{ + statusCode: http.StatusBadRequest, + contentType: "application/json; charset=utf-8", + body: `{"code":"invalid","message":"bad request json body","error":"EOF"}`, + }, + }, + { + name: "no properties", + fields: fields{ + &mock.DashboardService{ + AddDashboardCellF: func(ctx context.Context, id platform.ID, c *platform.Cell, opt platform.AddDashboardCellOptions) error { + c.ID = platformtesting.MustIDBase16("020f755c3c082000") + return nil + }, + }, + }, + args: args{ + id: "020f755c3c082000", + body: `{"bad":1}`, + }, + wants: wants{ + statusCode: http.StatusBadRequest, + contentType: "application/json; charset=utf-8", + body: ` + { + "code": "invalid", + "message": "req body is empty" + }`, + }, + }, + { + name: "bad dash id", + fields: fields{ + &mock.DashboardService{ + AddDashboardCellF: func(ctx context.Context, id platform.ID, c *platform.Cell, opt platform.AddDashboardCellOptions) error { + c.ID = platformtesting.MustIDBase16("020f755c3c082000") + return nil + }, + }, + }, + args: args{ + id: "fff", + body: `{}`, + }, + wants: wants{ + statusCode: http.StatusBadRequest, + contentType: "application/json; charset=utf-8", + body: ` + { + "code": "invalid", + "error": "id must have a length of 16 bytes", + "message": "invalid dashboard id" + }`, + }, + }, + { + name: "general create a dashboard cell", + fields: fields{ + &mock.DashboardService{ + AddDashboardCellF: func(ctx context.Context, id platform.ID, c *platform.Cell, opt platform.AddDashboardCellOptions) error { + c.ID = platformtesting.MustIDBase16("020f755c3c082000") + return nil + }, + GetDashboardCellViewF: func(ctx context.Context, id1, id2 platform.ID) (*platform.View, error) { + return &platform.View{ + ViewContents: platform.ViewContents{ + ID: platformtesting.MustIDBase16("020f755c3c082001"), + }}, nil + }, }, }, + args: args{ + id: "020f755c3c082000", + body: `{"x":10,"y":11,"name":"name1","usingView":"020f755c3c082001"}`, + }, wants: wants{ statusCode: http.StatusCreated, contentType: "application/json; charset=utf-8", @@ -989,13 +1069,9 @@ func TestService_handlePostDashboardCell(t *testing.T) { dashboardBackend := NewMockDashboardBackend() dashboardBackend.DashboardService = tt.fields.DashboardService h := NewDashboardHandler(dashboardBackend) - - b, err := json.Marshal(tt.args.cell) - if err != nil { - t.Fatalf("failed to unmarshal cell: %v", err) - } - - r := httptest.NewRequest("GET", "http://any.url", bytes.NewReader(b)) + buf := new(bytes.Buffer) + _, _ = buf.WriteString(tt.args.body) + r := httptest.NewRequest("POST", "http://any.url", buf) r = r.WithContext(context.WithValue( context.Background(), diff --git a/http/swagger.yml b/http/swagger.yml index 5169d275875..91c03ac37bc 100644 --- a/http/swagger.yml +++ b/http/swagger.yml @@ -6749,9 +6749,6 @@ components: h: type: integer format: int32 - viewID: - type: string - description: uses the view provided in the request usingView: type: string description: makes a copy of the provided view diff --git a/testing/dashboards.go b/testing/dashboards.go index c3efe3e4e82..0557906dfc3 100644 --- a/testing/dashboards.go +++ b/testing/dashboards.go @@ -1373,7 +1373,9 @@ func UpdateDashboardCell( Cells: []*platform.Cell{ { ID: MustIDBase16(dashTwoID), - X: 10, + CellProperty: platform.CellProperty{ + X: 10, + }, }, { ID: MustIDBase16(dashOneID), @@ -1576,11 +1578,15 @@ func ReplaceDashboardCells( cells: []*platform.Cell{ { ID: MustIDBase16(dashTwoID), - X: 10, + CellProperty: platform.CellProperty{ + X: 10, + }, }, { ID: MustIDBase16(dashOneID), - Y: 11, + CellProperty: platform.CellProperty{ + Y: 11, + }, }, }, }, @@ -1596,11 +1602,15 @@ func ReplaceDashboardCells( Cells: []*platform.Cell{ { ID: MustIDBase16(dashTwoID), - X: 10, + CellProperty: platform.CellProperty{ + X: 10, + }, }, { ID: MustIDBase16(dashOneID), - Y: 11, + CellProperty: platform.CellProperty{ + Y: 11, + }, }, }, }, @@ -1641,11 +1651,15 @@ func ReplaceDashboardCells( cells: []*platform.Cell{ { ID: MustIDBase16(dashTwoID), - X: 10, + CellProperty: platform.CellProperty{ + X: 10, + }, }, { ID: MustIDBase16(dashOneID), - Y: 11, + CellProperty: platform.CellProperty{ + Y: 11, + }, }, }, },