mirror of https://github.com/grafana/grafana.git
				
				
				
			
		
			
				
	
	
		
			643 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			643 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			Go
		
	
	
	
package sqlstore
 | 
						|
 | 
						|
import (
 | 
						|
	"strings"
 | 
						|
	"time"
 | 
						|
 | 
						|
	"github.com/grafana/grafana/pkg/bus"
 | 
						|
	"github.com/grafana/grafana/pkg/metrics"
 | 
						|
	m "github.com/grafana/grafana/pkg/models"
 | 
						|
	"github.com/grafana/grafana/pkg/services/search"
 | 
						|
	"github.com/grafana/grafana/pkg/util"
 | 
						|
)
 | 
						|
 | 
						|
func init() {
 | 
						|
	bus.AddHandler("sql", SaveDashboard)
 | 
						|
	bus.AddHandler("sql", GetDashboard)
 | 
						|
	bus.AddHandler("sql", GetDashboards)
 | 
						|
	bus.AddHandler("sql", DeleteDashboard)
 | 
						|
	bus.AddHandler("sql", SearchDashboards)
 | 
						|
	bus.AddHandler("sql", GetDashboardTags)
 | 
						|
	bus.AddHandler("sql", GetDashboardSlugById)
 | 
						|
	bus.AddHandler("sql", GetDashboardUIDById)
 | 
						|
	bus.AddHandler("sql", GetDashboardsByPluginId)
 | 
						|
	bus.AddHandler("sql", GetDashboardPermissionsForUser)
 | 
						|
	bus.AddHandler("sql", GetDashboardsBySlug)
 | 
						|
	bus.AddHandler("sql", ValidateDashboardBeforeSave)
 | 
						|
	bus.AddHandler("sql", HasEditPermissionInFolders)
 | 
						|
}
 | 
						|
 | 
						|
var generateNewUid func() string = util.GenerateShortUid
 | 
						|
 | 
						|
func SaveDashboard(cmd *m.SaveDashboardCommand) error {
 | 
						|
	return inTransaction(func(sess *DBSession) error {
 | 
						|
		return saveDashboard(sess, cmd)
 | 
						|
	})
 | 
						|
}
 | 
						|
 | 
						|
