// hanldeGetDashboard retrieves a dashboard by ID.
540472
func (h *DashboardHandler) handleGetDashboard(w http.ResponseWriter, r *http.Request) {
	ctx := r.Context()

	req, err := decodeGetDashboardRequest(ctx, r)
	if err != nil {
		EncodeError(ctx, err, w)
		return
	}

	dashboard, err := h.DashboardService.FindDashboardByID(ctx, req.DashboardID)
	if err != nil {
		EncodeError(ctx, err, w)
		return
	}

	labels, err := h.LabelService.FindResourceLabels(ctx, platform.LabelMappingFilter{ResourceID: dashboard.ID})
	if err != nil {
		EncodeError(ctx, err, w)
		return
	}

	if err := encodeResponse(ctx, w, http.StatusOK, newDashboardResponse(dashboard, labels)); err != nil {
		logEncodingError(h.Logger, r, err)
		return
	}
}
794309
func (cmd *CreateFolderCommand) GetDashboardModel(orgId int64, userId int64) *Dashboard {
	dashFolder := NewDashboardFolder(strings.TrimSpace(cmd.Title))
	dashFolder.OrgId = orgId
	dashFolder.SetUid(strings.TrimSpace(cmd.Uid))

	if userId == 0 {
		userId = -1
	}

	dashFolder.CreatedBy = userId
	dashFolder.UpdatedBy = userId
	dashFolder.UpdateSlug()

	return dashFolder
}
724395
func deployDashboard(client *sshClient, network string, conf *config, config *dashboardInfos, nocache bool) ([]byte, error) {
	// Generate the content to upload to the server
	workdir := fmt.Sprintf("%d", rand.Int63())
	files := make(map[string][]byte)

	dockerfile := new(bytes.Buffer)
	template.Must(template.New("").Parse(dashboardDockerfile)).Execute(dockerfile, map[string]interface{}{
		"Network": network,
	})
	files[filepath.Join(workdir, "Dockerfile")] = dockerfile.Bytes()

	composefile := new(bytes.Buffer)
	template.Must(template.New("").Parse(dashboardComposefile)).Execute(composefile, map[string]interface{}{
		"Network":      network,
		"Port":         config.port,
		"VHost":        config.host,
		"EthstatsPage": config.ethstats,
		"ExplorerPage": config.explorer,
		"WalletPage":   config.wallet,
		"FaucetPage":   config.faucet,
	})
	files[filepath.Join(workdir, "docker-compose.yaml")] = composefile.Bytes()

	statsLogin := fmt.Sprintf("yournode:%s", conf.ethstats)
	if !config.trusted {
		statsLogin = ""
	}
	indexfile := new(bytes.Buffer)
	bootCpp := make([]string, len(conf.bootnodes))
	for i, boot := range conf.bootnodes {
		bootCpp[i] = "required:" + strings.TrimPrefix(boot, "enode://")
	}
	bootHarmony := make([]string, len(conf.bootnodes))
	for i, boot := range conf.bootnodes {
		bootHarmony[i] = fmt.Sprintf("-Dpeer.active.%d.url=%s", i, boot)
	}
	bootPython := make([]string, len(conf.bootnodes))
	for i, boot := range conf.bootnodes {
		bootPython[i] = "'" + boot + "'"
	}
	template.Must(template.New("").Parse(dashboardContent)).Execute(indexfile, map[string]interface{}{
		"Network":           network,
		"NetworkID":         conf.Genesis.Config.ChainID,
		"NetworkTitle":      strings.Title(network),
		"EthstatsPage":      config.ethstats,
		"ExplorerPage":      config.explorer,
		"WalletPage":        config.wallet,
		"FaucetPage":        config.faucet,
		"GethGenesis":       network + ".json",
		"Bootnodes":         conf.bootnodes,
		"BootnodesFlat":     strings.Join(conf.bootnodes, ","),
		"Ethstats":          statsLogin,
		"Ethash":            conf.Genesis.Config.Ethash != nil,
		"CppGenesis":        network + "-cpp.json",
		"CppBootnodes":      strings.Join(bootCpp, " "),
		"HarmonyGenesis":    network + "-harmony.json",
		"HarmonyBootnodes":  strings.Join(bootHarmony, " "),
		"ParityGenesis":     network + "-parity.json",
		"PythonGenesis":     network + "-python.json",
		"PythonBootnodes":   strings.Join(bootPython, ","),
		"Homestead":         conf.Genesis.Config.HomesteadBlock,
		"Tangerine":         conf.Genesis.Config.EIP150Block,
		"Spurious":          conf.Genesis.Config.EIP155Block,
		"Byzantium":         conf.Genesis.Config.ByzantiumBlock,
		"Constantinople":    conf.Genesis.Config.ConstantinopleBlock,
		"ConstantinopleFix": conf.Genesis.Config.PetersburgBlock,
	})
	files[filepath.Join(workdir, "index.html")] = indexfile.Bytes()

	// Marshal the genesis spec files for go-ethereum and all the other clients
	genesis, _ := conf.Genesis.MarshalJSON()
	files[filepath.Join(workdir, network+".json")] = genesis

	if conf.Genesis.Config.Ethash != nil {
		cppSpec, err := newAlethGenesisSpec(network, conf.Genesis)
		if err != nil {
			return nil, err
		}
		cppSpecJSON, _ := json.Marshal(cppSpec)
		files[filepath.Join(workdir, network+"-cpp.json")] = cppSpecJSON

		harmonySpecJSON, _ := conf.Genesis.MarshalJSON()
		files[filepath.Join(workdir, network+"-harmony.json")] = harmonySpecJSON

		paritySpec, err := newParityChainSpec(network, conf.Genesis, conf.bootnodes)
		if err != nil {
			return nil, err
		}
		paritySpecJSON, _ := json.Marshal(paritySpec)
		files[filepath.Join(workdir, network+"-parity.json")] = paritySpecJSON

		pyethSpec, err := newPyEthereumGenesisSpec(network, conf.Genesis)
		if err != nil {
			return nil, err
		}
		pyethSpecJSON, _ := json.Marshal(pyethSpec)
		files[filepath.Join(workdir, network+"-python.json")] = pyethSpecJSON
	} else {
		for _, client := range []string{"cpp", "harmony", "parity", "python"} {
			files[filepath.Join(workdir, network+"-"+client+".json")] = []byte{}
		}
	}
	files[filepath.Join(workdir, "puppeth.png")] = dashboardMascot

	// Upload the deployment files to the remote server (and clean up afterwards)
	if out, err := client.Upload(files); err != nil {
		return out, err
	}
	defer client.Run("rm -rf " + workdir)

	// Build and deploy the dashboard service
	if nocache {
		return nil, client.Stream(fmt.Sprintf("cd %s && docker-compose -p %s build --pull --no-cache && docker-compose -p %s up -d --force-recreate --timeout 60", workdir, network, network))
	}
	return nil, client.Stream(fmt.Sprintf("cd %s && docker-compose -p %s up -d --build --force-recreate --timeout 60", workdir, network))
}
906039
func (s *DashboardService) FindDashboards(ctx context.Context, filter influxdb.DashboardFilter, opt influxdb.FindOptions) ([]*influxdb.Dashboard, int, error) {
	// TODO: we'll likely want to push this operation into the database eventually since fetching the whole list of data
	// will likely be expensive.
	bs, _, err := s.s.FindDashboards(ctx, filter, opt)
	if err != nil {
		return nil, 0, err
	}

	// This filters without allocating
	// https://github.com/golang/go/wiki/SliceTricks#filtering-without-allocating
	dashboards := bs[:0]
	for _, b := range bs {
		err := authorizeReadDashboard(ctx, b.OrganizationID, b.ID)
		if err != nil && influxdb.ErrorCode(err) != influxdb.EUnauthorized {
			return nil, 0, err
		}

		if influxdb.ErrorCode(err) == influxdb.EUnauthorized {
			continue
		}

		dashboards = append(dashboards, b)
	}

	return dashboards, len(dashboards), nil
}
608396
func (s *Service) FindDashboards(ctx context.Context, filter platform.DashboardFilter, opts platform.FindOptions) ([]*platform.Dashboard, int, error) {
	var ds []*platform.Dashboard
	op := OpPrefix + platform.OpFindDashboards
	if len(filter.IDs) == 1 {
		d, err := s.FindDashboardByID(ctx, *filter.IDs[0])
		if err != nil && platform.ErrorCode(err) != platform.ENotFound {
			return ds, 0, &platform.Error{
				Err: err,
				Op:  op,
			}
		}
		if d == nil {
			return ds, 0, nil
		}
		return []*platform.Dashboard{d}, 1, nil
	}

	var err error
	filterF := filterDashboardFn(filter)
	s.dashboardKV.Range(func(k, v interface{}) bool {
		d, ok := v.(*platform.Dashboard)
		if !ok {
			return false
		}

		if filterF(d) {
			ds = append(ds, d)
		}
		return true
	})

	platform.SortDashboards(opts.SortBy, ds)

	return ds, len(ds), err
}
506910
func (s *DashboardService) DeleteDashboard(ctx context.Context, id influxdb.ID) error {
	b, err := s.s.FindDashboardByID(ctx, id)
	if err != nil {
		return err
	}

	if err := authorizeWriteDashboard(ctx, b.OrganizationID, id); err != nil {
		return err
	}

	return s.s.DeleteDashboard(ctx, id)
}
508763
func (cmd *SaveDashboardCommand) GetDashboardModel() *Dashboard {
	dash := NewDashboardFromJson(cmd.Dashboard)
	userId := cmd.UserId

	if userId == 0 {
		userId = -1
	}

	dash.UpdatedBy = userId
	dash.OrgId = cmd.OrgId
	dash.PluginId = cmd.PluginId
	dash.IsFolder = cmd.IsFolder
	dash.FolderId = cmd.FolderId
	dash.UpdateSlug()
	return dash
}
450077
func (dr *dashboardServiceImpl) DeleteDashboard(dashboardId int64, orgId int64) error {
	return dr.deleteDashboard(dashboardId, orgId, true)
}
727888
func (s *Service) ReplaceDashboard(w http.ResponseWriter, r *http.Request) {
	ctx := r.Context()
	idParam, err := paramID("id", r)
	if err != nil {
		msg := fmt.Sprintf("Could not parse dashboard ID: %s", err)
		Error(w, http.StatusInternalServerError, msg, s.Logger)
	}
	id := chronograf.DashboardID(idParam)

	_, err = s.Store.Dashboards(ctx).Get(ctx, id)
	if err != nil {
		Error(w, http.StatusNotFound, fmt.Sprintf("ID %d not found", id), s.Logger)
		return
	}

	var req chronograf.Dashboard
	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		invalidJSON(w, s.Logger)
		return
	}
	req.ID = id

	defaultOrg, err := s.Store.Organizations(ctx).DefaultOrganization(ctx)
	if err != nil {
		unknownErrorWithMessage(w, err, s.Logger)
		return
	}

	if err := ValidDashboardRequest(&req, defaultOrg.ID); err != nil {
		invalidData(w, err, s.Logger)
		return
	}

	if err := s.Store.Dashboards(ctx).Update(ctx, req); err != nil {
		msg := fmt.Sprintf("Error updating dashboard ID %d: %v", id, err)
		Error(w, http.StatusInternalServerError, msg, s.Logger)
		return
	}

	res := newDashboardResponse(req)
	encodeJSON(w, http.StatusOK, res, s.Logger)
}
76032
func (s *Service) RemoveDashboardCell(ctx context.Context, dashboardID platform.ID, cellID platform.ID) error {
	op := OpPrefix + platform.OpRemoveDashboardCell
	d, err := s.FindDashboardByID(ctx, dashboardID)
	if err != nil {
		return &platform.Error{
			Err: err,
			Op:  op,
		}
	}

	idx := -1
	for i, cell := range d.Cells {
		if cell.ID == cellID {
			idx = i
			break
		}
	}
	if idx == -1 {
		return &platform.Error{
			Code: platform.ENotFound,
			Op:   op,
			Msg:  platform.ErrCellNotFound,
		}
	}

	if err := s.DeleteView(ctx, d.Cells[idx].ID); err != nil {
		return &platform.Error{
			Err: err,
			Op:  op,
		}
	}

	d.Cells = append(d.Cells[:idx], d.Cells[idx+1:]...)
	return s.PutDashboardWithMeta(ctx, d)

}
426126
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 {
		logEncodingError(h.Logger, r, err)
		return
	}
}
211323
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
	}

	// fixme > in case c does not contain a valid ID this errors out
	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
	}

	if err := CheckError(resp, true); err != nil {
		return err
	}

	// TODO (goller): deal with the dashboard cell options
	return json.NewDecoder(resp.Body).Decode(c)
}
643209
func (s *ProjectsService) ListDashboards(projectName string) (*[]DashboardInfo, *Response, error) {
	u := fmt.Sprintf("projects/%s/dashboards/", url.QueryEscape(projectName))

	req, err := s.client.NewRequest("GET", u, nil)
	if err != nil {
		return nil, nil, err
	}

	v := new([]DashboardInfo)
	resp, err := s.client.Do(req, v)
	if err != nil {
		return nil, resp, err
	}

	return v, resp, err
}
180152
func (h *DashboardHandler) handlePostDashboard(w http.ResponseWriter, r *http.Request) {
	ctx := r.Context()

	req, err := decodePostDashboardRequest(ctx, r)
	if err != nil {
		EncodeError(ctx, err, w)
		return
	}
	if err := h.DashboardService.CreateDashboard(ctx, req.Dashboard); err != nil {
		EncodeError(ctx, errors.InternalErrorf("Error loading dashboards: %v", err), w)
		return
	}

	if err := encodeResponse(ctx, w, http.StatusCreated, newDashboardResponse(req.Dashboard, []*platform.Label{})); err != nil {
		logEncodingError(h.Logger, r, err)
		return
	}
}
826517
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
	}
	defer resp.Body.Close()

	return CheckError(resp)
}
466047
func (s *Service) GetDashboardCellView(ctx context.Context, dashboardID, cellID influxdb.ID) (*influxdb.View, error) {
	var v *influxdb.View
	err := s.kv.View(ctx, func(tx Tx) error {
		view, err := s.findDashboardCellView(ctx, tx, dashboardID, cellID)
		if err != nil {
			return err
		}

		v = view
		return nil
	})

	if err != nil {
		return nil, &influxdb.Error{
			Err: err,
		}
	}

	return v, nil
}
346723
func (c *Client) CreateDashboard(ctx context.Context, d *platform.Dashboard) error {
	err := c.db.Update(func(tx *bolt.Tx) error {
		d.ID = c.IDGenerator.ID()

		for _, cell := range d.Cells {
			cell.ID = c.IDGenerator.ID()

			if err := c.createCellView(ctx, tx, d.ID, cell.ID, nil); err != nil {
				return err
			}
		}

		if err := c.appendDashboardEventToLog(ctx, tx, d.ID, dashboardCreatedEvent); err != nil {
			return err
		}

		// TODO(desa): don't populate this here. use the first/last methods of the oplog to get meta fields.
		d.Meta.CreatedAt = c.time()

		return c.putDashboardWithMeta(ctx, tx, d)
	})
	if err != nil {
		return &platform.Error{
			Err: err,
			Op:  getOp(platform.OpCreateDashboard),
		}
	}
	return nil
}