// handleMissingDashboardFiles will unprovision or delete dashboards which are missing on disk.
8424
func (fr *fileReader) handleMissingDashboardFiles(provisionedDashboardRefs map[string]*models.DashboardProvisioning, filesFoundOnDisk map[string]os.FileInfo) {
	// find dashboards to delete since json file is missing
	var dashboardToDelete []int64
	for path, provisioningData := range provisionedDashboardRefs {
		_, existsOnDisk := filesFoundOnDisk[path]
		if !existsOnDisk {
			dashboardToDelete = append(dashboardToDelete, provisioningData.DashboardId)
		}
	}

	if fr.Cfg.DisableDeletion {
		// If deletion is disabled for the provisioner we just remove provisioning metadata about the dashboard
		// so afterwards the dashboard is considered unprovisioned.
		for _, dashboardId := range dashboardToDelete {
			fr.log.Debug("unprovisioning provisioned dashboard. missing on disk", "id", dashboardId)
			err := fr.dashboardProvisioningService.UnprovisionDashboard(dashboardId)
			if err != nil {
				fr.log.Error("failed to unprovision dashboard", "dashboard_id", dashboardId, "error", err)
			}
		}
	} else {
		// delete dashboard that are missing json file
		for _, dashboardId := range dashboardToDelete {
			fr.log.Debug("deleting provisioned dashboard. missing on disk", "id", dashboardId)
			err := fr.dashboardProvisioningService.DeleteProvisionedDashboard(dashboardId, fr.Cfg.OrgId)
			if err != nil {
				fr.log.Error("failed to delete dashboard", "id", dashboardId, "error", err)
			}
		}
	}
}
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
}
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))
}
216420
func GetDashboardVersions(query *m.GetDashboardVersionsQuery) error {
	if query.Limit == 0 {
		query.Limit = 1000
	}

	err := x.Table("dashboard_version").
		Select(`dashboard_version.id,
				dashboard_version.dashboard_id,
				dashboard_version.parent_version,
				dashboard_version.restored_from,
				dashboard_version.version,
				dashboard_version.created,
				dashboard_version.created_by as created_by_id,
				dashboard_version.message,
				dashboard_version.data,`+
			dialect.Quote("user")+`.login as created_by`).
		Join("LEFT", dialect.Quote("user"), `dashboard_version.created_by = `+dialect.Quote("user")+`.id`).
		Join("LEFT", "dashboard", `dashboard.id = dashboard_version.dashboard_id`).
		Where("dashboard_version.dashboard_id=? AND dashboard.org_id=?", query.DashboardId, query.OrgId).
		OrderBy("dashboard_version.version DESC").
		Limit(query.Limit, query.Start).
		Find(&query.Result)
	if err != nil {
		return err
	}

	if len(query.Result) < 1 {
		return m.ErrNoVersionsForDashboardId
	}
	return nil
}
644647
func (c *Client) GetDashboard() (*tumblr.Dashboard, error) {
	return c.GetDashboardWithParams(url.Values{})
}
1039292
func GetDashboard(client ClientInterface, params url.Values) (*Dashboard, error) {
	if params.Get("offset") != "" && params.Get("since_id") != "" {
		return nil, errors.New("Cannot specify both offset and since_id")
	}

	response, err := client.GetWithParams("/user/dashboard", params)
	if err != nil {
		return nil, err
	}
	result := struct {
		Response struct {
			Posts []MiniPost `json:"posts"`
		} `json:"response"`
	}{}
	if err = json.Unmarshal(response.body, &result); err != nil {
		return nil, err
	}
	minis := result.Response.Posts
	full := struct {
		Response Dashboard `json:"response"`
	}{
		Response: Dashboard{
			client:   client,
			params:   params,
			byOffset: params.Get("offset") != "",
			bySince:  params.Get("since_id") != "",
		},
	}
	full.Response.Posts = makePostsFromMinis(minis, client)
	if err = json.Unmarshal(response.body, &full); err != nil {
		return nil, err
	}
	return &full.Response, nil
}
1036056
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
}
450077
func (dr *dashboardServiceImpl) DeleteDashboard(dashboardId int64, orgId int64) error {
	return dr.deleteDashboard(dashboardId, orgId, true)
}
315691
func (s *Service) FindDashboard(ctx context.Context, filter influxdb.DashboardFilter, opts ...influxdb.FindOptions) (*influxdb.Dashboard, error) {
	if len(filter.IDs) == 1 {
		return s.FindDashboardByID(ctx, *filter.IDs[0])
	}

	var d *influxdb.Dashboard
	err := s.kv.View(ctx, func(tx Tx) error {
		filterFn := filterDashboardsFn(filter)
		return s.forEachDashboard(ctx, tx, opts[0].Descending, func(dash *influxdb.Dashboard) bool {
			if filterFn(dash) {
				d = dash
				return false
			}
			return true
		})
	})

	if err != nil {
		return nil, err
	}

	if d == nil {
		return nil, &influxdb.Error{
			Code: influxdb.ENotFound,
			Msg:  influxdb.ErrDashboardNotFound,
		}
	}

	return d, nil
}
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)
}
517959
func (s *Service) DeleteDashboard(ctx context.Context, id platform.ID) error {
	op := OpPrefix + platform.OpDeleteDashboard
	if _, err := s.FindDashboardByID(ctx, id); err != nil {
		return &platform.Error{
			Err: err,
			Op:  op,
		}
	}
	s.dashboardKV.Delete(id.String())
	err := s.deleteLabel(ctx, platform.LabelFilter{ResourceID: id})
	if err != nil {
		return &platform.Error{
			Err: err,
			Op:  op,
		}
	}
	return nil
}
371699
func (s *GetDeliverabilityDashboardOptionsOutput) SetDashboardEnabled(v bool) *GetDeliverabilityDashboardOptionsOutput {
	s.DashboardEnabled = &v
	return s
}
915558
func (h *DashboardHandler) handleGetDashboards(w http.ResponseWriter, r *http.Request) {
	ctx := r.Context()
	req, err := decodeGetDashboardsRequest(ctx, r)
	if err != nil {
		EncodeError(ctx, err, w)
		return
	}

	if req.ownerID != nil {
		filter := platform.UserResourceMappingFilter{
			UserID:       *req.ownerID,
			UserType:     platform.Owner,
			ResourceType: platform.DashboardsResourceType,
		}

		mappings, _, err := h.UserResourceMappingService.FindUserResourceMappings(ctx, filter)
		if err != nil {
			EncodeError(ctx, &platform.Error{
				Code: platform.EInternal,
				Msg:  "Error loading dashboard owners",
				Err:  err,
			}, w)
			return
		}

		for _, mapping := range mappings {
			req.filter.IDs = append(req.filter.IDs, &mapping.ResourceID)
		}
	}

	dashboards, _, err := h.DashboardService.FindDashboards(ctx, req.filter, req.opts)
	if err != nil {
		EncodeError(ctx, err, w)
		return
	}

	if err := encodeResponse(ctx, w, http.StatusOK, newGetDashboardsResponse(ctx, dashboards, req.filter, req.opts, h.LabelService)); err != nil {
		logEncodingError(h.Logger, r, err)
		return
	}
}
556012
func (cmd *UpdateFolderCommand) UpdateDashboardModel(dashFolder *Dashboard, orgId int64, userId int64) {
	dashFolder.OrgId = orgId
	dashFolder.Title = strings.TrimSpace(cmd.Title)
	dashFolder.Data.Set("title", dashFolder.Title)

	if cmd.Uid != "" {
		dashFolder.SetUid(cmd.Uid)
	}

	dashFolder.SetVersion(cmd.Version)
	dashFolder.IsFolder = true

	if userId == 0 {
		userId = -1
	}

	dashFolder.UpdatedBy = userId
	dashFolder.UpdateSlug()
}
151111
func (h *DashboardHandler) handleDeleteDashboardCell(w http.ResponseWriter, r *http.Request) {
	ctx := r.Context()

	req, err := decodeDeleteDashboardCellRequest(ctx, r)
	if err != nil {
		EncodeError(ctx, err, w)
		return
	}
	if err := h.DashboardService.RemoveDashboardCell(ctx, req.dashboardID, req.cellID); err != nil {
		EncodeError(ctx, err, w)
		return
	}

	w.WriteHeader(http.StatusNoContent)
}
104311
func (d *Dashboard) GetDashboardIdForSavePermissionCheck() int64 {
	if d.Id == 0 {
		return d.FolderId
	}

	return d.Id
}
1313881
func SortDashboards(opts FindOptions, ds []*Dashboard) {
	var sorter func(i, j int) bool
	switch opts.SortBy {
	case "CreatedAt":
		sorter = func(i, j int) bool {
			return ds[j].Meta.CreatedAt.After(ds[i].Meta.CreatedAt)
		}
	case "UpdatedAt":
		sorter = func(i, j int) bool {
			return ds[j].Meta.UpdatedAt.After(ds[i].Meta.UpdatedAt)
		}
	case "Name":
		sorter = func(i, j int) bool {
			return ds[i].Name < ds[j].Name
		}
	default:
		sorter = func(i, j int) bool {
			if opts.Descending {
				return ds[i].ID > ds[j].ID
			}
			return ds[i].ID < ds[j].ID
		}
	}

	sort.Slice(ds, sorter)
}