2018-05-31 14:44:23 +00:00
|
|
|
package http
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"context"
|
|
|
|
"encoding/json"
|
|
|
|
"fmt"
|
2018-08-07 20:10:05 +00:00
|
|
|
"io/ioutil"
|
2018-05-31 14:44:23 +00:00
|
|
|
"net/http"
|
2019-01-09 22:43:29 +00:00
|
|
|
"net/url"
|
2018-09-17 02:39:46 +00:00
|
|
|
"path"
|
2018-11-02 18:21:14 +00:00
|
|
|
"strconv"
|
2018-05-31 14:44:23 +00:00
|
|
|
|
2019-01-08 00:37:16 +00:00
|
|
|
platform "github.com/influxdata/influxdb"
|
|
|
|
"github.com/influxdata/influxdb/kit/errors"
|
2018-05-31 14:44:23 +00:00
|
|
|
"github.com/julienschmidt/httprouter"
|
2018-12-20 16:07:46 +00:00
|
|
|
"go.uber.org/zap"
|
2018-05-31 14:44:23 +00:00
|
|
|
)
|
|
|
|
|
2018-08-07 20:10:05 +00:00
|
|
|
// DashboardHandler is the handler for the dashboard service
|
2018-05-31 14:44:23 +00:00
|
|
|
type DashboardHandler struct {
|
|
|
|
*httprouter.Router
|
|
|
|
|
2018-12-20 16:07:46 +00:00
|
|
|
Logger *zap.Logger
|
|
|
|
|
2018-11-02 18:21:14 +00:00
|
|
|
DashboardService platform.DashboardService
|
|
|
|
DashboardOperationLogService platform.DashboardOperationLogService
|
|
|
|
UserResourceMappingService platform.UserResourceMappingService
|
2018-12-03 16:07:08 +00:00
|
|
|
LabelService platform.LabelService
|
2018-11-17 15:54:21 +00:00
|
|
|
UserService platform.UserService
|
2018-05-31 14:44:23 +00:00
|
|
|
}
|
|
|
|
|
2018-09-17 02:39:46 +00:00
|
|
|
const (
|
2019-01-04 19:12:35 +00:00
|
|
|
dashboardsPath = "/api/v2/dashboards"
|
|
|
|
dashboardsIDPath = "/api/v2/dashboards/:id"
|
|
|
|
dashboardsIDCellsPath = "/api/v2/dashboards/:id/cells"
|
|
|
|
dashboardsIDCellsIDPath = "/api/v2/dashboards/:id/cells/:cellID"
|
|
|
|
dashboardsIDCellsIDViewPath = "/api/v2/dashboards/:id/cells/:cellID/view"
|
|
|
|
dashboardsIDMembersPath = "/api/v2/dashboards/:id/members"
|
|
|
|
dashboardsIDLogPath = "/api/v2/dashboards/:id/log"
|
|
|
|
dashboardsIDMembersIDPath = "/api/v2/dashboards/:id/members/:userID"
|
|
|
|
dashboardsIDOwnersPath = "/api/v2/dashboards/:id/owners"
|
|
|
|
dashboardsIDOwnersIDPath = "/api/v2/dashboards/:id/owners/:userID"
|
|
|
|
dashboardsIDLabelsPath = "/api/v2/dashboards/:id/labels"
|
|
|
|
dashboardsIDLabelsNamePath = "/api/v2/dashboards/:id/labels/:name"
|
2018-09-17 02:39:46 +00:00
|
|
|
)
|
|
|
|
|
2018-05-31 14:44:23 +00:00
|
|
|
// NewDashboardHandler returns a new instance of DashboardHandler.
|
2018-12-17 12:43:06 +00:00
|
|
|
func NewDashboardHandler(mappingService platform.UserResourceMappingService, labelService platform.LabelService, userService platform.UserService) *DashboardHandler {
|
2018-05-31 14:44:23 +00:00
|
|
|
h := &DashboardHandler{
|
2019-01-08 00:37:16 +00:00
|
|
|
Router: NewRouter(),
|
|
|
|
Logger: zap.NewNop(),
|
|
|
|
|
2018-10-16 21:49:35 +00:00
|
|
|
UserResourceMappingService: mappingService,
|
2018-12-03 16:07:08 +00:00
|
|
|
LabelService: labelService,
|
2018-12-17 12:43:06 +00:00
|
|
|
UserService: userService,
|
2018-05-31 14:44:23 +00:00
|
|
|
}
|
|
|
|
|
2018-09-17 02:39:46 +00:00
|
|
|
h.HandlerFunc("POST", dashboardsPath, h.handlePostDashboard)
|
|
|
|
h.HandlerFunc("GET", dashboardsPath, h.handleGetDashboards)
|
|
|
|
h.HandlerFunc("GET", dashboardsIDPath, h.handleGetDashboard)
|
2018-11-02 18:21:14 +00:00
|
|
|
h.HandlerFunc("GET", dashboardsIDLogPath, h.handleGetDashboardLog)
|
2018-09-17 02:39:46 +00:00
|
|
|
h.HandlerFunc("DELETE", dashboardsIDPath, h.handleDeleteDashboard)
|
|
|
|
h.HandlerFunc("PATCH", dashboardsIDPath, h.handlePatchDashboard)
|
2018-05-31 14:44:23 +00:00
|
|
|
|
2018-09-17 02:39:46 +00:00
|
|
|
h.HandlerFunc("PUT", dashboardsIDCellsPath, h.handlePutDashboardCells)
|
|
|
|
h.HandlerFunc("POST", dashboardsIDCellsPath, h.handlePostDashboardCell)
|
|
|
|
h.HandlerFunc("DELETE", dashboardsIDCellsIDPath, h.handleDeleteDashboardCell)
|
|
|
|
h.HandlerFunc("PATCH", dashboardsIDCellsIDPath, h.handlePatchDashboardCell)
|
2018-09-27 22:50:32 +00:00
|
|
|
|
2019-01-04 19:12:35 +00:00
|
|
|
h.HandlerFunc("GET", dashboardsIDCellsIDViewPath, h.handleGetDashboardCellView)
|
|
|
|
h.HandlerFunc("PATCH", dashboardsIDCellsIDViewPath, h.handlePatchDashboardCellView)
|
|
|
|
|
2018-12-28 23:02:19 +00:00
|
|
|
h.HandlerFunc("POST", dashboardsIDMembersPath, newPostMemberHandler(h.UserResourceMappingService, h.UserService, platform.DashboardsResource, platform.Member))
|
|
|
|
h.HandlerFunc("GET", dashboardsIDMembersPath, newGetMembersHandler(h.UserResourceMappingService, h.UserService, platform.DashboardsResource, platform.Member))
|
2018-10-01 09:03:37 +00:00
|
|
|
h.HandlerFunc("DELETE", dashboardsIDMembersIDPath, newDeleteMemberHandler(h.UserResourceMappingService, platform.Member))
|
2018-09-27 22:50:32 +00:00
|
|
|
|
2018-12-28 23:02:19 +00:00
|
|
|
h.HandlerFunc("POST", dashboardsIDOwnersPath, newPostMemberHandler(h.UserResourceMappingService, h.UserService, platform.DashboardsResource, platform.Owner))
|
|
|
|
h.HandlerFunc("GET", dashboardsIDOwnersPath, newGetMembersHandler(h.UserResourceMappingService, h.UserService, platform.DashboardsResource, platform.Owner))
|
2018-10-01 09:03:37 +00:00
|
|
|
h.HandlerFunc("DELETE", dashboardsIDOwnersIDPath, newDeleteMemberHandler(h.UserResourceMappingService, platform.Owner))
|
2018-12-03 16:07:08 +00:00
|
|
|
|
|
|
|
h.HandlerFunc("GET", dashboardsIDLabelsPath, newGetLabelsHandler(h.LabelService))
|
|
|
|
h.HandlerFunc("POST", dashboardsIDLabelsPath, newPostLabelHandler(h.LabelService))
|
|
|
|
h.HandlerFunc("DELETE", dashboardsIDLabelsNamePath, newDeleteLabelHandler(h.LabelService))
|
2018-12-18 09:45:49 +00:00
|
|
|
h.HandlerFunc("PATCH", dashboardsIDLabelsNamePath, newPatchLabelHandler(h.LabelService))
|
2018-12-03 16:07:08 +00:00
|
|
|
|
2018-05-31 14:44:23 +00:00
|
|
|
return h
|
|
|
|
}
|
|
|
|
|
2018-08-07 20:10:05 +00:00
|
|
|
type dashboardLinks struct {
|
2019-01-09 22:43:29 +00:00
|
|
|
Self string `json:"self"`
|
2019-01-14 03:54:44 +00:00
|
|
|
Members string `json:"members"`
|
|
|
|
Owners string `json:"owners"`
|
2019-01-09 22:43:29 +00:00
|
|
|
Cells string `json:"cells"`
|
|
|
|
Log string `json:"log"`
|
|
|
|
Labels string `json:"labels"`
|
|
|
|
Organization string `json:"org"`
|
2018-08-07 20:10:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
type dashboardResponse struct {
|
|
|
|
platform.Dashboard
|
2019-01-02 19:17:28 +00:00
|
|
|
Cells []dashboardCellResponse `json:"cells"`
|
|
|
|
Labels []platform.Label `json:"labels"`
|
|
|
|
Links dashboardLinks `json:"links"`
|
2018-08-07 20:10:05 +00:00
|
|
|
}
|
|
|
|
|
2018-09-17 02:39:46 +00:00
|
|
|
func (d dashboardResponse) toPlatform() *platform.Dashboard {
|
2018-12-11 18:38:24 +00:00
|
|
|
var cells []*platform.Cell
|
|
|
|
if len(d.Cells) > 0 {
|
|
|
|
cells = make([]*platform.Cell, len(d.Cells))
|
|
|
|
}
|
2018-09-17 02:39:46 +00:00
|
|
|
for i := range d.Cells {
|
2018-12-11 18:38:24 +00:00
|
|
|
cells[i] = d.Cells[i].toPlatform()
|
2018-09-17 02:39:46 +00:00
|
|
|
}
|
|
|
|
return &platform.Dashboard{
|
2019-01-09 22:43:29 +00:00
|
|
|
ID: d.ID,
|
|
|
|
OrganizationID: d.OrganizationID,
|
|
|
|
Name: d.Name,
|
|
|
|
Meta: d.Meta,
|
|
|
|
Cells: cells,
|
2018-09-17 02:39:46 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-01-02 19:17:28 +00:00
|
|
|
func newDashboardResponse(d *platform.Dashboard, labels []*platform.Label) dashboardResponse {
|
2018-08-07 20:10:05 +00:00
|
|
|
res := dashboardResponse{
|
|
|
|
Links: dashboardLinks{
|
2019-01-09 22:43:29 +00:00
|
|
|
Self: fmt.Sprintf("/api/v2/dashboards/%s", d.ID),
|
2019-01-14 03:54:44 +00:00
|
|
|
Members: fmt.Sprintf("/api/v2/dashboards/%s/members", d.ID),
|
|
|
|
Owners: fmt.Sprintf("/api/v2/dashboards/%s/owners", d.ID),
|
2019-01-09 22:43:29 +00:00
|
|
|
Cells: fmt.Sprintf("/api/v2/dashboards/%s/cells", d.ID),
|
|
|
|
Log: fmt.Sprintf("/api/v2/dashboards/%s/log", d.ID),
|
|
|
|
Labels: fmt.Sprintf("/api/v2/dashboards/%s/labels", d.ID),
|
|
|
|
Organization: fmt.Sprintf("/api/v2/orgs/%s", d.OrganizationID),
|
2018-08-07 20:10:05 +00:00
|
|
|
},
|
|
|
|
Dashboard: *d,
|
2019-01-02 19:17:28 +00:00
|
|
|
Labels: []platform.Label{},
|
2018-08-07 20:10:05 +00:00
|
|
|
Cells: []dashboardCellResponse{},
|
|
|
|
}
|
|
|
|
|
2019-01-02 19:17:28 +00:00
|
|
|
for _, l := range labels {
|
|
|
|
res.Labels = append(res.Labels, *l)
|
|
|
|
}
|
|
|
|
|
2018-08-07 20:10:05 +00:00
|
|
|
for _, cell := range d.Cells {
|
|
|
|
res.Cells = append(res.Cells, newDashboardCellResponse(d.ID, cell))
|
|
|
|
}
|
|
|
|
|
|
|
|
return res
|
|
|
|
}
|
|
|
|
|
|
|
|
type dashboardCellResponse struct {
|
|
|
|
platform.Cell
|
|
|
|
Links map[string]string `json:"links"`
|
|
|
|
}
|
|
|
|
|
2018-09-17 02:39:46 +00:00
|
|
|
func (c dashboardCellResponse) toPlatform() *platform.Cell {
|
|
|
|
return &c.Cell
|
|
|
|
}
|
|
|
|
|
2018-08-07 20:10:05 +00:00
|
|
|
func newDashboardCellResponse(dashboardID platform.ID, c *platform.Cell) dashboardCellResponse {
|
|
|
|
return dashboardCellResponse{
|
|
|
|
Cell: *c,
|
|
|
|
Links: map[string]string{
|
2018-09-26 08:49:19 +00:00
|
|
|
"self": fmt.Sprintf("/api/v2/dashboards/%s/cells/%s", dashboardID, c.ID),
|
2019-01-04 19:12:35 +00:00
|
|
|
"view": fmt.Sprintf("/api/v2/dashboards/%s/cells/%s/view", dashboardID, c.ID),
|
2018-08-07 20:10:05 +00:00
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
type dashboardCellsResponse struct {
|
|
|
|
Cells []dashboardCellResponse `json:"cells"`
|
|
|
|
Links map[string]string `json:"links"`
|
|
|
|
}
|
|
|
|
|
|
|
|
func newDashboardCellsResponse(dashboardID platform.ID, cs []*platform.Cell) dashboardCellsResponse {
|
|
|
|
res := dashboardCellsResponse{
|
|
|
|
Cells: []dashboardCellResponse{},
|
|
|
|
Links: map[string]string{
|
2018-09-26 08:49:19 +00:00
|
|
|
"self": fmt.Sprintf("/api/v2/dashboards/%s/cells", dashboardID),
|
2018-08-07 20:10:05 +00:00
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, cell := range cs {
|
|
|
|
res.Cells = append(res.Cells, newDashboardCellResponse(dashboardID, cell))
|
|
|
|
}
|
|
|
|
|
|
|
|
return res
|
|
|
|
}
|
|
|
|
|
2019-01-04 19:12:35 +00:00
|
|
|
func newDashboardCellViewResponse(dashID, cellID platform.ID, v *platform.View) viewResponse {
|
|
|
|
return viewResponse{
|
|
|
|
Links: viewLinks{
|
|
|
|
Self: fmt.Sprintf("/api/v2/dashboards/%s/cells/%s", dashID, cellID),
|
|
|
|
},
|
|
|
|
View: *v,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-02 18:21:14 +00:00
|
|
|
type operationLogResponse struct {
|
|
|
|
Links map[string]string `json:"links"`
|
|
|
|
Log []*operationLogEntryResponse `json:"log"`
|
|
|
|
}
|
|
|
|
|
|
|
|
func newDashboardLogResponse(id platform.ID, es []*platform.OperationLogEntry) *operationLogResponse {
|
|
|
|
log := make([]*operationLogEntryResponse, 0, len(es))
|
|
|
|
for _, e := range es {
|
|
|
|
log = append(log, newOperationLogEntryResponse(e))
|
|
|
|
}
|
|
|
|
return &operationLogResponse{
|
|
|
|
Links: map[string]string{
|
|
|
|
"self": fmt.Sprintf("/api/v2/dashboards/%s/log", id),
|
|
|
|
},
|
|
|
|
Log: log,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
type operationLogEntryResponse struct {
|
|
|
|
Links map[string]string `json:"links"`
|
|
|
|
*platform.OperationLogEntry
|
|
|
|
}
|
|
|
|
|
|
|
|
func newOperationLogEntryResponse(e *platform.OperationLogEntry) *operationLogEntryResponse {
|
|
|
|
links := map[string]string{}
|
|
|
|
if e.UserID.Valid() {
|
|
|
|
links["user"] = fmt.Sprintf("/api/v2/users/%s", e.UserID)
|
|
|
|
}
|
|
|
|
return &operationLogEntryResponse{
|
|
|
|
Links: links,
|
|
|
|
OperationLogEntry: e,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-08-07 20:10:05 +00:00
|
|
|
// handleGetDashboards returns all dashboards within the store.
|
|
|
|
func (h *DashboardHandler) handleGetDashboards(w http.ResponseWriter, r *http.Request) {
|
|
|
|
ctx := r.Context()
|
2018-09-17 02:39:46 +00:00
|
|
|
req, err := decodeGetDashboardsRequest(ctx, r)
|
|
|
|
if err != nil {
|
|
|
|
EncodeError(ctx, err, w)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2018-10-05 00:18:01 +00:00
|
|
|
if req.ownerID != nil {
|
|
|
|
filter := platform.UserResourceMappingFilter{
|
2018-12-28 23:02:19 +00:00
|
|
|
UserID: *req.ownerID,
|
|
|
|
UserType: platform.Owner,
|
|
|
|
Resource: platform.DashboardsResource,
|
2018-10-05 00:18:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
mappings, _, err := h.UserResourceMappingService.FindUserResourceMappings(ctx, filter)
|
|
|
|
if err != nil {
|
|
|
|
EncodeError(ctx, errors.InternalErrorf("Error loading dashboard owners: %v", err), w)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, mapping := range mappings {
|
|
|
|
req.filter.IDs = append(req.filter.IDs, &mapping.ResourceID)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-10-16 13:52:52 +00:00
|
|
|
dashboards, _, err := h.DashboardService.FindDashboards(ctx, req.filter, req.opts)
|
2018-08-07 20:10:05 +00:00
|
|
|
if err != nil {
|
2018-12-11 18:38:24 +00:00
|
|
|
EncodeError(ctx, err, w)
|
2018-08-07 20:10:05 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2019-01-09 22:43:29 +00:00
|
|
|
if err := encodeResponse(ctx, w, http.StatusOK, newGetDashboardsResponse(ctx, dashboards, req.filter, h.LabelService)); err != nil {
|
2018-12-20 16:07:46 +00:00
|
|
|
logEncodingError(h.Logger, r, err)
|
2018-08-07 20:10:05 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-09-17 02:39:46 +00:00
|
|
|
type getDashboardsRequest struct {
|
2018-10-04 23:30:51 +00:00
|
|
|
filter platform.DashboardFilter
|
2018-10-16 13:52:52 +00:00
|
|
|
opts platform.FindOptions
|
2018-10-04 23:30:51 +00:00
|
|
|
ownerID *platform.ID
|
2018-09-17 02:39:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func decodeGetDashboardsRequest(ctx context.Context, r *http.Request) (*getDashboardsRequest, error) {
|
|
|
|
qp := r.URL.Query()
|
|
|
|
req := &getDashboardsRequest{}
|
|
|
|
|
2018-10-09 13:13:50 +00:00
|
|
|
initialID := platform.InvalidID()
|
2018-10-08 08:56:18 +00:00
|
|
|
if ids, ok := qp["id"]; ok {
|
2018-10-04 23:30:51 +00:00
|
|
|
for _, id := range ids {
|
2018-10-09 13:13:50 +00:00
|
|
|
i := initialID
|
2018-10-04 23:30:51 +00:00
|
|
|
if err := i.DecodeFromString(id); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2018-10-09 13:13:50 +00:00
|
|
|
req.filter.IDs = append(req.filter.IDs, &i)
|
2018-09-17 02:39:46 +00:00
|
|
|
}
|
2019-01-09 22:43:29 +00:00
|
|
|
} else if ownerID := qp.Get("ownerID"); ownerID != "" {
|
2018-10-09 13:13:50 +00:00
|
|
|
req.ownerID = &initialID
|
2019-01-09 22:43:29 +00:00
|
|
|
if err := req.ownerID.DecodeFromString(ownerID); err != nil {
|
2018-10-02 21:48:14 +00:00
|
|
|
return nil, err
|
|
|
|
}
|
2019-01-09 22:43:29 +00:00
|
|
|
} else if orgID := qp.Get("orgID"); orgID != "" {
|
|
|
|
id := platform.InvalidID()
|
|
|
|
if err := id.DecodeFromString(orgID); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
req.filter.OrganizationID = &id
|
|
|
|
} else if org := qp.Get("org"); org != "" {
|
|
|
|
req.filter.Organization = &org
|
2018-10-02 21:48:14 +00:00
|
|
|
}
|
|
|
|
|
2018-10-16 13:52:52 +00:00
|
|
|
req.opts = platform.DefaultDashboardFindOptions
|
|
|
|
|
|
|
|
if sortBy := qp.Get("sortBy"); sortBy != "" {
|
|
|
|
req.opts.SortBy = sortBy
|
|
|
|
}
|
|
|
|
|
2018-09-17 02:39:46 +00:00
|
|
|
return req, nil
|
|
|
|
}
|
|
|
|
|
2018-08-07 20:10:05 +00:00
|
|
|
type getDashboardsLinks struct {
|
|
|
|
Self string `json:"self"`
|
|
|
|
}
|
|
|
|
|
|
|
|
type getDashboardsResponse struct {
|
|
|
|
Links getDashboardsLinks `json:"links"`
|
|
|
|
Dashboards []dashboardResponse `json:"dashboards"`
|
|
|
|
}
|
|
|
|
|
2018-09-17 02:39:46 +00:00
|
|
|
func (d getDashboardsResponse) toPlatform() []*platform.Dashboard {
|
|
|
|
res := make([]*platform.Dashboard, len(d.Dashboards))
|
|
|
|
for i := range d.Dashboards {
|
|
|
|
res[i] = d.Dashboards[i].toPlatform()
|
|
|
|
}
|
|
|
|
return res
|
|
|
|
}
|
|
|
|
|
2019-01-09 22:43:29 +00:00
|
|
|
func newGetDashboardsResponse(ctx context.Context, dashboards []*platform.Dashboard, filter platform.DashboardFilter, labelService platform.LabelService) getDashboardsResponse {
|
|
|
|
qp := url.Values{}
|
|
|
|
for _, id := range filter.IDs {
|
|
|
|
qp.Add("id", id.String())
|
|
|
|
}
|
|
|
|
|
|
|
|
if filter.OrganizationID != nil {
|
|
|
|
qp.Add("orgID", filter.OrganizationID.String())
|
|
|
|
}
|
|
|
|
|
|
|
|
if filter.Organization != nil {
|
|
|
|
qp.Add("org", *filter.Organization)
|
|
|
|
}
|
|
|
|
|
|
|
|
self := "/api/v2/dashboards"
|
|
|
|
if len(qp) > 0 {
|
|
|
|
self = self + "?" + qp.Encode()
|
|
|
|
}
|
|
|
|
|
2018-08-07 20:10:05 +00:00
|
|
|
res := getDashboardsResponse{
|
|
|
|
Links: getDashboardsLinks{
|
2019-01-09 22:43:29 +00:00
|
|
|
Self: self,
|
2018-08-07 20:10:05 +00:00
|
|
|
},
|
|
|
|
Dashboards: make([]dashboardResponse, 0, len(dashboards)),
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, dashboard := range dashboards {
|
2018-12-11 18:38:24 +00:00
|
|
|
if dashboard != nil {
|
2019-01-02 19:17:28 +00:00
|
|
|
labels, _ := labelService.FindLabels(ctx, platform.LabelFilter{ResourceID: dashboard.ID})
|
|
|
|
res.Dashboards = append(res.Dashboards, newDashboardResponse(dashboard, labels))
|
2018-12-11 18:38:24 +00:00
|
|
|
}
|
2018-08-07 20:10:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return res
|
|
|
|
}
|
|
|
|
|
|
|
|
// handlePostDashboard creates a new dashboard.
|
2018-05-31 14:44:23 +00:00
|
|
|
func (h *DashboardHandler) handlePostDashboard(w http.ResponseWriter, r *http.Request) {
|
|
|
|
ctx := r.Context()
|
|
|
|
|
|
|
|
req, err := decodePostDashboardRequest(ctx, r)
|
|
|
|
if err != nil {
|
2018-06-28 19:32:16 +00:00
|
|
|
EncodeError(ctx, err, w)
|
2018-05-31 14:44:23 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
if err := h.DashboardService.CreateDashboard(ctx, req.Dashboard); err != nil {
|
2018-08-07 20:10:05 +00:00
|
|
|
EncodeError(ctx, errors.InternalErrorf("Error loading dashboards: %v", err), w)
|
2018-05-31 14:44:23 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2019-01-02 19:17:28 +00:00
|
|
|
if err := encodeResponse(ctx, w, http.StatusCreated, newDashboardResponse(req.Dashboard, []*platform.Label{})); err != nil {
|
2018-12-20 16:07:46 +00:00
|
|
|
logEncodingError(h.Logger, r, err)
|
2018-05-31 14:44:23 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
type postDashboardRequest struct {
|
|
|
|
Dashboard *platform.Dashboard
|
|
|
|
}
|
|
|
|
|
|
|
|
func decodePostDashboardRequest(ctx context.Context, r *http.Request) (*postDashboardRequest, error) {
|
2018-08-07 20:10:05 +00:00
|
|
|
c := &platform.Dashboard{}
|
|
|
|
if err := json.NewDecoder(r.Body).Decode(c); err != nil {
|
2018-05-31 14:44:23 +00:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return &postDashboardRequest{
|
2018-08-07 20:10:05 +00:00
|
|
|
Dashboard: c,
|
2018-05-31 14:44:23 +00:00
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
2018-08-07 20:10:05 +00:00
|
|
|
// hanldeGetDashboard retrieves a dashboard by ID.
|
2018-05-31 14:44:23 +00:00
|
|
|
func (h *DashboardHandler) handleGetDashboard(w http.ResponseWriter, r *http.Request) {
|
|
|
|
ctx := r.Context()
|
|
|
|
|
|
|
|
req, err := decodeGetDashboardRequest(ctx, r)
|
|
|
|
if err != nil {
|
2018-06-28 19:32:16 +00:00
|
|
|
EncodeError(ctx, err, w)
|
2018-05-31 14:44:23 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2018-08-07 20:10:05 +00:00
|
|
|
dashboard, err := h.DashboardService.FindDashboardByID(ctx, req.DashboardID)
|
2018-05-31 14:44:23 +00:00
|
|
|
if err != nil {
|
2018-06-28 19:32:16 +00:00
|
|
|
EncodeError(ctx, err, w)
|
2018-05-31 14:44:23 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2019-01-02 19:17:28 +00:00
|
|
|
labels, err := h.LabelService.FindLabels(ctx, platform.LabelFilter{ResourceID: dashboard.ID})
|
|
|
|
if err != nil {
|
|
|
|
EncodeError(ctx, err, w)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := encodeResponse(ctx, w, http.StatusOK, newDashboardResponse(dashboard, labels)); err != nil {
|
2018-12-20 16:07:46 +00:00
|
|
|
logEncodingError(h.Logger, r, err)
|
2018-05-31 14:44:23 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
type getDashboardRequest struct {
|
|
|
|
DashboardID platform.ID
|
|
|
|
}
|
|
|
|
|
|
|
|
func decodeGetDashboardRequest(ctx context.Context, r *http.Request) (*getDashboardRequest, error) {
|
|
|
|
params := httprouter.ParamsFromContext(ctx)
|
|
|
|
id := params.ByName("id")
|
|
|
|
if id == "" {
|
2018-08-07 20:10:05 +00:00
|
|
|
return nil, errors.InvalidDataf("url missing id")
|
2018-05-31 14:44:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
var i platform.ID
|
|
|
|
if err := i.DecodeFromString(id); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2018-08-07 20:10:05 +00:00
|
|
|
return &getDashboardRequest{
|
|
|
|
DashboardID: i,
|
|
|
|
}, nil
|
2018-05-31 14:44:23 +00:00
|
|
|
}
|
|
|
|
|
2018-11-02 18:21:14 +00:00
|
|
|
// hanldeGetDashboardLog retrieves a dashboard log by the dashboards ID.
|
|
|
|
func (h *DashboardHandler) handleGetDashboardLog(w http.ResponseWriter, r *http.Request) {
|
|
|
|
ctx := r.Context()
|
|
|
|
|
|
|
|
req, err := decodeGetDashboardLogRequest(ctx, r)
|
|
|
|
if err != nil {
|
|
|
|
EncodeError(ctx, err, w)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
log, _, err := h.DashboardOperationLogService.GetDashboardOperationLog(ctx, req.DashboardID, req.opts)
|
|
|
|
if err != nil {
|
|
|
|
EncodeError(ctx, err, w)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := encodeResponse(ctx, w, http.StatusOK, newDashboardLogResponse(req.DashboardID, log)); err != nil {
|
2018-12-20 16:07:46 +00:00
|
|
|
logEncodingError(h.Logger, r, err)
|
2018-11-02 18:21:14 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
type getDashboardLogRequest struct {
|
|
|
|
DashboardID platform.ID
|
|
|
|
opts platform.FindOptions
|
|
|
|
}
|
|
|
|
|
|
|
|
func decodeGetDashboardLogRequest(ctx context.Context, r *http.Request) (*getDashboardLogRequest, error) {
|
|
|
|
params := httprouter.ParamsFromContext(ctx)
|
|
|
|
id := params.ByName("id")
|
|
|
|
if id == "" {
|
|
|
|
return nil, errors.InvalidDataf("url missing id")
|
|
|
|
}
|
|
|
|
|
|
|
|
var i platform.ID
|
|
|
|
if err := i.DecodeFromString(id); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
opts := platform.DefaultOperationLogFindOptions
|
|
|
|
qp := r.URL.Query()
|
|
|
|
if v := qp.Get("desc"); v == "false" {
|
|
|
|
opts.Descending = false
|
|
|
|
}
|
|
|
|
if v := qp.Get("limit"); v != "" {
|
|
|
|
i, err := strconv.Atoi(v)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
opts.Limit = i
|
|
|
|
}
|
|
|
|
if v := qp.Get("offset"); v != "" {
|
|
|
|
i, err := strconv.Atoi(v)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
opts.Offset = i
|
|
|
|
}
|
|
|
|
|
|
|
|
return &getDashboardLogRequest{
|
|
|
|
DashboardID: i,
|
|
|
|
opts: opts,
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
2018-08-07 20:10:05 +00:00
|
|
|
// handleDeleteDashboard removes a dashboard by ID.
|
2018-05-31 14:44:23 +00:00
|
|
|
func (h *DashboardHandler) handleDeleteDashboard(w http.ResponseWriter, r *http.Request) {
|
|
|
|
ctx := r.Context()
|
|
|
|
|
|
|
|
req, err := decodeDeleteDashboardRequest(ctx, r)
|
|
|
|
if err != nil {
|
2018-06-28 19:32:16 +00:00
|
|
|
EncodeError(ctx, err, w)
|
2018-05-31 14:44:23 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := h.DashboardService.DeleteDashboard(ctx, req.DashboardID); err != nil {
|
2018-06-28 19:32:16 +00:00
|
|
|
EncodeError(ctx, err, w)
|
2018-05-31 14:44:23 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2018-08-07 20:10:05 +00:00
|
|
|
w.WriteHeader(http.StatusNoContent)
|
2018-05-31 14:44:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
type deleteDashboardRequest struct {
|
|
|
|
DashboardID platform.ID
|
|
|
|
}
|
|
|
|
|
|
|
|
func decodeDeleteDashboardRequest(ctx context.Context, r *http.Request) (*deleteDashboardRequest, error) {
|
|
|
|
params := httprouter.ParamsFromContext(ctx)
|
|
|
|
id := params.ByName("id")
|
|
|
|
if id == "" {
|
2018-08-07 20:10:05 +00:00
|
|
|
return nil, errors.InvalidDataf("url missing id")
|
2018-05-31 14:44:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
var i platform.ID
|
|
|
|
if err := i.DecodeFromString(id); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2018-08-07 20:10:05 +00:00
|
|
|
return &deleteDashboardRequest{
|
|
|
|
DashboardID: i,
|
|
|
|
}, nil
|
2018-05-31 14:44:23 +00:00
|
|
|
}
|
|
|
|
|
2018-08-07 20:10:05 +00:00
|
|
|
// handlePatchDashboard updates a dashboard.
|
2018-05-31 14:44:23 +00:00
|
|
|
func (h *DashboardHandler) handlePatchDashboard(w http.ResponseWriter, r *http.Request) {
|
|
|
|
ctx := r.Context()
|
|
|
|
|
|
|
|
req, err := decodePatchDashboardRequest(ctx, r)
|
|
|
|
if err != nil {
|
2018-06-28 19:32:16 +00:00
|
|
|
EncodeError(ctx, err, w)
|
2018-05-31 14:44:23 +00:00
|
|
|
return
|
|
|
|
}
|
2018-08-07 20:10:05 +00:00
|
|
|
dashboard, err := h.DashboardService.UpdateDashboard(ctx, req.DashboardID, req.Upd)
|
2018-05-31 14:44:23 +00:00
|
|
|
if err != nil {
|
2018-06-28 19:32:16 +00:00
|
|
|
EncodeError(ctx, err, w)
|
2018-05-31 14:44:23 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2019-01-02 19:17:28 +00:00
|
|
|
labels, err := h.LabelService.FindLabels(ctx, platform.LabelFilter{ResourceID: dashboard.ID})
|
|
|
|
if err != nil {
|
|
|
|
EncodeError(ctx, err, w)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := encodeResponse(ctx, w, http.StatusOK, newDashboardResponse(dashboard, labels)); err != nil {
|
2018-12-20 16:07:46 +00:00
|
|
|
logEncodingError(h.Logger, r, err)
|
2018-05-31 14:44:23 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
type patchDashboardRequest struct {
|
|
|
|
DashboardID platform.ID
|
2018-08-07 20:10:05 +00:00
|
|
|
Upd platform.DashboardUpdate
|
2018-05-31 14:44:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func decodePatchDashboardRequest(ctx context.Context, r *http.Request) (*patchDashboardRequest, error) {
|
2018-08-07 20:10:05 +00:00
|
|
|
req := &patchDashboardRequest{}
|
|
|
|
upd := platform.DashboardUpdate{}
|
|
|
|
if err := json.NewDecoder(r.Body).Decode(&upd); err != nil {
|
|
|
|
return nil, errors.MalformedDataf(err.Error())
|
|
|
|
}
|
|
|
|
req.Upd = upd
|
|
|
|
|
2018-05-31 14:44:23 +00:00
|
|
|
params := httprouter.ParamsFromContext(ctx)
|
|
|
|
id := params.ByName("id")
|
|
|
|
if id == "" {
|
2018-08-07 20:10:05 +00:00
|
|
|
return nil, errors.InvalidDataf("url missing id")
|
2018-05-31 14:44:23 +00:00
|
|
|
}
|
|
|
|
var i platform.ID
|
|
|
|
if err := i.DecodeFromString(id); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2018-08-07 20:10:05 +00:00
|
|
|
req.DashboardID = i
|
|
|
|
|
|
|
|
if err := req.Valid(); err != nil {
|
|
|
|
return nil, errors.MalformedDataf(err.Error())
|
2018-05-31 14:44:23 +00:00
|
|
|
}
|
|
|
|
|
2018-08-07 20:10:05 +00:00
|
|
|
return req, nil
|
2018-05-31 14:44:23 +00:00
|
|
|
}
|
|
|
|
|
2018-08-07 20:10:05 +00:00
|
|
|
// Valid validates that the dashboard ID is non zero valued and update has expected values set.
|
|
|
|
func (r *patchDashboardRequest) Valid() error {
|
2018-09-12 16:07:18 +00:00
|
|
|
if !r.DashboardID.Valid() {
|
2018-08-07 20:10:05 +00:00
|
|
|
return fmt.Errorf("missing dashboard ID")
|
2018-05-31 14:44:23 +00:00
|
|
|
}
|
|
|
|
|
2018-12-11 18:38:24 +00:00
|
|
|
if pe := r.Upd.Valid(); pe != nil {
|
|
|
|
return pe
|
|
|
|
}
|
|
|
|
return nil
|
2018-05-31 14:44:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
type postDashboardCellRequest struct {
|
2018-08-07 20:10:05 +00:00
|
|
|
dashboardID platform.ID
|
|
|
|
cell *platform.Cell
|
|
|
|
opts platform.AddDashboardCellOptions
|
2018-05-31 14:44:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func decodePostDashboardCellRequest(ctx context.Context, r *http.Request) (*postDashboardCellRequest, error) {
|
2018-08-07 20:10:05 +00:00
|
|
|
req := &postDashboardCellRequest{}
|
|
|
|
|
2018-05-31 14:44:23 +00:00
|
|
|
params := httprouter.ParamsFromContext(ctx)
|
|
|
|
id := params.ByName("id")
|
|
|
|
if id == "" {
|
2018-08-07 20:10:05 +00:00
|
|
|
return nil, errors.InvalidDataf("url missing id")
|
2018-05-31 14:44:23 +00:00
|
|
|
}
|
2018-08-07 20:10:05 +00:00
|
|
|
if err := req.dashboardID.DecodeFromString(id); err != nil {
|
2018-05-31 14:44:23 +00:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2018-08-07 20:10:05 +00:00
|
|
|
bs, err := ioutil.ReadAll(r.Body)
|
|
|
|
if err != nil {
|
2018-05-31 14:44:23 +00:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2018-08-07 20:10:05 +00:00
|
|
|
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
|
|
|
|
}
|
|
|
|
|
|
|
|
return req, nil
|
2018-05-31 14:44:23 +00:00
|
|
|
}
|
|
|
|
|
2018-08-07 20:10:05 +00:00
|
|
|
// handlePostDashboardCell creates a dashboard cell.
|
|
|
|
func (h *DashboardHandler) handlePostDashboardCell(w http.ResponseWriter, r *http.Request) {
|
2018-05-31 14:44:23 +00:00
|
|
|
ctx := r.Context()
|
|
|
|
|
2018-08-07 20:10:05 +00:00
|
|
|
req, err := decodePostDashboardCellRequest(ctx, r)
|
2018-05-31 14:44:23 +00:00
|
|
|
if err != nil {
|
2018-06-28 19:32:16 +00:00
|
|
|
EncodeError(ctx, err, w)
|
2018-05-31 14:44:23 +00:00
|
|
|
return
|
|
|
|
}
|
2018-08-07 20:10:05 +00:00
|
|
|
if err := h.DashboardService.AddDashboardCell(ctx, req.dashboardID, req.cell, req.opts); err != nil {
|
2018-06-28 19:32:16 +00:00
|
|
|
EncodeError(ctx, err, w)
|
2018-05-31 14:44:23 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2018-08-07 20:10:05 +00:00
|
|
|
if err := encodeResponse(ctx, w, http.StatusCreated, newDashboardCellResponse(req.dashboardID, req.cell)); err != nil {
|
2018-12-20 16:07:46 +00:00
|
|
|
logEncodingError(h.Logger, r, err)
|
2018-05-31 14:44:23 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
type putDashboardCellRequest struct {
|
2018-08-07 20:10:05 +00:00
|
|
|
dashboardID platform.ID
|
|
|
|
cells []*platform.Cell
|
2018-05-31 14:44:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func decodePutDashboardCellRequest(ctx context.Context, r *http.Request) (*putDashboardCellRequest, error) {
|
|
|
|
req := &putDashboardCellRequest{}
|
|
|
|
|
2018-08-07 20:10:05 +00:00
|
|
|
params := httprouter.ParamsFromContext(ctx)
|
2018-05-31 14:44:23 +00:00
|
|
|
id := params.ByName("id")
|
|
|
|
if id == "" {
|
2018-08-07 20:10:05 +00:00
|
|
|
return nil, errors.InvalidDataf("url missing id")
|
2018-05-31 14:44:23 +00:00
|
|
|
}
|
2018-08-07 20:10:05 +00:00
|
|
|
if err := req.dashboardID.DecodeFromString(id); err != nil {
|
2018-05-31 14:44:23 +00:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2018-08-07 20:10:05 +00:00
|
|
|
req.cells = []*platform.Cell{}
|
|
|
|
if err := json.NewDecoder(r.Body).Decode(&req.cells); err != nil {
|
2018-05-31 14:44:23 +00:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return req, nil
|
|
|
|
}
|
|
|
|
|
2018-08-07 20:10:05 +00:00
|
|
|
// handlePutDashboardCells replaces a dashboards cells.
|
|
|
|
func (h *DashboardHandler) handlePutDashboardCells(w http.ResponseWriter, r *http.Request) {
|
2018-05-31 14:44:23 +00:00
|
|
|
ctx := r.Context()
|
|
|
|
|
2018-08-07 20:10:05 +00:00
|
|
|
req, err := decodePutDashboardCellRequest(ctx, r)
|
2018-05-31 14:44:23 +00:00
|
|
|
if err != nil {
|
2018-06-28 19:32:16 +00:00
|
|
|
EncodeError(ctx, err, w)
|
2018-05-31 14:44:23 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2018-08-07 20:10:05 +00:00
|
|
|
if err := h.DashboardService.ReplaceDashboardCells(ctx, req.dashboardID, req.cells); err != nil {
|
2018-06-28 19:32:16 +00:00
|
|
|
EncodeError(ctx, err, w)
|
2018-05-31 14:44:23 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2018-08-07 20:10:05 +00:00
|
|
|
if err := encodeResponse(ctx, w, http.StatusCreated, newDashboardCellsResponse(req.dashboardID, req.cells)); err != nil {
|
2018-12-20 16:07:46 +00:00
|
|
|
logEncodingError(h.Logger, r, err)
|
2018-08-07 20:10:05 +00:00
|
|
|
return
|
|
|
|
}
|
2018-05-31 14:44:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
type deleteDashboardCellRequest struct {
|
2018-08-07 20:10:05 +00:00
|
|
|
dashboardID platform.ID
|
|
|
|
cellID platform.ID
|
2018-05-31 14:44:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func decodeDeleteDashboardCellRequest(ctx context.Context, r *http.Request) (*deleteDashboardCellRequest, error) {
|
|
|
|
req := &deleteDashboardCellRequest{}
|
|
|
|
|
2018-08-07 20:10:05 +00:00
|
|
|
params := httprouter.ParamsFromContext(ctx)
|
2018-05-31 14:44:23 +00:00
|
|
|
id := params.ByName("id")
|
|
|
|
if id == "" {
|
2018-08-07 20:10:05 +00:00
|
|
|
return nil, errors.InvalidDataf("url missing id")
|
2018-05-31 14:44:23 +00:00
|
|
|
}
|
2018-08-07 20:10:05 +00:00
|
|
|
if err := req.dashboardID.DecodeFromString(id); err != nil {
|
2018-05-31 14:44:23 +00:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2018-08-07 20:10:05 +00:00
|
|
|
cellID := params.ByName("cellID")
|
2018-05-31 14:44:23 +00:00
|
|
|
if cellID == "" {
|
2018-08-07 20:10:05 +00:00
|
|
|
return nil, errors.InvalidDataf("url missing cellID")
|
2018-05-31 14:44:23 +00:00
|
|
|
}
|
2018-08-07 20:10:05 +00:00
|
|
|
if err := req.cellID.DecodeFromString(cellID); err != nil {
|
2018-05-31 14:44:23 +00:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return req, nil
|
|
|
|
}
|
|
|
|
|
2019-01-04 19:12:35 +00:00
|
|
|
type getDashboardCellViewRequest struct {
|
|
|
|
dashboardID platform.ID
|
|
|
|
cellID platform.ID
|
|
|
|
}
|
|
|
|
|
|
|
|
func decodeGetDashboardCellViewRequest(ctx context.Context, r *http.Request) (*getDashboardCellViewRequest, error) {
|
|
|
|
req := &getDashboardCellViewRequest{}
|
|
|
|
|
|
|
|
params := httprouter.ParamsFromContext(ctx)
|
|
|
|
id := params.ByName("id")
|
|
|
|
if id == "" {
|
2019-01-07 21:47:16 +00:00
|
|
|
return nil, platform.NewError(platform.WithErrorMsg("url missing id"), platform.WithErrorCode(platform.EInvalid))
|
2019-01-04 19:12:35 +00:00
|
|
|
}
|
|
|
|
if err := req.dashboardID.DecodeFromString(id); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
cellID := params.ByName("cellID")
|
|
|
|
if cellID == "" {
|
2019-01-07 21:47:16 +00:00
|
|
|
return nil, platform.NewError(platform.WithErrorMsg("url missing cellID"), platform.WithErrorCode(platform.EInvalid))
|
2019-01-04 19:12:35 +00:00
|
|
|
}
|
|
|
|
if err := req.cellID.DecodeFromString(cellID); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return req, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (h *DashboardHandler) handleGetDashboardCellView(w http.ResponseWriter, r *http.Request) {
|
|
|
|
ctx := r.Context()
|
|
|
|
|
|
|
|
req, err := decodeGetDashboardCellViewRequest(ctx, r)
|
|
|
|
if err != nil {
|
|
|
|
EncodeError(ctx, err, w)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
view, err := h.DashboardService.GetDashboardCellView(ctx, req.dashboardID, req.cellID)
|
|
|
|
if err != nil {
|
|
|
|
EncodeError(ctx, err, w)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := encodeResponse(ctx, w, http.StatusOK, newDashboardCellViewResponse(req.dashboardID, req.cellID, view)); err != nil {
|
|
|
|
logEncodingError(h.Logger, r, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
type patchDashboardCellViewRequest struct {
|
|
|
|
dashboardID platform.ID
|
|
|
|
cellID platform.ID
|
|
|
|
upd platform.ViewUpdate
|
|
|
|
}
|
|
|
|
|
|
|
|
func decodePatchDashboardCellViewRequest(ctx context.Context, r *http.Request) (*patchDashboardCellViewRequest, error) {
|
|
|
|
req := &patchDashboardCellViewRequest{}
|
|
|
|
|
|
|
|
params := httprouter.ParamsFromContext(ctx)
|
|
|
|
id := params.ByName("id")
|
|
|
|
if id == "" {
|
2019-01-07 21:47:16 +00:00
|
|
|
return nil, platform.NewError(platform.WithErrorMsg("url missing id"), platform.WithErrorCode(platform.EInvalid))
|
2019-01-04 19:12:35 +00:00
|
|
|
}
|
|
|
|
if err := req.dashboardID.DecodeFromString(id); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
cellID := params.ByName("cellID")
|
|
|
|
if cellID == "" {
|
2019-01-07 21:47:16 +00:00
|
|
|
return nil, platform.NewError(platform.WithErrorMsg("url missing cellID"), platform.WithErrorCode(platform.EInvalid))
|
2019-01-04 19:12:35 +00:00
|
|
|
}
|
|
|
|
if err := req.cellID.DecodeFromString(cellID); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := json.NewDecoder(r.Body).Decode(&req.upd); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return req, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (h *DashboardHandler) handlePatchDashboardCellView(w http.ResponseWriter, r *http.Request) {
|
|
|
|
ctx := r.Context()
|
|
|
|
|
|
|
|
req, err := decodePatchDashboardCellViewRequest(ctx, r)
|
|
|
|
if err != nil {
|
|
|
|
EncodeError(ctx, err, w)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
view, err := h.DashboardService.UpdateDashboardCellView(ctx, req.dashboardID, req.cellID, req.upd)
|
|
|
|
if err != nil {
|
|
|
|
EncodeError(ctx, err, w)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := encodeResponse(ctx, w, http.StatusOK, newDashboardCellViewResponse(req.dashboardID, req.cellID, view)); err != nil {
|
|
|
|
logEncodingError(h.Logger, r, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-08-07 20:10:05 +00:00
|
|
|
// handleDeleteDashboardCell deletes a dashboard cell.
|
|
|
|
func (h *DashboardHandler) handleDeleteDashboardCell(w http.ResponseWriter, r *http.Request) {
|
|
|
|
ctx := r.Context()
|
2018-05-31 14:44:23 +00:00
|
|
|
|
2018-08-07 20:10:05 +00:00
|
|
|
req, err := decodeDeleteDashboardCellRequest(ctx, r)
|
2018-05-31 14:44:23 +00:00
|
|
|
if err != nil {
|
2018-08-07 20:10:05 +00:00
|
|
|
EncodeError(ctx, err, w)
|
|
|
|
return
|
2018-05-31 14:44:23 +00:00
|
|
|
}
|
2018-08-07 20:10:05 +00:00
|
|
|
if err := h.DashboardService.RemoveDashboardCell(ctx, req.dashboardID, req.cellID); err != nil {
|
|
|
|
EncodeError(ctx, err, w)
|
|
|
|
return
|
2018-05-31 14:44:23 +00:00
|
|
|
}
|
|
|
|
|
2018-08-07 20:10:05 +00:00
|
|
|
w.WriteHeader(http.StatusNoContent)
|
2018-05-31 14:44:23 +00:00
|
|
|
}
|
|
|
|
|
2018-08-07 20:10:05 +00:00
|
|
|
type patchDashboardCellRequest struct {
|
|
|
|
dashboardID platform.ID
|
|
|
|
cellID platform.ID
|
|
|
|
upd platform.CellUpdate
|
2018-05-31 14:44:23 +00:00
|
|
|
}
|
|
|
|
|
2018-08-07 20:10:05 +00:00
|
|
|
func decodePatchDashboardCellRequest(ctx context.Context, r *http.Request) (*patchDashboardCellRequest, error) {
|
|
|
|
req := &patchDashboardCellRequest{}
|
2018-05-31 14:44:23 +00:00
|
|
|
|
2018-08-07 20:10:05 +00:00
|
|
|
params := httprouter.ParamsFromContext(ctx)
|
|
|
|
id := params.ByName("id")
|
|
|
|
if id == "" {
|
2018-12-11 18:38:24 +00:00
|
|
|
return nil, &platform.Error{
|
|
|
|
Code: platform.EInvalid,
|
|
|
|
Msg: "url missing id",
|
|
|
|
}
|
2018-05-31 14:44:23 +00:00
|
|
|
}
|
2018-08-07 20:10:05 +00:00
|
|
|
if err := req.dashboardID.DecodeFromString(id); err != nil {
|
2018-05-31 14:44:23 +00:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2018-08-07 20:10:05 +00:00
|
|
|
cellID := params.ByName("cellID")
|
|
|
|
if cellID == "" {
|
2018-12-11 18:38:24 +00:00
|
|
|
return nil, &platform.Error{
|
|
|
|
Code: platform.EInvalid,
|
|
|
|
Msg: "cannot provide empty cell id",
|
|
|
|
}
|
2018-05-31 14:44:23 +00:00
|
|
|
}
|
2018-08-07 20:10:05 +00:00
|
|
|
if err := req.cellID.DecodeFromString(cellID); err != nil {
|
2018-05-31 14:44:23 +00:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2018-08-07 20:10:05 +00:00
|
|
|
if err := json.NewDecoder(r.Body).Decode(&req.upd); err != nil {
|
2018-12-11 18:38:24 +00:00
|
|
|
return nil, &platform.Error{
|
|
|
|
Code: platform.EInvalid,
|
|
|
|
Err: err,
|
|
|
|
}
|
2018-05-31 14:44:23 +00:00
|
|
|
}
|
|
|
|
|
2018-12-11 18:38:24 +00:00
|
|
|
if pe := req.upd.Valid(); pe != nil {
|
|
|
|
return nil, pe
|
2018-10-25 23:05:12 +00:00
|
|
|
}
|
|
|
|
|
2018-08-07 20:10:05 +00:00
|
|
|
return req, nil
|
2018-05-31 14:44:23 +00:00
|
|
|
}
|
|
|
|
|
2018-08-07 20:10:05 +00:00
|
|
|
// handlePatchDashboardCell updates a dashboard cell.
|
|
|
|
func (h *DashboardHandler) handlePatchDashboardCell(w http.ResponseWriter, r *http.Request) {
|
|
|
|
ctx := r.Context()
|
2018-05-31 14:44:23 +00:00
|
|
|
|
2018-08-07 20:10:05 +00:00
|
|
|
req, err := decodePatchDashboardCellRequest(ctx, r)
|
2018-05-31 14:44:23 +00:00
|
|
|
if err != nil {
|
2018-08-07 20:10:05 +00:00
|
|
|
EncodeError(ctx, err, w)
|
|
|
|
return
|
2018-05-31 14:44:23 +00:00
|
|
|
}
|
2018-08-07 20:10:05 +00:00
|
|
|
cell, err := h.DashboardService.UpdateDashboardCell(ctx, req.dashboardID, req.cellID, req.upd)
|
2018-05-31 14:44:23 +00:00
|
|
|
if err != nil {
|
2018-08-07 20:10:05 +00:00
|
|
|
EncodeError(ctx, err, w)
|
|
|
|
return
|
2018-05-31 14:44:23 +00:00
|
|
|
}
|
|
|
|
|
2018-08-07 20:10:05 +00:00
|
|
|
if err := encodeResponse(ctx, w, http.StatusOK, newDashboardCellResponse(req.dashboardID, cell)); err != nil {
|
2018-12-20 16:07:46 +00:00
|
|
|
logEncodingError(h.Logger, r, err)
|
2018-08-07 20:10:05 +00:00
|
|
|
return
|
2018-05-31 14:44:23 +00:00
|
|
|
}
|
|
|
|
}
|
2018-09-17 02:39:46 +00:00
|
|
|
|
|
|
|
// DashboardService is a dashboard service over HTTP to the influxdb server.
|
|
|
|
type DashboardService struct {
|
|
|
|
Addr string
|
|
|
|
Token string
|
|
|
|
InsecureSkipVerify bool
|
2018-12-11 18:38:24 +00:00
|
|
|
// OpPrefix is the op prefix for certain errors op.
|
|
|
|
OpPrefix string
|
2018-09-17 02:39:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// FindDashboardByID returns a single dashboard by ID.
|
|
|
|
func (s *DashboardService) FindDashboardByID(ctx context.Context, id platform.ID) (*platform.Dashboard, error) {
|
|
|
|
path := dashboardIDPath(id)
|
|
|
|
url, err := newURL(s.Addr, path)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
req, err := http.NewRequest("GET", url.String(), nil)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
SetToken(s.Token, req)
|
|
|
|
hc := newClient(url.Scheme, s.InsecureSkipVerify)
|
|
|
|
|
|
|
|
resp, err := hc.Do(req)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2018-12-11 18:38:24 +00:00
|
|
|
if err := CheckError(resp, true); err != nil {
|
2018-09-17 02:39:46 +00:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
var dr dashboardResponse
|
|
|
|
if err := json.NewDecoder(resp.Body).Decode(&dr); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
dashboard := dr.toPlatform()
|
|
|
|
return dashboard, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// FindDashboards returns a list of dashboards that match filter and the total count of matching dashboards.
|
|
|
|
// Additional options provide pagination & sorting.
|
2018-10-16 13:52:52 +00:00
|
|
|
func (s *DashboardService) FindDashboards(ctx context.Context, filter platform.DashboardFilter, opts platform.FindOptions) ([]*platform.Dashboard, int, error) {
|
2018-12-11 18:38:24 +00:00
|
|
|
dashboards := []*platform.Dashboard{}
|
2018-09-17 02:39:46 +00:00
|
|
|
url, err := newURL(s.Addr, dashboardsPath)
|
2018-12-11 18:38:24 +00:00
|
|
|
|
2018-09-17 02:39:46 +00:00
|
|
|
if err != nil {
|
2018-12-11 18:38:24 +00:00
|
|
|
return dashboards, 0, err
|
2018-09-17 02:39:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
qp := url.Query()
|
2018-10-16 13:52:52 +00:00
|
|
|
qp.Add("sortBy", opts.SortBy)
|
2018-10-08 08:56:18 +00:00
|
|
|
for _, id := range filter.IDs {
|
|
|
|
qp.Add("id", id.String())
|
2018-09-17 02:39:46 +00:00
|
|
|
}
|
2019-01-09 22:43:29 +00:00
|
|
|
if filter.OrganizationID != nil {
|
|
|
|
qp.Add("orgID", filter.OrganizationID.String())
|
|
|
|
}
|
2018-09-17 02:39:46 +00:00
|
|
|
url.RawQuery = qp.Encode()
|
|
|
|
|
|
|
|
req, err := http.NewRequest("GET", url.String(), nil)
|
|
|
|
if err != nil {
|
2018-12-11 18:38:24 +00:00
|
|
|
return dashboards, 0, err
|
2018-09-17 02:39:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
SetToken(s.Token, req)
|
|
|
|
hc := newClient(url.Scheme, s.InsecureSkipVerify)
|
|
|
|
|
|
|
|
resp, err := hc.Do(req)
|
|
|
|
if err != nil {
|
2018-12-11 18:38:24 +00:00
|
|
|
return dashboards, 0, err
|
2018-09-17 02:39:46 +00:00
|
|
|
}
|
|
|
|
|
2018-12-11 18:38:24 +00:00
|
|
|
if err := CheckError(resp, true); err != nil {
|
|
|
|
return dashboards, 0, err
|
2018-09-17 02:39:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
var dr getDashboardsResponse
|
|
|
|
if err := json.NewDecoder(resp.Body).Decode(&dr); err != nil {
|
2018-12-11 18:38:24 +00:00
|
|
|
return dashboards, 0, err
|
2018-09-17 02:39:46 +00:00
|
|
|
}
|
|
|
|
|
2018-12-11 18:38:24 +00:00
|
|
|
dashboards = dr.toPlatform()
|
2018-09-17 02:39:46 +00:00
|
|
|
return dashboards, len(dashboards), nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// CreateDashboard creates a new dashboard and sets b.ID with the new identifier.
|
|
|
|
func (s *DashboardService) CreateDashboard(ctx context.Context, d *platform.Dashboard) error {
|
|
|
|
url, err := newURL(s.Addr, dashboardsPath)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
b, err := json.Marshal(d)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
req, err := http.NewRequest("POST", url.String(), bytes.NewReader(b))
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
req.Header.Set("Content-Type", "application/json")
|
|
|
|
SetToken(s.Token, req)
|
|
|
|
|
|
|
|
hc := newClient(url.Scheme, s.InsecureSkipVerify)
|
|
|
|
|
|
|
|
resp, err := hc.Do(req)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2018-12-11 18:38:24 +00:00
|
|
|
if err := CheckError(resp, true); err != nil {
|
2018-09-17 02:39:46 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2018-10-16 13:52:52 +00:00
|
|
|
if err := json.NewDecoder(resp.Body).Decode(d); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
2018-09-17 02:39:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// UpdateDashboard updates a single dashboard with changeset.
|
|
|
|
// Returns the new dashboard state after update.
|
|
|
|
func (s *DashboardService) UpdateDashboard(ctx context.Context, id platform.ID, upd platform.DashboardUpdate) (*platform.Dashboard, error) {
|
2018-12-11 18:38:24 +00:00
|
|
|
//op := s.OpPrefix + platform.OpUpdateDashboard
|
2018-09-17 02:39:46 +00:00
|
|
|
u, err := newURL(s.Addr, dashboardIDPath(id))
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
b, err := json.Marshal(upd)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
req, err := http.NewRequest("PATCH", u.String(), bytes.NewReader(b))
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
req.Header.Set("Content-Type", "application/json")
|
|
|
|
SetToken(s.Token, req)
|
|
|
|
|
|
|
|
hc := newClient(u.Scheme, s.InsecureSkipVerify)
|
|
|
|
|
|
|
|
resp, err := hc.Do(req)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2018-12-11 18:38:24 +00:00
|
|
|
if err := CheckError(resp, true); err != nil {
|
2018-09-17 02:39:46 +00:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
var d platform.Dashboard
|
|
|
|
if err := json.NewDecoder(resp.Body).Decode(&d); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
defer resp.Body.Close()
|
|
|
|
if len(d.Cells) == 0 {
|
|
|
|
d.Cells = nil
|
|
|
|
}
|
|
|
|
|
|
|
|
return &d, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// DeleteDashboard removes a dashboard by ID.
|
|
|
|
func (s *DashboardService) DeleteDashboard(ctx context.Context, id platform.ID) error {
|
|
|
|
u, err := newURL(s.Addr, dashboardIDPath(id))
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
req, err := http.NewRequest("DELETE", u.String(), nil)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
SetToken(s.Token, req)
|
|
|
|
|
|
|
|
hc := newClient(u.Scheme, s.InsecureSkipVerify)
|
|
|
|
resp, err := hc.Do(req)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2018-12-11 18:38:24 +00:00
|
|
|
return CheckError(resp, true)
|
2018-09-17 02:39:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// AddDashboardCell adds a cell to a dashboard.
|
|
|
|
func (s *DashboardService) AddDashboardCell(ctx context.Context, id platform.ID, c *platform.Cell, opts platform.AddDashboardCellOptions) error {
|
|
|
|
url, err := newURL(s.Addr, cellPath(id))
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2018-09-26 11:51:36 +00:00
|
|
|
// fixme > in case c does not contain a valid ID this errors out
|
2018-09-17 02:39:46 +00:00
|
|
|
b, err := json.Marshal(c)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
req, err := http.NewRequest("POST", url.String(), bytes.NewReader(b))
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
req.Header.Set("Content-Type", "application/json")
|
|
|
|
SetToken(s.Token, req)
|
|
|
|
|
|
|
|
hc := newClient(url.Scheme, s.InsecureSkipVerify)
|
|
|
|
resp, err := hc.Do(req)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2018-12-11 18:38:24 +00:00
|
|
|
if err := CheckError(resp, true); err != nil {
|
2018-09-17 02:39:46 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO (goller): deal with the dashboard cell options
|
|
|
|
return json.NewDecoder(resp.Body).Decode(c)
|
|
|
|
}
|
|
|
|
|
|
|
|
// RemoveDashboardCell removes a dashboard.
|
|
|
|
func (s *DashboardService) RemoveDashboardCell(ctx context.Context, dashboardID, cellID platform.ID) error {
|
|
|
|
u, err := newURL(s.Addr, dashboardCellIDPath(dashboardID, cellID))
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
req, err := http.NewRequest("DELETE", u.String(), nil)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
SetToken(s.Token, req)
|
|
|
|
|
|
|
|
hc := newClient(u.Scheme, s.InsecureSkipVerify)
|
|
|
|
resp, err := hc.Do(req)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2018-12-11 18:38:24 +00:00
|
|
|
return CheckError(resp, true)
|
2018-09-17 02:39:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// UpdateDashboardCell replaces the dashboard cell with the provided ID.
|
|
|
|
func (s *DashboardService) UpdateDashboardCell(ctx context.Context, dashboardID, cellID platform.ID, upd platform.CellUpdate) (*platform.Cell, error) {
|
2018-12-11 18:38:24 +00:00
|
|
|
op := s.OpPrefix + platform.OpUpdateDashboardCell
|
2018-10-25 23:05:12 +00:00
|
|
|
if err := upd.Valid(); err != nil {
|
2018-12-11 18:38:24 +00:00
|
|
|
return nil, &platform.Error{
|
|
|
|
Op: op,
|
|
|
|
Err: err,
|
|
|
|
}
|
2018-10-25 23:05:12 +00:00
|
|
|
}
|
|
|
|
|
2018-09-17 02:39:46 +00:00
|
|
|
u, err := newURL(s.Addr, dashboardCellIDPath(dashboardID, cellID))
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
b, err := json.Marshal(upd)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
req, err := http.NewRequest("PATCH", u.String(), bytes.NewReader(b))
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
req.Header.Set("Content-Type", "application/json")
|
|
|
|
SetToken(s.Token, req)
|
|
|
|
|
|
|
|
hc := newClient(u.Scheme, s.InsecureSkipVerify)
|
|
|
|
|
|
|
|
resp, err := hc.Do(req)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2018-12-11 18:38:24 +00:00
|
|
|
if err := CheckError(resp, true); err != nil {
|
2018-09-17 02:39:46 +00:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
var c platform.Cell
|
|
|
|
if err := json.NewDecoder(resp.Body).Decode(&c); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
defer resp.Body.Close()
|
|
|
|
|
|
|
|
return &c, nil
|
|
|
|
}
|
|
|
|
|
2019-01-04 19:12:35 +00:00
|
|
|
// GetDashboardCellView retrieves the view for a dashboard cell.
|
|
|
|
func (s *DashboardService) GetDashboardCellView(ctx context.Context, dashboardID, cellID platform.ID) (*platform.View, error) {
|
|
|
|
u, err := newURL(s.Addr, cellViewPath(dashboardID, cellID))
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
req, err := http.NewRequest("GET", u.String(), nil)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
req.Header.Set("Content-Type", "application/json")
|
|
|
|
SetToken(s.Token, req)
|
|
|
|
|
|
|
|
hc := newClient(u.Scheme, s.InsecureSkipVerify)
|
|
|
|
|
|
|
|
resp, err := hc.Do(req)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := CheckError(resp, true); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
res := viewResponse{}
|
|
|
|
if err := json.NewDecoder(resp.Body).Decode(&res); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
defer resp.Body.Close()
|
|
|
|
|
|
|
|
return &res.View, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// UpdateDashboardCellView updates the view for a dashboard cell.
|
|
|
|
func (s *DashboardService) UpdateDashboardCellView(ctx context.Context, dashboardID, cellID platform.ID, upd platform.ViewUpdate) (*platform.View, error) {
|
|
|
|
u, err := newURL(s.Addr, cellViewPath(dashboardID, cellID))
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
b, err := json.Marshal(upd)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
req, err := http.NewRequest("PATCH", u.String(), bytes.NewReader(b))
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
req.Header.Set("Content-Type", "application/json")
|
|
|
|
SetToken(s.Token, req)
|
|
|
|
|
|
|
|
hc := newClient(u.Scheme, s.InsecureSkipVerify)
|
|
|
|
|
|
|
|
resp, err := hc.Do(req)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := CheckError(resp, true); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
res := viewResponse{}
|
|
|
|
if err := json.NewDecoder(resp.Body).Decode(&res); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
defer resp.Body.Close()
|
|
|
|
|
|
|
|
return &res.View, nil
|
|
|
|
}
|
|
|
|
|
2018-09-17 02:39:46 +00:00
|
|
|
// ReplaceDashboardCells replaces all cells in a dashboard
|
|
|
|
func (s *DashboardService) ReplaceDashboardCells(ctx context.Context, id platform.ID, cs []*platform.Cell) error {
|
|
|
|
u, err := newURL(s.Addr, cellPath(id))
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO(goller): I think this should be {"cells":[]}
|
|
|
|
b, err := json.Marshal(cs)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
req, err := http.NewRequest("PUT", u.String(), bytes.NewReader(b))
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
req.Header.Set("Content-Type", "application/json")
|
|
|
|
SetToken(s.Token, req)
|
|
|
|
|
|
|
|
hc := newClient(u.Scheme, s.InsecureSkipVerify)
|
|
|
|
|
|
|
|
resp, err := hc.Do(req)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2018-12-11 18:38:24 +00:00
|
|
|
if err := CheckError(resp, true); err != nil {
|
2018-09-17 02:39:46 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
cells := dashboardCellsResponse{}
|
|
|
|
if err := json.NewDecoder(resp.Body).Decode(&cells); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
defer resp.Body.Close()
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func dashboardIDPath(id platform.ID) string {
|
|
|
|
return path.Join(dashboardsPath, id.String())
|
|
|
|
}
|
|
|
|
|
|
|
|
func cellPath(id platform.ID) string {
|
|
|
|
return path.Join(dashboardIDPath(id), "cells")
|
|
|
|
}
|
|
|
|
|
2019-01-04 19:12:35 +00:00
|
|
|
func cellViewPath(dashboardID, cellID platform.ID) string {
|
|
|
|
return path.Join(dashboardIDPath(dashboardID), "cells", cellID.String(), "view")
|
|
|
|
}
|
|
|
|
|
2018-09-17 02:39:46 +00:00
|
|
|
func dashboardCellIDPath(id platform.ID, cellID platform.ID) string {
|
|
|
|
return path.Join(cellPath(id), cellID.String())
|
|
|
|
}
|