Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/master' into postgres-query-bu…
Browse files Browse the repository at this point in the history
…ilder
  • Loading branch information
svenklemm committed Feb 8, 2018
2 parents ef18eb7 + a91bd53 commit dd2b6c7
Show file tree
Hide file tree
Showing 12 changed files with 370 additions and 186 deletions.
12 changes: 10 additions & 2 deletions pkg/api/dashboard.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"fmt"
"os"
"path"
"strings"

"github.com/grafana/grafana/pkg/services/dashboards"

Expand Down Expand Up @@ -217,6 +218,10 @@ func PostDashboard(c *middleware.Context, cmd m.SaveDashboardCommand) Response {
return ApiError(400, m.ErrDashboardTitleEmpty.Error(), nil)
}

if dash.IsFolder && strings.ToLower(dash.Title) == strings.ToLower(m.RootFolderName) {
return ApiError(400, "A folder already exists with that name", nil)
}

if dash.Id == 0 {
limitReached, err := middleware.QuotaReached(c, "dashboard")
if err != nil {
Expand All @@ -237,8 +242,11 @@ func PostDashboard(c *middleware.Context, cmd m.SaveDashboardCommand) Response {

dashboard, err := dashboards.GetRepository().SaveDashboard(dashItem)

if err == m.ErrDashboardTitleEmpty {
return ApiError(400, m.ErrDashboardTitleEmpty.Error(), nil)
if err == m.ErrDashboardTitleEmpty ||
err == m.ErrDashboardWithSameNameAsFolder ||
err == m.ErrDashboardFolderWithSameNameAsDashboard ||
err == m.ErrDashboardTypeMismatch {
return ApiError(400, err.Error(), nil)
}

if err == m.ErrDashboardContainsInvalidAlertData {
Expand Down
46 changes: 27 additions & 19 deletions pkg/models/dashboards.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,22 @@ import (

// Typed errors
var (
ErrDashboardNotFound = errors.New("Dashboard not found")
ErrDashboardSnapshotNotFound = errors.New("Dashboard snapshot not found")
ErrDashboardWithSameUIDExists = errors.New("A dashboard with the same uid already exists")
ErrDashboardWithSameNameInFolderExists = errors.New("A dashboard with the same name in the folder already exists")
ErrDashboardVersionMismatch = errors.New("The dashboard has been changed by someone else")
ErrDashboardTitleEmpty = errors.New("Dashboard title cannot be empty")
ErrDashboardFolderCannotHaveParent = errors.New("A Dashboard Folder cannot be added to another folder")
ErrDashboardContainsInvalidAlertData = errors.New("Invalid alert data. Cannot save dashboard")
ErrDashboardFailedToUpdateAlertData = errors.New("Failed to save alert data")
ErrDashboardsWithSameSlugExists = errors.New("Multiple dashboards with the same slug exists")
ErrDashboardFailedGenerateUniqueUid = errors.New("Failed to generate unique dashboard id")
ErrDashboardNotFound = errors.New("Dashboard not found")
ErrDashboardSnapshotNotFound = errors.New("Dashboard snapshot not found")
ErrDashboardWithSameUIDExists = errors.New("A dashboard with the same uid already exists")
ErrDashboardWithSameNameInFolderExists = errors.New("A dashboard with the same name in the folder already exists")
ErrDashboardVersionMismatch = errors.New("The dashboard has been changed by someone else")
ErrDashboardTitleEmpty = errors.New("Dashboard title cannot be empty")
ErrDashboardFolderCannotHaveParent = errors.New("A Dashboard Folder cannot be added to another folder")
ErrDashboardContainsInvalidAlertData = errors.New("Invalid alert data. Cannot save dashboard")
ErrDashboardFailedToUpdateAlertData = errors.New("Failed to save alert data")
ErrDashboardsWithSameSlugExists = errors.New("Multiple dashboards with the same slug exists")
ErrDashboardFailedGenerateUniqueUid = errors.New("Failed to generate unique dashboard id")
ErrDashboardExistingCannotChangeToDashboard = errors.New("An existing folder cannot be changed to a dashboard")
ErrDashboardTypeMismatch = errors.New("Dashboard cannot be changed to a folder")
ErrDashboardFolderWithSameNameAsDashboard = errors.New("Folder name cannot be the same as one of its dashboards")
ErrDashboardWithSameNameAsFolder = errors.New("Dashboard name cannot be the same as folder")
RootFolderName = "General"
)

type UpdatePluginDashboardError struct {
Expand Down Expand Up @@ -95,14 +100,21 @@ func NewDashboardFromJson(data *simplejson.Json) *Dashboard {
dash.Data = data
dash.Title = dash.Data.Get("title").MustString()
dash.UpdateSlug()
update := false

if id, err := dash.Data.Get("id").Float64(); err == nil {
dash.Id = int64(id)
update = true
}

if uid, err := dash.Data.Get("uid").String(); err == nil {
dash.Uid = uid
update = true
}

if version, err := dash.Data.Get("version").Float64(); err == nil {
dash.Version = int(version)
dash.Updated = time.Now()
}
if version, err := dash.Data.Get("version").Float64(); err == nil && update {
dash.Version = int(version)
dash.Updated = time.Now()
} else {
dash.Data.Set("version", 0)
dash.Created = time.Now()
Expand All @@ -113,10 +125,6 @@ func NewDashboardFromJson(data *simplejson.Json) *Dashboard {
dash.GnetId = int64(gnetId)
}

if uid, err := dash.Data.Get("uid").String(); err == nil {
dash.Uid = uid
}

return dash
}

Expand Down
1 change: 1 addition & 0 deletions pkg/plugins/dashboard_importer.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ func ImportDashboard(cmd *ImportDashboardCommand) error {
Path: cmd.Path,
Revision: dashboard.Data.Get("revision").MustInt64(1),
ImportedUri: "db/" + saveCmd.Result.Slug,
ImportedUrl: saveCmd.Result.GetUrl(),
ImportedRevision: dashboard.Data.Get("revision").MustInt64(1),
Imported: true,
}
Expand Down
2 changes: 2 additions & 0 deletions pkg/plugins/dashboards.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ type PluginDashboardInfoDTO struct {
Title string `json:"title"`
Imported bool `json:"imported"`
ImportedUri string `json:"importedUri"`
ImportedUrl string `json:"importedUrl"`
Slug string `json:"slug"`
DashboardId int64 `json:"dashboardId"`
ImportedRevision int64 `json:"importedRevision"`
Expand Down Expand Up @@ -64,6 +65,7 @@ func GetPluginDashboards(orgId int64, pluginId string) ([]*PluginDashboardInfoDT
res.DashboardId = existingDash.Id
res.Imported = true
res.ImportedUri = "db/" + existingDash.Slug
res.ImportedUrl = existingDash.GetUrl()
res.ImportedRevision = existingDash.Data.Get("revision").MustInt64(1)
existingMatches[existingDash.Id] = true
}
Expand Down
149 changes: 90 additions & 59 deletions pkg/services/sqlstore/dashboard.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,47 +32,36 @@ func SaveDashboard(cmd *m.SaveDashboardCommand) error {
return inTransaction(func(sess *DBSession) error {
dash := cmd.GetDashboardModel()

// try get existing dashboard
var existing m.Dashboard
if err := getExistingDashboardForUpdate(sess, dash, cmd); err != nil {
return err
}

if dash.Id != 0 {
dashWithIdExists, err := sess.Where("id=? AND org_id=?", dash.Id, dash.OrgId).Get(&existing)
if err != nil {
return err
}
if !dashWithIdExists {
return m.ErrDashboardNotFound
}
var existingByTitleAndFolder m.Dashboard

// check for is someone else has written in between
if dash.Version != existing.Version {
if cmd.Overwrite {
dash.Version = existing.Version
} else {
return m.ErrDashboardVersionMismatch
dashWithTitleAndFolderExists, err := sess.Where("org_id=? AND slug=? AND (is_folder=? OR folder_id=?)", dash.OrgId, dash.Slug, dialect.BooleanStr(true), dash.FolderId).Get(&existingByTitleAndFolder)
if err != nil {
return err
}

if dashWithTitleAndFolderExists {
if dash.Id != existingByTitleAndFolder.Id {
if existingByTitleAndFolder.IsFolder && !cmd.IsFolder {
return m.ErrDashboardWithSameNameAsFolder
}
}

// do not allow plugin dashboard updates without overwrite flag
if existing.PluginId != "" && cmd.Overwrite == false {
return m.UpdatePluginDashboardError{PluginId: existing.PluginId}
}
} else if dash.Uid != "" {
var sameUid m.Dashboard
sameUidExists, err := sess.Where("org_id=? AND uid=?", dash.OrgId, dash.Uid).Get(&sameUid)
if err != nil {
return err
}
if !existingByTitleAndFolder.IsFolder && cmd.IsFolder {
return m.ErrDashboardFolderWithSameNameAsDashboard
}

if sameUidExists {
// another dashboard with same uid
if dash.Id != sameUid.Id {
if cmd.Overwrite {
dash.Id = sameUid.Id
dash.Version = sameUid.Version
} else {
return m.ErrDashboardWithSameUIDExists
if cmd.Overwrite {
dash.Id = existingByTitleAndFolder.Id
dash.Version = existingByTitleAndFolder.Version

if dash.Uid == "" {
dash.Uid = existingByTitleAndFolder.Uid
}
} else {
return m.ErrDashboardWithSameNameInFolderExists
}
}
}
Expand All @@ -86,11 +75,6 @@ func SaveDashboard(cmd *m.SaveDashboardCommand) error {
dash.Data.Set("uid", uid)
}

err := guaranteeDashboardNameIsUniqueInFolder(sess, dash)
if err != nil {
return err
}

err = setHasAcl(sess, dash)
if err != nil {
return err
Expand Down Expand Up @@ -162,6 +146,72 @@ func SaveDashboard(cmd *m.SaveDashboardCommand) error {
})
}

func getExistingDashboardForUpdate(sess *DBSession, dash *m.Dashboard, cmd *m.SaveDashboardCommand) (err error) {
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.Uid = 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 !dashWithIdExists && !dashWithUidExists {
return nil
}

if dashWithIdExists && dashWithUidExists && existingById.Id != existingByUid.Id {
return m.ErrDashboardWithSameUIDExists
}

existing := existingById

if !dashWithIdExists && dashWithUidExists {
dash.Id = existingByUid.Id
existing = existingByUid
}

if (existing.IsFolder && !cmd.IsFolder) ||
(!existing.IsFolder && cmd.IsFolder) {
return m.ErrDashboardTypeMismatch
}

// check for is someone else has written in between
if dash.Version != existing.Version {
if cmd.Overwrite {
dash.Version = existing.Version
} else {
return m.ErrDashboardVersionMismatch
}
}

// do not allow plugin dashboard updates without overwrite flag
if existing.PluginId != "" && cmd.Overwrite == false {
return m.UpdatePluginDashboardError{PluginId: existing.PluginId}
}

return nil
}

func generateNewDashboardUid(sess *DBSession, orgId int64) (string, error) {
for i := 0; i < 3; i++ {
uid := generateNewUid()
Expand All @@ -179,23 +229,6 @@ func generateNewDashboardUid(sess *DBSession, orgId int64) (string, error) {
return "", m.ErrDashboardFailedGenerateUniqueUid
}

func guaranteeDashboardNameIsUniqueInFolder(sess *DBSession, dash *m.Dashboard) error {
var sameNameInFolder m.Dashboard
sameNameInFolderExist, err := sess.Where("org_id=? AND title=? AND folder_id = ? AND uid <> ?",
dash.OrgId, dash.Title, dash.FolderId, dash.Uid).
Get(&sameNameInFolder)

if err != nil {
return err
}

if sameNameInFolderExist {
return m.ErrDashboardWithSameNameInFolderExists
}

return nil
}

func setHasAcl(sess *DBSession, dash *m.Dashboard) error {
// check if parent has acl
if dash.FolderId > 0 {
Expand Down Expand Up @@ -518,9 +551,7 @@ func GetDashboardPermissionsForUser(query *m.GetDashboardPermissionsForUserQuery
params = append(params, query.UserId)
params = append(params, dialect.BooleanStr(false))

x.ShowSQL(true)
err := x.Sql(sql, params...).Find(&query.Result)
x.ShowSQL(false)

for _, p := range query.Result {
p.PermissionName = p.Permission.String()
Expand Down
Loading

0 comments on commit dd2b6c7

Please sign in to comment.