func saveDashboard(sess *DBSession, cmd *m.SaveDashboardCommand) error {
 | 
						|
	dash := cmd.GetDashboardModel()
 | 
						|
 | 
						|
	userId := cmd.UserId
 | 
						|
 | 
						|
	if userId == 0 {
 | 
						|
		userId = -1
 | 
						|
	}
 | 
						|
 | 
						|
	if dash.Id > 0 {
 | 
						|
		var existing m.Dashboard
 | 
						|
		dashWithIdExists, err := sess.Where("id=? AND org_id=?", dash.Id, dash.OrgId).Get(&existing)
 | 
						|
		if err != nil {
 | 
						|
			return err
 | 
						|
		}
 | 
						|
		if !dashWithIdExists {
 | 
						|
			return m.ErrDashboardNotFound
 | 
						|
		}
 | 
						|
 | 
						|
		// check for is someone else has written in between
 | 
						|
		if dash.Version != existing.Version {
 | 
						|
			if cmd.Overwrite {
 | 
						|
				dash.SetVersion(existing.Version)
 | 
						|
			} else {
 | 
						|
				return m.ErrDashboardVersionMismatch
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		// do not allow plugin dashboard updates without overwrite flag
 | 
						|
		if existing.PluginId != "" && !cmd.Overwrite {
 | 
						|
			return m.UpdatePluginDashboardError{PluginId: existing.PluginId}
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if dash.Uid == "" {
 | 
						|
		uid, err := generateNewDashboardUid(sess, dash.OrgId)
 | 
						|
		if err != nil {
 | 
						|
			return err
 | 
						|
		}
 | 
						|
		dash.SetUid(uid)
 | 
						|
	}
 | 
						|
 | 
						|
	parentVersion := dash.Version
 | 
						|
	var affectedRows int64
 | 
						|
	var err error
 | 
						|
 | 
						|
	if dash.Id == 0 {
 | 
						|
		dash.SetVersion(1)
 | 
						|
		dash.Created = time.Now()
 | 
						|
		dash.CreatedBy = userId
 | 
						|
		dash.Updated = time.Now()
 | 
						|
		dash.UpdatedBy = userId
 | 
						|
		metrics.M_Api_Dashboard_Insert.Inc()
 | 
						|
		affectedRows, err = sess.Insert(dash)
 | 
						|
	} else {
 | 
						|
		dash.SetVersion(dash.Version + 1)
 | 
						|
 | 
						|
		if !cmd.UpdatedAt.IsZero() {
 | 
						|
			dash.Updated = cmd.UpdatedAt
 | 
						|
		} else {
 | 
						|
			dash.Updated = time.Now()
 | 
						|
		}
 | 
						|
 | 
						|
		dash.UpdatedBy = userId
 | 
						|
 | 
						|
		affectedRows, err = sess.MustCols("folder_id").ID(dash.Id).Update(dash)
 | 
						|
	}
 | 
						|
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	if affectedRows == 0 {
 | 
						|
		return m.ErrDashboardNotFound
 | 
						|
	}
 | 
						|
 | 
						|
	dashVersion := &m.DashboardVersion{
 | 
						|
		DashboardId:   dash.Id,
 | 
						|
		ParentVersion: parentVersion,
 | 
						|
		RestoredFrom:  cmd.RestoredFrom,
 | 
						|
		Version:       dash.Version,
 | 
						|
		Created:       time.Now(),
 | 
						|
		CreatedBy:     dash.UpdatedBy,
 | 
						|
		Message:       cmd.Message,
 | 
						|
		Data:          dash.Data,
 | 
						|
	}
 | 
						|
 | 
						|
	// insert version entry
 | 
						|
	if affectedRows, err = sess.Insert(dashVersion); err != nil {
 | 
						|
		return err
 | 
						|
	} else if affectedRows == 0 {
 | 
						|
		return m.ErrDashboardNotFound
 | 
						|
	}
 | 
						|
 | 
						|
	// delete existing tags
 | 
						|
	_, err = sess.Exec("DELETE FROM dashboard_tag WHERE dashboard_id=?", dash.Id)
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	// insert new tags
 | 
						|
	tags := dash.GetTags()
 | 
						|
	if len(tags) > 0 {
 | 
						|
		for _, tag := range tags {
 | 
						|
			if _, err := sess.Insert(&DashboardTag{DashboardId: dash.Id, Term: tag}); err != nil {
 | 
						|
				return err
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	cmd.Result = dash
 | 
						|
 | 
						|
	return err
 | 
						|
}
 | 
						|
 | 
						|
func generateNewDashboardUid(sess *DBSession, orgId int64) (string, error) {
 | 
						|
	for i := 0; i < 3; i++ {
 | 
						|
		uid := generateNewUid()
 | 
						|
 | 
						|
		exists, err := sess.Where("org_id=? AND uid=?", orgId, uid).Get(&m.Dashboard{})
 | 
						|
		if err != nil {
 | 
						|
			return "", err
 | 
						|
		}
 | 
						|
 | 
						|
		if !exists {
 | 
						|
			return uid, nil
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return "", m.ErrDashboardFailedGenerateUniqueUid
 | 
						|
}
 | 
						|
 | 
						|
func GetDashboard(query *m.GetDashboardQuery) error {
 | 
						|
	dashboard := m.Dashboard{Slug: query.Slug, OrgId: query.OrgId, Id: query.Id, Uid: query.Uid}
 | 
						|
	has, err := x.Get(&dashboard)
 | 
						|
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	} else if !has {
 | 
						|
		return m.ErrDashboardNotFound
 | 
						|
	}
 | 
						|
 | 
						|
	dashboard.SetId(dashboard.Id)
 | 
						|
	dashboard.SetUid(dashboard.Uid)
 | 
						|
	query.Result = &dashboard
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
type DashboardSearchProjection struct {
 | 
						|
	Id          int64
 | 
						|
	Uid         string
 | 
						|
	Title       string
 | 
						|
	Slug        string
 | 
						|
	Term        string
 | 
						|
	IsFolder    bool
 | 
						|
	FolderId    int64
 | 
						|
	FolderUid   string
 | 
						|
	FolderSlug  string
 | 
						|
	FolderTitle string
 | 
						|
}
 | 
						|
 | 
						|
func findDashboards(query *search.FindPersistedDashboardsQuery) ([]DashboardSearchProjection, error) {
 | 
						|
	limit := query.Limit
 | 
						|
	if limit == 0 {
 | 
						|
		limit = 1000
 | 
						|
	}
 | 
						|
 | 
						|
	sb := NewSearchBuilder(query.SignedInUser, limit, query.Permission).
 | 
						|
		WithTags(query.Tags).
 | 
						|
		WithDashboardIdsIn(query.DashboardIds)
 | 
						|
 | 
						|
	if query.IsStarred {
 | 
						|
		sb.IsStarred()
 | 
						|
	}
 | 
						|
 | 
						|
	if len(query.Title) > 0 {
 | 
						|
		sb.WithTitle(query.Title)
 | 
						|
	}
 | 
						|
 | 
						|
	if len(query.Type) > 0 {
 | 
						|
		sb.WithType(query.Type)
 | 
						|
	}
 | 
						|
 | 
						|
	if len(query.FolderIds) > 0 {
 | 
						|
		sb.WithFolderIds(query.FolderIds)
 | 
						|
	}
 | 
						|
 | 
						|
	var res []DashboardSearchProjection
 | 
						|
 | 
						|
	sql, params := sb.ToSql()
 | 
						|
	err := x.SQL(sql, params...).Find(&res)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
 | 
						|
	return res, nil
 | 
						|
}
 | 
						|
 | 
						|
func SearchDashboards(query *search.FindPersistedDashboardsQuery) error {
 | 
						|
	res, err := findDashboards(query)
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	makeQueryResult(query, res)
 | 
						|
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
func getHitType(item DashboardSearchProjection) search.HitType {
 | 
						|
	var hitType search.HitType
 | 
						|
	if item.IsFolder {
 | 
						|
		hitType = search.DashHitFolder
 | 
						|
	} else {
 | 
						|
		hitType = search.DashHitDB
 | 
						|
	}
 | 
						|
 | 
						|
	return hitType
 | 
						|
}
 | 
						|
 | 
						|
func makeQueryResult(query *search.FindPersistedDashboardsQuery, res []DashboardSearchProjection) {
 | 
						|
	query.Result = make([]*search.Hit, 0)
 | 
						|
	hits := make(map[int64]*search.Hit)
 | 
						|
 | 
						|
	for _, item := range res {
 | 
						|
		hit, exists := hits[item.Id]
 | 
						|
		if !exists {
 | 
						|
			hit = &search.Hit{
 | 
						|
				Id:          item.Id,
 | 
						|
				Uid:         item.Uid,
 | 
						|
				Title:       item.Title,
 | 
						|
				Uri:         "db/" + item.Slug,
 | 
						|
				Url:         m.GetDashboardFolderUrl(item.IsFolder, item.Uid, item.Slug),
 | 
						|
				Type:        getHitType(item),
 | 
						|
				FolderId:    item.FolderId,
 | 
						|
				FolderUid:   item.FolderUid,
 | 
						|
				FolderTitle: item.FolderTitle,
 | 
						|
				Tags:        []string{},
 | 
						|
			}
 | 
						|
 | 
						|
			if item.FolderId > 0 {
 | 
						|
				hit.FolderUrl = m.GetFolderUrl(item.FolderUid, item.FolderSlug)
 | 
						|
			}
 | 
						|
 | 
						|
			query.Result = append(query.Result, hit)
 | 
						|
			hits[item.Id] = hit
 | 
						|
		}
 | 
						|
		if len(item.Term) > 0 {
 | 
						|
			hit.Tags = append(hit.Tags, item.Term)
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func GetDashboardTags(query *m.GetDashboardTagsQuery) error {
 | 
						|
	sql := `SELECT
 | 
						|
					  COUNT(*) as count,
 | 
						|
						term
 | 
						|
					FROM dashboard
 | 
						|
					INNER JOIN dashboard_tag on dashboard_tag.dashboard_id = dashboard.id
 | 
						|
					WHERE dashboard.org_id=?
 | 
						|
					GROUP BY term
 | 
						|
					ORDER BY term`
 | 
						|
 | 
						|
	query.Result = make([]*m.DashboardTagCloudItem, 0)
 | 
						|
	sess := x.SQL(sql, query.OrgId)
 | 
						|
	err := sess.Find(&query.Result)
 | 
						|
	return err
 | 
						|
}
 | 
						|
 | 
						|
func DeleteDashboard(cmd *m.DeleteDashboardCommand) error {
 | 
						|
	return inTransaction(func(sess *DBSession) error {
 | 
						|
		dashboard := m.Dashboard{Id: cmd.Id, OrgId: cmd.OrgId}
 | 
						|
		has, err := sess.Get(&dashboard)
 | 
						|
		if err != nil {
 | 
						|
			return err
 | 
						|
		} else if !has {
 | 
						|
			return m.ErrDashboardNotFound
 | 
						|
		}
 | 
						|
 | 
						|
		deletes := []string{
 | 
						|
			"DELETE FROM dashboard_tag WHERE dashboard_id = ? ",
 | 
						|
			"DELETE FROM star WHERE dashboard_id = ? ",
 | 
						|
			"DELETE FROM dashboard WHERE id = ?",
 | 
						|
			"DELETE FROM playlist_item WHERE type = 'dashboard_by_id' AND value = ?",
 | 
						|
			"DELETE FROM dashboard_version WHERE dashboard_id = ?",
 | 
						|
			"DELETE FROM dashboard WHERE folder_id = ?",
 | 
						|
			"DELETE FROM annotation WHERE dashboard_id = ?",
 | 
						|
			"DELETE FROM dashboard_provisioning WHERE dashboard_id = ?",
 | 
						|
		}
 | 
						|
 | 
						|
		for _, sql := range deletes {
 | 
						|
			_, err := sess.Exec(sql, dashboard.Id)
 | 
						|
			if err != nil {
 | 
						|
				return err
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		if err := deleteAlertDefinition(dashboard.Id, sess); err != nil {
 | 
						|
			return nil
 | 
						|
		}
 | 
						|
 | 
						|
		return nil
 | 
						|
	})
 | 
						|
}
 | 
						|
 | 
						|
func GetDashboards(query *m.GetDashboardsQuery) error {
 | 
						|
	if len(query.DashboardIds) == 0 {
 | 
						|
		return m.ErrCommandValidationFailed
 | 
						|
	}
 | 
						|
 | 
						|
	var dashboards = make([]*m.Dashboard, 0)
 | 
						|
 | 
						|
	err := x.In("id", query.DashboardIds).Find(&dashboards)
 | 
						|
	query.Result = dashboards
 | 
						|
	return err
 | 
						|
}
 | 
						|
 | 
						|
// GetDashboardPermissionsForUser returns the maximum permission the specified user has for a dashboard(s)
 | 
						|
// The function takes in a list of dashboard ids and the user id and role
 | 
						|
func GetDashboardPermissionsForUser(query *m.GetDashboardPermissionsForUserQuery) error {
 | 
						|
	if len(query.DashboardIds) == 0 {
 | 
						|
		return m.ErrCommandValidationFailed
 | 
						|
	}
 | 
						|
 | 
						|
	if query.OrgRole == m.ROLE_ADMIN {
 | 
						|
		var permissions = make([]*m.DashboardPermissionForUser, 0)
 | 
						|
		for _, d := range query.DashboardIds {
 | 
						|
			permissions = append(permissions, &m.DashboardPermissionForUser{
 | 
						|
				DashboardId:    d,
 | 
						|
				Permission:     m.PERMISSION_ADMIN,
 | 
						|
				PermissionName: m.PERMISSION_ADMIN.String(),
 | 
						|
			})
 | 
						|
		}
 | 
						|
		query.Result = permissions
 | 
						|
 | 
						|
		return nil
 | 
						|
	}
 | 
						|
 | 
						|
	params := make([]interface{}, 0)
 | 
						|
 | 
						|
	// check dashboards that have ACLs via user id, team id or role
 | 
						|
	sql := `SELECT d.id AS dashboard_id, MAX(COALESCE(da.permission, pt.permission)) AS permission
 | 
						|
	FROM dashboard AS d
 | 
						|
		LEFT JOIN dashboard_acl as da on d.folder_id = da.dashboard_id or d.id = da.dashboard_id
 | 
						|
		LEFT JOIN team_member as ugm on ugm.team_id =  da.team_id
 | 
						|
		LEFT JOIN org_user ou ON ou.role = da.role AND ou.user_id = ?
 | 
						|
	`
 | 
						|
	params = append(params, query.UserId)
 | 
						|
 | 
						|
	//check the user's role for dashboards that do not have hasAcl set
 | 
						|
	sql += `LEFT JOIN org_user ouRole ON ouRole.user_id = ? AND ouRole.org_id = ?`
 | 
						|
	params = append(params, query.UserId)
 | 
						|
	params = append(params, query.OrgId)
 | 
						|
 | 
						|
	sql += `
 | 
						|
		LEFT JOIN (SELECT 1 AS permission, 'Viewer' AS role
 | 
						|
			UNION SELECT 2 AS permission, 'Editor' AS role
 | 
						|
			UNION SELECT 4 AS permission, 'Admin' AS role) pt ON ouRole.role = pt.role
 | 
						|
	WHERE
 | 
						|
	d.Id IN (?` + strings.Repeat(",?", len(query.DashboardIds)-1) + `) `
 | 
						|
	for _, id := range query.DashboardIds {
 | 
						|
		params = append(params, id)
 | 
						|
	}
 | 
						|
 | 
						|
	sql += ` AND
 | 
						|
	d.org_id = ? AND
 | 
						|
	  (
 | 
						|
		(d.has_acl = ?  AND (da.user_id = ? OR ugm.user_id = ? OR ou.id IS NOT NULL))
 | 
						|
		OR (d.has_acl = ? AND ouRole.id IS NOT NULL)
 | 
						|
	)
 | 
						|
	group by d.id
 | 
						|
	order by d.id asc`
 | 
						|
	params = append(params, query.OrgId)
 | 
						|
	params = append(params, dialect.BooleanStr(true))
 | 
						|
	params = append(params, query.UserId)
 | 
						|
	params = append(params, query.UserId)
 | 
						|
	params = append(params, dialect.BooleanStr(false))
 | 
						|
 | 
						|
	err := x.SQL(sql, params...).Find(&query.Result)
 | 
						|
 | 
						|
	for _, p := range query.Result {
 | 
						|
		p.PermissionName = p.Permission.String()
 | 
						|
	}
 | 
						|
 | 
						|
	return err
 | 
						|
}
 | 
						|
 | 
						|
func GetDashboardsByPluginId(query *m.GetDashboardsByPluginIdQuery) error {
 | 
						|
	var dashboards = make([]*m.Dashboard, 0)
 | 
						|
	whereExpr := "org_id=? AND plugin_id=? AND is_folder=" + dialect.BooleanStr(false)
 | 
						|
 | 
						|
	err := x.Where(whereExpr, query.OrgId, query.PluginId).Find(&dashboards)
 | 
						|
	query.Result = dashboards
 | 
						|
	return err
 | 
						|
}
 | 
						|
 | 
						|
type DashboardSlugDTO struct {
 | 
						|
	Slug string
 | 
						|
}
 | 
						|
 | 
						|
func GetDashboardSlugById(query *m.GetDashboardSlugByIdQuery) error {
 | 
						|
	var rawSql = `SELECT slug from dashboard WHERE Id=?`
 | 
						|
	var slug = DashboardSlugDTO{}
 | 
						|
 | 
						|
	exists, err := x.SQL(rawSql, query.Id).Get(&slug)
 | 
						|
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	} else if !exists {
 | 
						|
		return m.ErrDashboardNotFound
 | 
						|
	}
 | 
						|
 | 
						|
	query.Result = slug.Slug
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
func GetDashboardsBySlug(query *m.GetDashboardsBySlugQuery) error {
 | 
						|
	var dashboards []*m.Dashboard
 | 
						|
 | 
						|
	if err := x.Where("org_id=? AND slug=?", query.OrgId, query.Slug).Find(&dashboards); err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	query.Result = dashboards
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
func GetDashboardUIDById(query *m.GetDashboardRefByIdQuery) error {
 | 
						|
	var rawSql = `SELECT uid, slug from dashboard WHERE Id=?`
 | 
						|
 | 
						|
	us := &m.DashboardRef{}
 | 
						|
 | 
						|
	exists, err := x.SQL(rawSql, query.Id).Get(us)
 | 
						|
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	} else if !exists {
 | 
						|
		return m.ErrDashboardNotFound
 | 
						|
	}
 | 
						|
 | 
						|
	query.Result = us
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
func getExistingDashboardByIdOrUidForUpdate(sess *DBSession, cmd *m.ValidateDashboardBeforeSaveCommand) (err error) {
 | 
						|
	dash := cmd.Dashboard
 | 
						|
 | 
						|
	dashWithIdExists := false
 | 
						|
	var existingById m.Dashboard
 | 
						|
 | 
						|
	if dash.Id > 0 {
 | 
						|
		dashWithIdExists, err = sess.Where("id=? AND org_id=?", dash.Id, dash.OrgId).Get(&existingById)
 | 
						|
		if err != nil {
 | 
						|
			return err
 | 
						|
		}
 | 
						|
 | 
						|
		if !dashWithIdExists {
 | 
						|
			return m.ErrDashboardNotFound
 | 
						|
		}
 | 
						|
 | 
						|
		if dash.Uid == "" {
 | 
						|
			dash.SetUid(existingById.Uid)
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	dashWithUidExists := false
 | 
						|
	var existingByUid m.Dashboard
 | 
						|
 | 
						|
	if dash.Uid != "" {
 | 
						|
		dashWithUidExists, err = sess.Where("org_id=? AND uid=?", dash.OrgId, dash.Uid).Get(&existingByUid)
 | 
						|
		if err != nil {
 | 
						|
			return err
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if dash.FolderId > 0 {
 | 
						|
		var existingFolder m.Dashboard
 | 
						|
		folderExists, folderErr := sess.Where("org_id=? AND id=? AND is_folder=?", dash.OrgId, dash.FolderId, dialect.BooleanStr(true)).Get(&existingFolder)
 | 
						|
		if folderErr != nil {
 | 
						|
			return folderErr
 | 
						|
		}
 | 
						|
 | 
						|
		if !folderExists {
 | 
						|
			return m.ErrDashboardFolderNotFound
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if !dashWithIdExists && !dashWithUidExists {
 | 
						|
		return nil
 | 
						|
	}
 | 
						|
 | 
						|
	if dashWithIdExists && dashWithUidExists && existingById.Id != existingByUid.Id {
 | 
						|
		return m.ErrDashboardWithSameUIDExists
 | 
						|
	}
 | 
						|
 | 
						|
	existing := existingById
 | 
						|
 | 
						|
	if !dashWithIdExists && dashWithUidExists {
 | 
						|
		dash.SetId(existingByUid.Id)
 | 
						|
		dash.SetUid(existingByUid.Uid)
 | 
						|
		existing = existingByUid
 | 
						|
 | 
						|
		if !dash.IsFolder {
 | 
						|
			cmd.Result.IsParentFolderChanged = true
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if (existing.IsFolder && !dash.IsFolder) ||
 | 
						|
		(!existing.IsFolder && dash.IsFolder) {
 | 
						|
		return m.ErrDashboardTypeMismatch
 | 
						|
	}
 | 
						|
 | 
						|
	if !dash.IsFolder && dash.FolderId != existing.FolderId {
 | 
						|
		cmd.Result.IsParentFolderChanged = true
 | 
						|
	}
 | 
						|
 | 
						|
	// check for is someone else has written in between
 | 
						|
	if dash.Version != existing.Version {
 | 
						|
		if cmd.Overwrite {
 | 
						|
			dash.SetVersion(existing.Version)
 | 
						|
		} else {
 | 
						|
			return m.ErrDashboardVersionMismatch
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	// do not allow plugin dashboard updates without overwrite flag
 | 
						|
	if existing.PluginId != "" && !cmd.Overwrite {
 | 
						|
		return m.UpdatePluginDashboardError{PluginId: existing.PluginId}
 | 
						|
	}
 | 
						|
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
func getExistingDashboardByTitleAndFolder(sess *DBSession, cmd *m.ValidateDashboardBeforeSaveCommand) error {
 | 
						|
	dash := cmd.Dashboard
 | 
						|
	var existing m.Dashboard
 | 
						|
 | 
						|
	exists, err := sess.Where("org_id=? AND slug=? AND (is_folder=? OR folder_id=?)", dash.OrgId, dash.Slug, dialect.BooleanStr(true), dash.FolderId).Get(&existing)
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	if exists && dash.Id != existing.Id {
 | 
						|
		if existing.IsFolder && !dash.IsFolder {
 | 
						|
			return m.ErrDashboardWithSameNameAsFolder
 | 
						|
		}
 | 
						|
 | 
						|
		if !existing.IsFolder && dash.IsFolder {
 | 
						|
			return m.ErrDashboardFolderWithSameNameAsDashboard
 | 
						|
		}
 | 
						|
 | 
						|
		if !dash.IsFolder && (dash.FolderId != existing.FolderId || dash.Id == 0) {
 | 
						|
			cmd.Result.IsParentFolderChanged = true
 | 
						|
		}
 | 
						|
 | 
						|
		if cmd.Overwrite {
 | 
						|
			dash.SetId(existing.Id)
 | 
						|
			dash.SetUid(existing.Uid)
 | 
						|
			dash.SetVersion(existing.Version)
 | 
						|
		} else {
 | 
						|
			return m.ErrDashboardWithSameNameInFolderExists
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
func ValidateDashboardBeforeSave(cmd *m.ValidateDashboardBeforeSaveCommand) (err error) {
 | 
						|
	cmd.Result = &m.ValidateDashboardBeforeSaveResult{}
 | 
						|
	return inTransaction(func(sess *DBSession) error {
 | 
						|
		if err = getExistingDashboardByIdOrUidForUpdate(sess, cmd); err != nil {
 | 
						|
			return err
 | 
						|
		}
 | 
						|
 | 
						|
		if err = getExistingDashboardByTitleAndFolder(sess, cmd); err != nil {
 | 
						|
			return err
 | 
						|
		}
 | 
						|
 | 
						|
		return nil
 | 
						|
	})
 | 
						|
}
 | 
						|
 | 
						|
func HasEditPermissionInFolders(query *m.HasEditPermissionInFoldersQuery) error {
 | 
						|
	if query.SignedInUser.HasRole(m.ROLE_EDITOR) {
 | 
						|
		query.Result = true
 | 
						|
		return nil
 | 
						|
	}
 | 
						|
 | 
						|
	builder := &SqlBuilder{}
 | 
						|
	builder.Write("SELECT COUNT(dashboard.id) AS count FROM dashboard WHERE dashboard.org_id = ? AND dashboard.is_folder = ?", query.SignedInUser.OrgId, dialect.BooleanStr(true))
 | 
						|
	builder.writeDashboardPermissionFilter(query.SignedInUser, m.PERMISSION_EDIT)
 | 
						|
 | 
						|
	type folderCount struct {
 | 
						|
		Count int64
 | 
						|
	}
 | 
						|
 | 
						|
	resp := make([]*folderCount, 0)
 | 
						|
	if err := x.SQL(builder.GetSqlString(), builder.params...).Find(&resp); err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	query.Result = len(resp) > 0 && resp[0].Count > 0
 | 
						|
 | 
						|
	return nil
 | 
						|
}
 |