// deployDashboard queries the user for various input on deploying a web-service
// dashboard, after which is pushes the container.
187072
func (w *wizard) deployDashboard() {
	// Select the server to interact with
	server := w.selectServer()
	if server == "" {
		return
	}
	client := w.servers[server]

	// Retrieve any active dashboard configurations from the server
	infos, err := checkDashboard(client, w.network)
	if err != nil {
		infos = &dashboardInfos{
			port: 80,
			host: client.server,
		}
	}
	existed := err == nil

	// Figure out which port to listen on
	fmt.Println()
	fmt.Printf("Which port should the dashboard listen on? (default = %d)\n", infos.port)
	infos.port = w.readDefaultInt(infos.port)

	// Figure which virtual-host to deploy the dashboard on
	infos.host, err = w.ensureVirtualHost(client, infos.port, infos.host)
	if err != nil {
		log.Error("Failed to decide on dashboard host", "err", err)
		return
	}
	// Port and proxy settings retrieved, figure out which services are available
	available := make(map[string][]string)
	for server, services := range w.services {
		for _, service := range services {
			available[service] = append(available[service], server)
		}
	}
	for _, service := range []string{"ethstats", "explorer", "wallet", "faucet"} {
		// Gather all the locally hosted pages of this type
		var pages []string
		for _, server := range available[service] {
			client := w.servers[server]
			if client == nil {
				continue
			}
			// If there's a service running on the machine, retrieve it's port number
			var port int
			switch service {
			case "ethstats":
				if infos, err := checkEthstats(client, w.network); err == nil {
					port = infos.port
				}
			case "explorer":
				if infos, err := checkExplorer(client, w.network); err == nil {
					port = infos.webPort
				}
			case "wallet":
				if infos, err := checkWallet(client, w.network); err == nil {
					port = infos.webPort
				}
			case "faucet":
				if infos, err := checkFaucet(client, w.network); err == nil {
					port = infos.port
				}
			}
			if page, err := resolve(client, w.network, service, port); err == nil && page != "" {
				pages = append(pages, page)
			}
		}
		// Prompt the user to chose one, enter manually or simply not list this service
		defLabel, defChoice := "don't list", len(pages)+2
		if len(pages) > 0 {
			defLabel, defChoice = pages[0], 1
		}
		fmt.Println()
		fmt.Printf("Which %s service to list? (default = %s)\n", service, defLabel)
		for i, page := range pages {
			fmt.Printf(" %d. %s\n", i+1, page)
		}
		fmt.Printf(" %d. List external %s service\n", len(pages)+1, service)
		fmt.Printf(" %d. Don't list any %s service\n", len(pages)+2, service)

		choice := w.readDefaultInt(defChoice)
		if choice < 0 || choice > len(pages)+2 {
			log.Error("Invalid listing choice, aborting")
			return
		}
		var page string
		switch {
		case choice <= len(pages):
			page = pages[choice-1]
		case choice == len(pages)+1:
			fmt.Println()
			fmt.Printf("Which address is the external %s service at?\n", service)
			page = w.readString()
		default:
			// No service hosting for this
		}
		// Save the users choice
		switch service {
		case "ethstats":
			infos.ethstats = page
		case "explorer":
			infos.explorer = page
		case "wallet":
			infos.wallet = page
		case "faucet":
			infos.faucet = page
		}
	}
	// If we have ethstats running, ask whether to make the secret public or not
	if w.conf.ethstats != "" {
		fmt.Println()
		fmt.Println("Include ethstats secret on dashboard (y/n)? (default = yes)")
		infos.trusted = w.readDefaultYesNo(true)
	}
	// Try to deploy the dashboard container on the host
	nocache := false
	if existed {
		fmt.Println()
		fmt.Printf("Should the dashboard be built from scratch (y/n)? (default = no)\n")
		nocache = w.readDefaultYesNo(false)
	}
	if out, err := deployDashboard(client, w.network, &w.conf, infos, nocache); err != nil {
		log.Error("Failed to deploy dashboard container", "err", err)
		if len(out) > 0 {
			fmt.Printf("%s\n", out)
		}
		return
	}
	// All ok, run a network scan to pick any changes up
	w.networkStats()
}
412317
func (s *ProtoService) CreateDashboardsFromProto(ctx context.Context, protoID platform.ID, orgID platform.ID) ([]*platform.Dashboard, error) {
	// TODO(desa): this should be done transactionally.
	proto, err := s.findProto(ctx, protoID)
	if err != nil {
		return nil, err
	}

	dashes := []*platform.Dashboard{}

	for _, protodash := range proto.Dashboards {
		dash := &platform.Dashboard{}
		*dash = protodash.Dashboard
		// TODO(desa): add organization id here
		dash.Cells = nil

		if err := s.DashboardService.CreateDashboard(ctx, dash); err != nil {
			return nil, err
		}

		cells := []*platform.Cell{}
		for _, protocell := range protodash.Dashboard.Cells {
			cell := &platform.Cell{}
			*cell = *protocell

			protoview, ok := protodash.Views[cell.ID]
			if !ok {
				return nil, &platform.Error{Msg: fmt.Sprintf("view for ID %q does not exist", cell.ID)}
			}

			view := &platform.View{}
			*view = protoview
			opts := platform.AddDashboardCellOptions{View: view}
			if err := s.DashboardService.AddDashboardCell(ctx, dash.ID, cell, opts); err != nil {
				return nil, err
			}

			cells = append(cells, cell)
		}

		dash.Cells = cells

		dashes = append(dashes, dash)
	}

	return dashes, nil
}
1008168
func (s *Service) RemoveDashboard(w http.ResponseWriter, r *http.Request) {
	id, err := paramID("id", r)
	if err != nil {
		Error(w, http.StatusUnprocessableEntity, err.Error(), s.Logger)
		return
	}

	ctx := r.Context()
	e, err := s.Store.Dashboards(ctx).Get(ctx, chronograf.DashboardID(id))
	if err != nil {
		notFound(w, id, s.Logger)
		return
	}

	if err := s.Store.Dashboards(ctx).Delete(ctx, e); err != nil {
		unknownErrorWithMessage(w, err, s.Logger)
		return
	}
	w.WriteHeader(http.StatusNoContent)
}
1238119
func (s *Service) GetDashboardCellView(ctx context.Context, dashboardID, cellID platform.ID) (*platform.View, error) {
	v, err := s.FindViewByID(ctx, cellID)
	if err != nil {
		return nil, &platform.Error{
			Err: err,
			Op:  OpPrefix + platform.OpGetDashboardCellView,
		}
	}

	return v, nil
}
364747
func hapiDashboard(w http.ResponseWriter, r *http.Request) {
	if os.Getenv("ABOT_ENV") != "test" {
		if !isAdmin(w, r) {
			return
		}
		if !isLoggedIn(w, r) {
			return
		}
	}

	// Assemble checklist
	checklist := []bool{}
	var adminCount int
	q := `SELECT COUNT(*) FROM users WHERE admin=TRUE`
	err := db.Get(&adminCount, q)
	if err != nil && err != sql.ErrNoRows {
		writeErrorInternal(w, err)
		return
	}
	checklist = append(checklist, adminCount > 0)
	var tokenCount int
	q = `SELECT COUNT(*) FROM remotetokens`
	err = db.Get(&tokenCount, q)
	if err != nil && err != sql.ErrNoRows {
		writeErrorInternal(w, err)
		return
	}
	checklist = append(checklist, len(AllPlugins) > 0)
	if smsConn != nil || emailConn != nil {
		checklist = append(checklist, true)
	} else {
		checklist = append(checklist, false)
	}
	checklist = append(checklist, tokenCount > 0)
	checklist = append(checklist, adminCount > 1)

	// Assemble analytics
	var userCount int
	q = `SELECT value FROM analytics WHERE label=$1 ORDER BY createdat DESC`
	if err = db.Get(&userCount, q, keyUserCount); err != nil {
		writeErrorInternal(w, err)
		return
	}
	var msgCount int
	if err = db.Get(&msgCount, q, keyMsgCount); err != nil {
		writeErrorInternal(w, err)
		return
	}
	var needsTraining int
	if err = db.Get(&needsTraining, q, keyTrainCount); err != nil {
		writeErrorInternal(w, err)
		return
	}
	var automationRate float64
	if msgCount == 0 {
		automationRate = 0
	} else {
		automationRate = 1 - float64(needsTraining)/float64(msgCount)
	}
	var version float64
	if err = db.Get(&version, q, keyVersion); err != nil {
		writeErrorInternal(w, err)
		return
	}
	needUpdate := conf.Version < version
	resp := struct {
		Checklist      []bool
		Users          int
		Messages       int
		AutomationRate float64
		NeedUpdate     bool
	}{
		Checklist:      checklist,
		Users:          userCount,
		Messages:       msgCount,
		AutomationRate: automationRate,
		NeedUpdate:     needUpdate,
	}
	byt, err := json.Marshal(resp)
	if err != nil {
		writeErrorInternal(w, err)
		return
	}
	_, err = w.Write(byt)
	if err != nil {
		log.Info("failed to write response.", err)
	}
}
504445
func ValidDashboardRequest(d *chronograf.Dashboard, defaultOrgID string) error {
	if d.Organization == "" {
		d.Organization = defaultOrgID
	}
	for i, c := range d.Cells {
		if err := ValidDashboardCellRequest(&c); err != nil {
			return err
		}
		d.Cells[i] = c
	}
	for _, t := range d.Templates {
		if err := ValidTemplateRequest(&t); err != nil {
			return err
		}
	}
	(*d) = DashboardDefaults(*d)
	return 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)
}
316609
func (s *Service) PutDashboardCell(ctx context.Context, id platform.ID, cell *platform.Cell) error {
	d, err := s.FindDashboardByID(ctx, id)
	if err != nil {
		return err
	}
	view := &platform.View{}
	view.ID = cell.ID
	if err := s.PutView(ctx, view); err != nil {
		return err
	}

	d.Cells = append(d.Cells, cell)
	return s.PutDashboard(ctx, d)
}
414520
func (s *Service) AddDashboardCell(ctx context.Context, id influxdb.ID, cell *influxdb.Cell, opts influxdb.AddDashboardCellOptions) error {
	err := s.kv.Update(ctx, func(tx Tx) error {
		return s.addDashboardCell(ctx, tx, id, cell, opts)
	})
	if err != nil {
		return &influxdb.Error{
			Err: err,
		}
	}
	return nil
}
563560
func (c *Client) FindDashboard(ctx context.Context, filter platform.DashboardFilter) (*platform.Dashboard, error) {
	if len(filter.IDs) == 1 {
		return c.FindDashboardByID(ctx, *filter.IDs[0])
	}

	var d *platform.Dashboard
	err := c.db.View(func(tx *bolt.Tx) error {
		filterFn := filterDashboardsFn(filter)
		return c.forEachDashboard(ctx, tx, func(dash *platform.Dashboard) bool {
			if filterFn(dash) {
				d = dash
				return false
			}
			return true
		})
	})

	if err != nil {
		return nil, err
	}

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

	return d, nil
}
554967
func (s *DashboardService) CreateDashboard(ctx context.Context, b *influxdb.Dashboard) error {
	p, err := influxdb.NewPermission(influxdb.WriteAction, influxdb.DashboardsResourceType, b.OrganizationID)
	if err != nil {
		return err
	}

	if err := IsAllowed(ctx, *p); err != nil {
		return err
	}

	return s.s.CreateDashboard(ctx, b)
}
887230
func (s *DashboardService) UpdateDashboardCell(ctx context.Context, dashboardID, cellID platform.ID, upd platform.CellUpdate) (*platform.Cell, error) {
	op := s.OpPrefix + platform.OpUpdateDashboardCell
	if err := upd.Valid(); err != nil {
		return nil, &platform.Error{
			Op:  op,
			Err: err,
		}
	}

	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
	}

	if err := CheckError(resp, true); err != nil {
		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
}
242585
func (s *Service) Dashboards(w http.ResponseWriter, r *http.Request) {
	ctx := r.Context()
	dashboards, err := s.Store.Dashboards(ctx).All(ctx)
	if err != nil {
		Error(w, http.StatusInternalServerError, "Error loading dashboards", s.Logger)
		return
	}

	res := getDashboardsResponse{
		Dashboards: []*dashboardResponse{},
	}

	for _, dashboard := range dashboards {
		res.Dashboards = append(res.Dashboards, newDashboardResponse(dashboard))
	}
	encodeJSON(w, http.StatusOK, res, s.Logger)
}
423570
func (s *Service) PutDashboard(ctx context.Context, d *platform.Dashboard) error {
	for _, cell := range d.Cells {
		if err := s.PutCellView(ctx, cell); err != nil {
			return err
		}
	}
	s.dashboardKV.Store(d.ID.String(), d)
	return nil
}
327899
func NewDashboard(title string) *Dashboard {
	dash := &Dashboard{}
	dash.Data = simplejson.New()
	dash.Data.Set("title", title)
	dash.Title = title
	dash.Created = time.Now()
	dash.Updated = time.Now()
	dash.UpdateSlug()
	return dash
}
235551
func ValidDashboardCellRequest(c *chronograf.DashboardCell) error {
	if c == nil {
		return fmt.Errorf("chronograf dashboard cell was nil")
	}

	CorrectWidthHeight(c)
	for _, q := range c.Queries {
		if err := ValidateQueryConfig(&q.QueryConfig); err != nil {
			return err
		}
	}
	MoveTimeShift(c)
	err := HasCorrectAxes(c)
	if err != nil {
		return err
	}
	if err = HasCorrectColors(c); err != nil {
		return err
	}
	return HasCorrectLegend(c)
}
429434
func (r *Client) SearchDashboards(query string, starred bool, tags ...string) ([]FoundBoard, error) {
	var (
		raw    []byte
		boards []FoundBoard
		code   int
		err    error
	)
	u := url.URL{}
	q := u.Query()
	if query != "" {
		q.Set("query", query)
	}
	if starred {
		q.Set("starred", "true")
	}
	for _, tag := range tags {
		q.Add("tag", tag)
	}
	if raw, code, err = r.get("api/search", q); err != nil {
		return nil, err
	}
	if code != 200 {
		return nil, fmt.Errorf("HTTP error %d: returns %s", code, raw)
	}
	err = json.Unmarshal(raw, &boards)
	return boards, err
}