chore/backend: move dashboard errors to dashboard service (#51593)

* chore/backend: move dashboard errors to dashboard service

Dashboard-related models are slowly moving out of the models package and into dashboard services. This commit moves dashboard-related errors; the rest will come in later commits.

There are no logical code changes, this is only a structural (package) move.

* lint lint lint
This commit is contained in:
Kristin Laemmert 2022-06-30 09:31:54 -04:00 committed by GitHub
parent a1fb73c503
commit 9de00c8eb2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
46 changed files with 489 additions and 466 deletions

View File

@ -7,15 +7,15 @@ import (
"net/http"
"github.com/grafana/grafana/pkg/api/response"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/plugins"
"github.com/grafana/grafana/pkg/services/alerting"
"github.com/grafana/grafana/pkg/services/dashboards"
"github.com/grafana/grafana/pkg/util"
)
// ToDashboardErrorResponse returns a different response status according to the dashboard error type
func ToDashboardErrorResponse(ctx context.Context, pluginStore plugins.Store, err error) response.Response {
var dashboardErr models.DashboardErr
var dashboardErr dashboards.DashboardErr
if ok := errors.As(err, &dashboardErr); ok {
if body := dashboardErr.Body(); body != nil {
return response.JSON(dashboardErr.StatusCode, body)
@ -26,7 +26,7 @@ func ToDashboardErrorResponse(ctx context.Context, pluginStore plugins.Store, er
return response.Error(dashboardErr.StatusCode, dashboardErr.Error(), nil)
}
if errors.Is(err, models.ErrFolderNotFound) {
if errors.Is(err, dashboards.ErrFolderNotFound) {
return response.Error(http.StatusBadRequest, err.Error(), nil)
}
@ -35,7 +35,7 @@ func ToDashboardErrorResponse(ctx context.Context, pluginStore plugins.Store, er
return response.Error(http.StatusUnprocessableEntity, validationErr.Error(), err)
}
var pluginErr models.UpdatePluginDashboardError
var pluginErr dashboards.UpdatePluginDashboardError
if ok := errors.As(err, &pluginErr); ok {
message := fmt.Sprintf("The dashboard belongs to plugin %s.", pluginErr.PluginId)
// look up plugin name

View File

@ -4,40 +4,40 @@ import (
"errors"
"github.com/grafana/grafana/pkg/api/response"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/dashboards"
"github.com/grafana/grafana/pkg/util"
)
// ToFolderErrorResponse returns a different response status according to the folder error type
func ToFolderErrorResponse(err error) response.Response {
var dashboardErr models.DashboardErr
var dashboardErr dashboards.DashboardErr
if ok := errors.As(err, &dashboardErr); ok {
return response.Error(dashboardErr.StatusCode, err.Error(), err)
}
if errors.Is(err, models.ErrFolderTitleEmpty) ||
errors.Is(err, models.ErrDashboardTypeMismatch) ||
errors.Is(err, models.ErrDashboardInvalidUid) ||
errors.Is(err, models.ErrDashboardUidTooLong) ||
errors.Is(err, models.ErrFolderContainsAlertRules) {
if errors.Is(err, dashboards.ErrFolderTitleEmpty) ||
errors.Is(err, dashboards.ErrDashboardTypeMismatch) ||
errors.Is(err, dashboards.ErrDashboardInvalidUid) ||
errors.Is(err, dashboards.ErrDashboardUidTooLong) ||
errors.Is(err, dashboards.ErrFolderContainsAlertRules) {
return response.Error(400, err.Error(), nil)
}
if errors.Is(err, models.ErrFolderAccessDenied) {
if errors.Is(err, dashboards.ErrFolderAccessDenied) {
return response.Error(403, "Access denied", err)
}
if errors.Is(err, models.ErrFolderNotFound) {
return response.JSON(404, util.DynMap{"status": "not-found", "message": models.ErrFolderNotFound.Error()})
if errors.Is(err, dashboards.ErrFolderNotFound) {
return response.JSON(404, util.DynMap{"status": "not-found", "message": dashboards.ErrFolderNotFound.Error()})
}
if errors.Is(err, models.ErrFolderSameNameExists) ||
errors.Is(err, models.ErrFolderWithSameUIDExists) {
if errors.Is(err, dashboards.ErrFolderSameNameExists) ||
errors.Is(err, dashboards.ErrFolderWithSameUIDExists) {
return response.Error(409, err.Error(), nil)
}
if errors.Is(err, models.ErrFolderVersionMismatch) {
return response.JSON(412, util.DynMap{"status": "version-mismatch", "message": models.ErrFolderVersionMismatch.Error()})
if errors.Is(err, dashboards.ErrFolderVersionMismatch) {
return response.JSON(412, util.DynMap{"status": "version-mismatch", "message": dashboards.ErrFolderVersionMismatch.Error()})
}
return response.Error(500, "Folder API error", err)

View File

@ -145,7 +145,7 @@ func (hs *HTTPServer) GetDashboard(c *models.ReqContext) response.Response {
if dash.FolderId > 0 {
query := models.GetDashboardQuery{Id: dash.FolderId, OrgId: c.OrgId}
if err := hs.dashboardService.GetDashboard(c.Req.Context(), &query); err != nil {
if errors.Is(err, models.ErrFolderNotFound) {
if errors.Is(err, dashboards.ErrFolderNotFound) {
return response.Error(404, "Folder not found", err)
}
return response.Error(500, "Dashboard folder could not be read", err)
@ -264,9 +264,9 @@ func (hs *HTTPServer) deleteDashboard(c *models.ReqContext) response.Response {
err = hs.dashboardService.DeleteDashboard(c.Req.Context(), dash.Id, c.OrgId)
if err != nil {
var dashboardErr models.DashboardErr
var dashboardErr dashboards.DashboardErr
if ok := errors.As(err, &dashboardErr); ok {
if errors.Is(err, models.ErrDashboardCannotDeleteProvisionedDashboard) {
if errors.Is(err, dashboards.ErrDashboardCannotDeleteProvisionedDashboard) {
return response.Error(dashboardErr.StatusCode, dashboardErr.Error(), err)
}
}
@ -333,7 +333,7 @@ func (hs *HTTPServer) postDashboard(c *models.ReqContext, cmd models.SaveDashboa
if cmd.FolderUid != "" {
folder, err := hs.folderService.GetFolderByUID(ctx, c.SignedInUser, c.OrgId, cmd.FolderUid)
if err != nil {
if errors.Is(err, models.ErrFolderNotFound) {
if errors.Is(err, dashboards.ErrFolderNotFound) {
return response.Error(400, "Folder not found", err)
}
return response.Error(500, "Error while checking folder ID", err)
@ -362,7 +362,7 @@ func (hs *HTTPServer) postDashboard(c *models.ReqContext, cmd models.SaveDashboa
provisioningData = data
} else if dash.Uid != "" {
data, err := hs.dashboardProvisioningService.GetProvisionedDashboardDataByDashboardUID(dash.OrgId, dash.Uid)
if err != nil && !errors.Is(err, models.ErrProvisionedDashboardNotFound) && !errors.Is(err, models.ErrDashboardNotFound) {
if err != nil && !errors.Is(err, dashboards.ErrProvisionedDashboardNotFound) && !errors.Is(err, dashboards.ErrDashboardNotFound) {
return response.Error(500, "Error while checking if dashboard is provisioned", err)
}
provisioningData = data

View File

@ -131,7 +131,7 @@ func (hs *HTTPServer) QueryPublicDashboard(c *models.ReqContext) response.Respon
// util to help us unpack a dashboard err or use default http code and message
func handleDashboardErr(defaultCode int, defaultMsg string, err error) response.Response {
var dashboardErr models.DashboardErr
var dashboardErr dashboards.DashboardErr
if ok := errors.As(err, &dashboardErr); ok {
return response.Error(dashboardErr.StatusCode, dashboardErr.Error(), dashboardErr)

View File

@ -87,7 +87,7 @@ func TestAPIGetPublicDashboard(t *testing.T) {
AccessToken: accessToken,
ExpectedHttpResponse: http.StatusNotFound,
publicDashboardResult: nil,
publicDashboardErr: models.ErrPublicDashboardNotFound,
publicDashboardErr: dashboards.ErrPublicDashboardNotFound,
},
}
@ -153,7 +153,7 @@ func TestAPIGetPublicDashboardConfig(t *testing.T) {
DashboardUid: "77777",
ExpectedHttpResponse: http.StatusNotFound,
PublicDashboardResult: nil,
PublicDashboardError: models.ErrDashboardNotFound,
PublicDashboardError: dashboards.ErrDashboardNotFound,
},
{
Name: "returns 500 when internal server error",
@ -218,7 +218,7 @@ func TestApiSavePublicDashboardConfig(t *testing.T) {
Name: "returns 404 when dashboard not found",
ExpectedHttpResponse: http.StatusNotFound,
publicDashboardConfig: &models.PublicDashboard{},
saveDashboardError: models.ErrDashboardNotFound,
saveDashboardError: dashboards.ErrDashboardNotFound,
},
}

View File

@ -13,6 +13,7 @@ import (
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/infra/metrics"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/dashboards"
"github.com/grafana/grafana/pkg/services/dashboardsnapshots"
"github.com/grafana/grafana/pkg/services/guardian"
"github.com/grafana/grafana/pkg/setting"
@ -272,11 +273,11 @@ func (hs *HTTPServer) DeleteDashboardSnapshot(c *models.ReqContext) response.Res
guardian := guardian.New(c.Req.Context(), dashboardID, c.OrgId, c.SignedInUser)
canEdit, err := guardian.CanEdit()
// check for permissions only if the dahboard is found
if err != nil && !errors.Is(err, models.ErrDashboardNotFound) {
if err != nil && !errors.Is(err, dashboards.ErrDashboardNotFound) {
return response.Error(500, "Error while checking permissions for snapshot", err)
}
if !canEdit && query.Result.UserId != c.SignedInUser.UserId && !errors.Is(err, models.ErrDashboardNotFound) {
if !canEdit && query.Result.UserId != c.SignedInUser.UserId && !errors.Is(err, dashboards.ErrDashboardNotFound) {
return response.Error(403, "Access denied to this snapshot", nil)
}

View File

@ -9,7 +9,6 @@ import (
"net/http"
"testing"
"github.com/grafana/grafana/pkg/framework/coremodel/registry"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
@ -18,6 +17,7 @@ import (
"github.com/grafana/grafana/pkg/api/response"
"github.com/grafana/grafana/pkg/api/routing"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/framework/coremodel/registry"
"github.com/grafana/grafana/pkg/infra/usagestats"
"github.com/grafana/grafana/pkg/models"
accesscontrolmock "github.com/grafana/grafana/pkg/services/accesscontrol/mock"
@ -679,24 +679,24 @@ func TestDashboardAPIEndpoint(t *testing.T) {
SaveError error
ExpectedStatusCode int
}{
{SaveError: models.ErrDashboardNotFound, ExpectedStatusCode: 404},
{SaveError: models.ErrFolderNotFound, ExpectedStatusCode: 400},
{SaveError: models.ErrDashboardWithSameUIDExists, ExpectedStatusCode: 400},
{SaveError: models.ErrDashboardWithSameNameInFolderExists, ExpectedStatusCode: 412},
{SaveError: models.ErrDashboardVersionMismatch, ExpectedStatusCode: 412},
{SaveError: models.ErrDashboardTitleEmpty, ExpectedStatusCode: 400},
{SaveError: models.ErrDashboardFolderCannotHaveParent, ExpectedStatusCode: 400},
{SaveError: dashboards.ErrDashboardNotFound, ExpectedStatusCode: 404},
{SaveError: dashboards.ErrFolderNotFound, ExpectedStatusCode: 400},
{SaveError: dashboards.ErrDashboardWithSameUIDExists, ExpectedStatusCode: 400},
{SaveError: dashboards.ErrDashboardWithSameNameInFolderExists, ExpectedStatusCode: 412},
{SaveError: dashboards.ErrDashboardVersionMismatch, ExpectedStatusCode: 412},
{SaveError: dashboards.ErrDashboardTitleEmpty, ExpectedStatusCode: 400},
{SaveError: dashboards.ErrDashboardFolderCannotHaveParent, ExpectedStatusCode: 400},
{SaveError: alerting.ValidationError{Reason: "Mu"}, ExpectedStatusCode: 422},
{SaveError: models.ErrDashboardFailedGenerateUniqueUid, ExpectedStatusCode: 500},
{SaveError: models.ErrDashboardTypeMismatch, ExpectedStatusCode: 400},
{SaveError: models.ErrDashboardFolderWithSameNameAsDashboard, ExpectedStatusCode: 400},
{SaveError: models.ErrDashboardWithSameNameAsFolder, ExpectedStatusCode: 400},
{SaveError: models.ErrDashboardFolderNameExists, ExpectedStatusCode: 400},
{SaveError: models.ErrDashboardUpdateAccessDenied, ExpectedStatusCode: 403},
{SaveError: models.ErrDashboardInvalidUid, ExpectedStatusCode: 400},
{SaveError: models.ErrDashboardUidTooLong, ExpectedStatusCode: 400},
{SaveError: models.ErrDashboardCannotSaveProvisionedDashboard, ExpectedStatusCode: 400},
{SaveError: models.UpdatePluginDashboardError{PluginId: "plug"}, ExpectedStatusCode: 412},
{SaveError: dashboards.ErrDashboardFailedGenerateUniqueUid, ExpectedStatusCode: 500},
{SaveError: dashboards.ErrDashboardTypeMismatch, ExpectedStatusCode: 400},
{SaveError: dashboards.ErrDashboardFolderWithSameNameAsDashboard, ExpectedStatusCode: 400},
{SaveError: dashboards.ErrDashboardWithSameNameAsFolder, ExpectedStatusCode: 400},
{SaveError: dashboards.ErrDashboardFolderNameExists, ExpectedStatusCode: 400},
{SaveError: dashboards.ErrDashboardUpdateAccessDenied, ExpectedStatusCode: 403},
{SaveError: dashboards.ErrDashboardInvalidUid, ExpectedStatusCode: 400},
{SaveError: dashboards.ErrDashboardUidTooLong, ExpectedStatusCode: 400},
{SaveError: dashboards.ErrDashboardCannotSaveProvisionedDashboard, ExpectedStatusCode: 400},
{SaveError: dashboards.UpdatePluginDashboardError{PluginId: "plug"}, ExpectedStatusCode: 412},
}
cmd := models.SaveDashboardCommand{

View File

@ -9,6 +9,7 @@ import (
"github.com/grafana/grafana/pkg/api/dtos"
"github.com/grafana/grafana/pkg/api/response"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/dashboards"
"github.com/grafana/grafana/pkg/services/guardian"
"github.com/grafana/grafana/pkg/util"
"github.com/grafana/grafana/pkg/web"
@ -24,7 +25,7 @@ func (hs *HTTPServer) GetFolderPermissionList(c *models.ReqContext) response.Res
g := guardian.New(c.Req.Context(), folder.Id, c.OrgId, c.SignedInUser)
if canAdmin, err := g.CanAdmin(); err != nil || !canAdmin {
return apierrors.ToFolderErrorResponse(models.ErrFolderAccessDenied)
return apierrors.ToFolderErrorResponse(dashboards.ErrFolderAccessDenied)
}
acl, err := g.GetAcl()
@ -78,7 +79,7 @@ func (hs *HTTPServer) UpdateFolderPermissions(c *models.ReqContext) response.Res
}
if !canAdmin {
return apierrors.ToFolderErrorResponse(models.ErrFolderAccessDenied)
return apierrors.ToFolderErrorResponse(dashboards.ErrFolderAccessDenied)
}
var items []*models.DashboardAcl

View File

@ -49,7 +49,7 @@ func TestFolderPermissionAPIEndpoint(t *testing.T) {
}
t.Run("Given folder not exists", func(t *testing.T) {
folderService.On("GetFolderByUID", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil, models.ErrFolderNotFound).Twice()
folderService.On("GetFolderByUID", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil, dashboards.ErrFolderNotFound).Twice()
mockSQLStore := mockstore.NewSQLStoreMock()
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/folders/uid/permissions", "/api/folders/:uid/permissions", models.ROLE_EDITOR, func(sc *scenarioContext) {
callGetFolderPermissions(sc, hs)
@ -81,7 +81,7 @@ func TestFolderPermissionAPIEndpoint(t *testing.T) {
})
guardian.MockDashboardGuardian(&guardian.FakeDashboardGuardian{CanAdminValue: false})
folderService.On("GetFolderByUID", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil, models.ErrFolderAccessDenied).Twice()
folderService.On("GetFolderByUID", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil, dashboards.ErrFolderAccessDenied).Twice()
mockSQLStore := mockstore.NewSQLStoreMock()
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/folders/uid/permissions", "/api/folders/:uid/permissions", models.ROLE_EDITOR, func(sc *scenarioContext) {

View File

@ -7,6 +7,10 @@ import (
"net/http"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
"github.com/grafana/grafana/pkg/api/dtos"
"github.com/grafana/grafana/pkg/api/response"
"github.com/grafana/grafana/pkg/api/routing"
@ -19,9 +23,6 @@ import (
"github.com/grafana/grafana/pkg/services/sqlstore/mockstore"
"github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana/pkg/web/webtest"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
)
func TestFoldersAPIEndpoint(t *testing.T) {
@ -55,15 +56,15 @@ func TestFoldersAPIEndpoint(t *testing.T) {
Error error
ExpectedStatusCode int
}{
{Error: models.ErrFolderWithSameUIDExists, ExpectedStatusCode: 409},
{Error: models.ErrFolderTitleEmpty, ExpectedStatusCode: 400},
{Error: models.ErrFolderSameNameExists, ExpectedStatusCode: 409},
{Error: models.ErrDashboardInvalidUid, ExpectedStatusCode: 400},
{Error: models.ErrDashboardUidTooLong, ExpectedStatusCode: 400},
{Error: models.ErrFolderAccessDenied, ExpectedStatusCode: 403},
{Error: models.ErrFolderNotFound, ExpectedStatusCode: 404},
{Error: models.ErrFolderVersionMismatch, ExpectedStatusCode: 412},
{Error: models.ErrFolderFailedGenerateUniqueUid, ExpectedStatusCode: 500},
{Error: dashboards.ErrFolderWithSameUIDExists, ExpectedStatusCode: 409},
{Error: dashboards.ErrFolderTitleEmpty, ExpectedStatusCode: 400},
{Error: dashboards.ErrFolderSameNameExists, ExpectedStatusCode: 409},
{Error: dashboards.ErrDashboardInvalidUid, ExpectedStatusCode: 400},
{Error: dashboards.ErrDashboardUidTooLong, ExpectedStatusCode: 400},
{Error: dashboards.ErrFolderAccessDenied, ExpectedStatusCode: 403},
{Error: dashboards.ErrFolderNotFound, ExpectedStatusCode: 404},
{Error: dashboards.ErrFolderVersionMismatch, ExpectedStatusCode: 412},
{Error: dashboards.ErrFolderFailedGenerateUniqueUid, ExpectedStatusCode: 500},
}
cmd := models.CreateFolderCommand{
@ -110,15 +111,15 @@ func TestFoldersAPIEndpoint(t *testing.T) {
Error error
ExpectedStatusCode int
}{
{Error: models.ErrFolderWithSameUIDExists, ExpectedStatusCode: 409},
{Error: models.ErrFolderTitleEmpty, ExpectedStatusCode: 400},
{Error: models.ErrFolderSameNameExists, ExpectedStatusCode: 409},
{Error: models.ErrDashboardInvalidUid, ExpectedStatusCode: 400},
{Error: models.ErrDashboardUidTooLong, ExpectedStatusCode: 400},
{Error: models.ErrFolderAccessDenied, ExpectedStatusCode: 403},
{Error: models.ErrFolderNotFound, ExpectedStatusCode: 404},
{Error: models.ErrFolderVersionMismatch, ExpectedStatusCode: 412},
{Error: models.ErrFolderFailedGenerateUniqueUid, ExpectedStatusCode: 500},
{Error: dashboards.ErrFolderWithSameUIDExists, ExpectedStatusCode: 409},
{Error: dashboards.ErrFolderTitleEmpty, ExpectedStatusCode: 400},
{Error: dashboards.ErrFolderSameNameExists, ExpectedStatusCode: 409},
{Error: dashboards.ErrDashboardInvalidUid, ExpectedStatusCode: 400},
{Error: dashboards.ErrDashboardUidTooLong, ExpectedStatusCode: 400},
{Error: dashboards.ErrFolderAccessDenied, ExpectedStatusCode: 403},
{Error: dashboards.ErrFolderNotFound, ExpectedStatusCode: 404},
{Error: dashboards.ErrFolderVersionMismatch, ExpectedStatusCode: 412},
{Error: dashboards.ErrFolderFailedGenerateUniqueUid, ExpectedStatusCode: 500},
}
cmd := models.UpdateFolderCommand{

View File

@ -10,173 +10,10 @@ import (
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana/pkg/util"
)
const RootFolderName = "General"
// Typed errors
var (
ErrDashboardNotFound = DashboardErr{
Reason: "Dashboard not found",
StatusCode: 404,
Status: "not-found",
}
ErrDashboardCorrupt = DashboardErr{
Reason: "Dashboard data is missing or corrupt",
StatusCode: 500,
Status: "not-found",
}
ErrDashboardPanelNotFound = DashboardErr{
Reason: "Dashboard panel not found",
StatusCode: 404,
Status: "not-found",
}
ErrDashboardFolderNotFound = DashboardErr{
Reason: "Folder not found",
StatusCode: 404,
}
ErrDashboardSnapshotNotFound = DashboardErr{
Reason: "Dashboard snapshot not found",
StatusCode: 404,
}
ErrDashboardWithSameUIDExists = DashboardErr{
Reason: "A dashboard with the same uid already exists",
StatusCode: 400,
}
ErrDashboardWithSameNameInFolderExists = DashboardErr{
Reason: "A dashboard with the same name in the folder already exists",
StatusCode: 412,
Status: "name-exists",
}
ErrDashboardVersionMismatch = DashboardErr{
Reason: "The dashboard has been changed by someone else",
StatusCode: 412,
Status: "version-mismatch",
}
ErrDashboardTitleEmpty = DashboardErr{
Reason: "Dashboard title cannot be empty",
StatusCode: 400,
Status: "empty-name",
}
ErrDashboardFolderCannotHaveParent = DashboardErr{
Reason: "A Dashboard Folder cannot be added to another folder",
StatusCode: 400,
}
ErrDashboardsWithSameSlugExists = DashboardErr{
Reason: "Multiple dashboards with the same slug exists",
StatusCode: 412,
}
ErrDashboardFailedGenerateUniqueUid = DashboardErr{
Reason: "Failed to generate unique dashboard id",
StatusCode: 500,
}
ErrDashboardTypeMismatch = DashboardErr{
Reason: "Dashboard cannot be changed to a folder",
StatusCode: 400,
}
ErrDashboardFolderWithSameNameAsDashboard = DashboardErr{
Reason: "Folder name cannot be the same as one of its dashboards",
StatusCode: 400,
}
ErrDashboardWithSameNameAsFolder = DashboardErr{
Reason: "Dashboard name cannot be the same as folder",
StatusCode: 400,
Status: "name-match",
}
ErrDashboardFolderNameExists = DashboardErr{
Reason: "A folder with that name already exists",
StatusCode: 400,
}
ErrDashboardUpdateAccessDenied = DashboardErr{
Reason: "Access denied to save dashboard",
StatusCode: 403,
}
ErrDashboardInvalidUid = DashboardErr{
Reason: "uid contains illegal characters",
StatusCode: 400,
}
ErrDashboardUidTooLong = DashboardErr{
Reason: "uid too long, max 40 characters",
StatusCode: 400,
}
ErrDashboardCannotSaveProvisionedDashboard = DashboardErr{
Reason: "Cannot save provisioned dashboard",
StatusCode: 400,
}
ErrDashboardRefreshIntervalTooShort = DashboardErr{
Reason: "Dashboard refresh interval is too low",
StatusCode: 400,
}
ErrDashboardCannotDeleteProvisionedDashboard = DashboardErr{
Reason: "provisioned dashboard cannot be deleted",
StatusCode: 400,
}
ErrDashboardIdentifierNotSet = DashboardErr{
Reason: "Unique identifier needed to be able to get a dashboard",
StatusCode: 400,
}
ErrDashboardIdentifierInvalid = DashboardErr{
Reason: "Dashboard ID not a number",
StatusCode: 400,
}
ErrDashboardPanelIdentifierInvalid = DashboardErr{
Reason: "Dashboard panel ID not a number",
StatusCode: 400,
}
ErrDashboardOrPanelIdentifierNotSet = DashboardErr{
Reason: "Unique identifier needed to be able to get a dashboard panel",
StatusCode: 400,
}
ErrProvisionedDashboardNotFound = DashboardErr{
Reason: "Dashboard is not provisioned",
StatusCode: 404,
Status: "not-found",
}
ErrDashboardThumbnailNotFound = DashboardErr{
Reason: "Dashboard thumbnail not found",
StatusCode: 404,
Status: "not-found",
}
)
// DashboardErr represents a dashboard error.
type DashboardErr struct {
StatusCode int
Status string
Reason string
}
// Equal returns whether equal to another DashboardErr.
func (e DashboardErr) Equal(o DashboardErr) bool {
return o.StatusCode == e.StatusCode && o.Status == e.Status && o.Reason == e.Reason
}
// Error returns the error message.
func (e DashboardErr) Error() string {
if e.Reason != "" {
return e.Reason
}
return "Dashboard Error"
}
// Body returns the error's response body, if applicable.
func (e DashboardErr) Body() util.DynMap {
if e.Status == "" {
return nil
}
return util.DynMap{"status": e.Status, "message": e.Error()}
}
type UpdatePluginDashboardError struct {
PluginId string
}
func (d UpdatePluginDashboardError) Error() string {
return "Dashboard belongs to plugin"
}
const (
DashTypeDB = "db"
DashTypeSnapshot = "snapshot"

View File

@ -6,31 +6,6 @@ import (
"github.com/grafana/grafana/pkg/components/simplejson"
)
var (
ErrPublicDashboardFailedGenerateUniqueUid = DashboardErr{
Reason: "Failed to generate unique public dashboard id",
StatusCode: 500,
}
ErrPublicDashboardFailedGenerateAccesstoken = DashboardErr{
Reason: "Failed to public dashboard access token",
StatusCode: 500,
}
ErrPublicDashboardNotFound = DashboardErr{
Reason: "Public dashboard not found",
StatusCode: 404,
Status: "not-found",
}
ErrPublicDashboardPanelNotFound = DashboardErr{
Reason: "Panel not found in dashboard",
StatusCode: 404,
Status: "not-found",
}
ErrPublicDashboardIdentifierNotSet = DashboardErr{
Reason: "No Uid for public dashboard specified",
StatusCode: 400,
}
)
type PublicDashboard struct {
Uid string `json:"uid" xorm:"pk uid"`
DashboardUid string `json:"dashboardUid" xorm:"dashboard_uid"`

View File

@ -1,24 +1,10 @@
package models
import (
"errors"
"strings"
"time"
)
// Typed errors
var (
ErrFolderNotFound = errors.New("folder not found")
ErrFolderVersionMismatch = errors.New("the folder has been changed by someone else")
ErrFolderTitleEmpty = errors.New("folder title cannot be empty")
ErrFolderWithSameUIDExists = errors.New("a folder/dashboard with the same uid already exists")
ErrFolderInvalidUID = errors.New("invalid uid for folder provided")
ErrFolderSameNameExists = errors.New("a folder or dashboard in the general folder with the same name already exists")
ErrFolderFailedGenerateUniqueUid = errors.New("failed to generate unique folder ID")
ErrFolderAccessDenied = errors.New("access denied to folder")
ErrFolderContainsAlertRules = errors.New("folder contains alert rules")
)
type Folder struct {
Id int64
Uid string

View File

@ -64,12 +64,12 @@ func TestNewFolderNameScopeResolver(t *testing.T) {
_, resolver := NewFolderNameScopeResolver(dashboardStore)
orgId := rand.Int63()
dashboardStore.On("GetFolderByTitle", mock.Anything, mock.Anything, mock.Anything).Return(nil, models.ErrDashboardNotFound).Once()
dashboardStore.On("GetFolderByTitle", mock.Anything, mock.Anything, mock.Anything).Return(nil, ErrDashboardNotFound).Once()
scope := "folders:name:" + util.GenerateShortUID()
resolvedScopes, err := resolver.Resolve(context.Background(), orgId, scope)
require.ErrorIs(t, err, models.ErrDashboardNotFound)
require.ErrorIs(t, err, ErrDashboardNotFound)
require.Nil(t, resolvedScopes)
})
}
@ -136,11 +136,11 @@ func TestNewFolderIDScopeResolver(t *testing.T) {
_, resolver := NewFolderIDScopeResolver(dashboardStore)
orgId := rand.Int63()
dashboardStore.On("GetFolderByID", mock.Anything, mock.Anything, mock.Anything).Return(nil, models.ErrDashboardNotFound).Once()
dashboardStore.On("GetFolderByID", mock.Anything, mock.Anything, mock.Anything).Return(nil, ErrDashboardNotFound).Once()
scope := "folders:id:10"
resolvedScopes, err := resolver.Resolve(context.Background(), orgId, scope)
require.ErrorIs(t, err, models.ErrDashboardNotFound)
require.ErrorIs(t, err, ErrDashboardNotFound)
require.Nil(t, resolvedScopes)
})
}

View File

@ -60,7 +60,7 @@ func (d *DashboardStore) ValidateDashboardBeforeSave(dashboard *models.Dashboard
func (d *DashboardStore) GetFolderByTitle(ctx context.Context, orgID int64, title string) (*models.Folder, error) {
if title == "" {
return nil, models.ErrFolderTitleEmpty
return nil, dashboards.ErrFolderTitleEmpty
}
// there is a unique constraint on org_id, folder_id, title
@ -72,7 +72,7 @@ func (d *DashboardStore) GetFolderByTitle(ctx context.Context, orgID int64, titl
return err
}
if !has {
return models.ErrFolderNotFound
return dashboards.ErrFolderNotFound
}
dashboard.SetId(dashboard.Id)
dashboard.SetUid(dashboard.Uid)
@ -89,7 +89,7 @@ func (d *DashboardStore) GetFolderByID(ctx context.Context, orgID int64, id int6
return err
}
if !has {
return models.ErrFolderNotFound
return dashboards.ErrFolderNotFound
}
dashboard.SetId(dashboard.Id)
dashboard.SetUid(dashboard.Uid)
@ -103,7 +103,7 @@ func (d *DashboardStore) GetFolderByID(ctx context.Context, orgID int64, id int6
func (d *DashboardStore) GetFolderByUID(ctx context.Context, orgID int64, uid string) (*models.Folder, error) {
if uid == "" {
return nil, models.ErrDashboardIdentifierNotSet
return nil, dashboards.ErrDashboardIdentifierNotSet
}
dashboard := models.Dashboard{OrgId: orgID, FolderId: 0, Uid: uid}
@ -113,7 +113,7 @@ func (d *DashboardStore) GetFolderByUID(ctx context.Context, orgID int64, uid st
return err
}
if !has {
return models.ErrFolderNotFound
return dashboards.ErrFolderNotFound
}
dashboard.SetId(dashboard.Id)
dashboard.SetUid(dashboard.Uid)
@ -147,15 +147,14 @@ func (d *DashboardStore) GetProvisionedDataByDashboardUID(orgID int64, dashboard
return err
}
if !exists {
return models.
ErrDashboardNotFound
return dashboards.ErrDashboardNotFound
}
exists, err = sess.Where("dashboard_id = ?", dashboard.Id).Get(&provisionedDashboard)
if err != nil {
return err
}
if !exists {
return models.ErrProvisionedDashboardNotFound
return dashboards.ErrProvisionedDashboardNotFound
}
return nil
})
@ -267,7 +266,7 @@ func (d *DashboardStore) DeleteOrphanedProvisionedDashboards(ctx context.Context
for _, deleteDashCommand := range result {
err := d.DeleteDashboard(ctx, &models.DeleteDashboardCommand{Id: deleteDashCommand.DashboardId})
if err != nil && !errors.Is(err, models.ErrDashboardNotFound) {
if err != nil && !errors.Is(err, dashboards.ErrDashboardNotFound) {
return err
}
}
@ -289,7 +288,7 @@ func getExistingDashboardByIdOrUidForUpdate(sess *sqlstore.DBSession, dash *mode
}
if !dashWithIdExists {
return false, models.ErrDashboardNotFound
return false, dashboards.ErrDashboardNotFound
}
if dash.Uid == "" {
@ -317,7 +316,7 @@ func getExistingDashboardByIdOrUidForUpdate(sess *sqlstore.DBSession, dash *mode
}
if !folderExists {
return false, models.ErrDashboardFolderNotFound
return false, dashboards.ErrDashboardFolderNotFound
}
}
@ -326,7 +325,7 @@ func getExistingDashboardByIdOrUidForUpdate(sess *sqlstore.DBSession, dash *mode
}
if dashWithIdExists && dashWithUidExists && existingById.Id != existingByUid.Id {
return false, models.ErrDashboardWithSameUIDExists
return false, dashboards.ErrDashboardWithSameUIDExists
}
existing := existingById
@ -339,7 +338,7 @@ func getExistingDashboardByIdOrUidForUpdate(sess *sqlstore.DBSession, dash *mode
if (existing.IsFolder && !dash.IsFolder) ||
(!existing.IsFolder && dash.IsFolder) {
return isParentFolderChanged, models.ErrDashboardTypeMismatch
return isParentFolderChanged, dashboards.ErrDashboardTypeMismatch
}
if !dash.IsFolder && dash.FolderId != existing.FolderId {
@ -351,13 +350,13 @@ func getExistingDashboardByIdOrUidForUpdate(sess *sqlstore.DBSession, dash *mode
if overwrite {
dash.SetVersion(existing.Version)
} else {
return isParentFolderChanged, models.ErrDashboardVersionMismatch
return isParentFolderChanged, dashboards.ErrDashboardVersionMismatch
}
}
// do not allow plugin dashboard updates without overwrite flag
if existing.PluginId != "" && !overwrite {
return isParentFolderChanged, models.UpdatePluginDashboardError{PluginId: existing.PluginId}
return isParentFolderChanged, dashboards.UpdatePluginDashboardError{PluginId: existing.PluginId}
}
return isParentFolderChanged, nil
@ -374,11 +373,11 @@ func getExistingDashboardByTitleAndFolder(sess *sqlstore.DBSession, dash *models
if exists && dash.Id != existing.Id {
if existing.IsFolder && !dash.IsFolder {
return isParentFolderChanged, models.ErrDashboardWithSameNameAsFolder
return isParentFolderChanged, dashboards.ErrDashboardWithSameNameAsFolder
}
if !existing.IsFolder && dash.IsFolder {
return isParentFolderChanged, models.ErrDashboardFolderWithSameNameAsDashboard
return isParentFolderChanged, dashboards.ErrDashboardFolderWithSameNameAsDashboard
}
if !dash.IsFolder && (dash.FolderId != existing.FolderId || dash.Id == 0) {
@ -390,7 +389,7 @@ func getExistingDashboardByTitleAndFolder(sess *sqlstore.DBSession, dash *models
dash.SetUid(existing.Uid)
dash.SetVersion(existing.Version)
} else {
return isParentFolderChanged, models.ErrDashboardWithSameNameInFolderExists
return isParentFolderChanged, dashboards.ErrDashboardWithSameNameInFolderExists
}
}
@ -413,7 +412,7 @@ func saveDashboard(sess *sqlstore.DBSession, cmd *models.SaveDashboardCommand) e
return err
}
if !dashWithIdExists {
return models.ErrDashboardNotFound
return dashboards.ErrDashboardNotFound
}
// check for is someone else has written in between
@ -421,13 +420,13 @@ func saveDashboard(sess *sqlstore.DBSession, cmd *models.SaveDashboardCommand) e
if cmd.Overwrite {
dash.SetVersion(existing.Version)
} else {
return models.ErrDashboardVersionMismatch
return dashboards.ErrDashboardVersionMismatch
}
}
// do not allow plugin dashboard updates without overwrite flag
if existing.PluginId != "" && !cmd.Overwrite {
return models.UpdatePluginDashboardError{PluginId: existing.PluginId}
return dashboards.UpdatePluginDashboardError{PluginId: existing.PluginId}
}
}
@ -470,7 +469,7 @@ func saveDashboard(sess *sqlstore.DBSession, cmd *models.SaveDashboardCommand) e
}
if affectedRows == 0 {
return models.ErrDashboardNotFound
return dashboards.ErrDashboardNotFound
}
dashVersion := &dashver.DashboardVersion{
@ -488,7 +487,7 @@ func saveDashboard(sess *sqlstore.DBSession, cmd *models.SaveDashboardCommand) e
if affectedRows, err = sess.Insert(dashVersion); err != nil {
return err
} else if affectedRows == 0 {
return models.ErrDashboardNotFound
return dashboards.ErrDashboardNotFound
}
// delete existing tags
@ -525,7 +524,7 @@ func generateNewDashboardUid(sess *sqlstore.DBSession, orgId int64) (string, err
}
}
return "", models.ErrDashboardFailedGenerateUniqueUid
return "", dashboards.ErrDashboardFailedGenerateUniqueUid
}
func saveProvisionedData(sess *sqlstore.DBSession, provisioning *models.DashboardProvisioning, dashboard *models.Dashboard) error {
@ -709,7 +708,7 @@ func (d *DashboardStore) deleteDashboard(cmd *models.DeleteDashboardCommand, ses
if err != nil {
return err
} else if !has {
return models.ErrDashboardNotFound
return dashboards.ErrDashboardNotFound
}
deletes := []string{
@ -779,7 +778,7 @@ func (d *DashboardStore) deleteDashboard(cmd *models.DeleteDashboardCommand, ses
}
if exists {
if !cmd.ForceDeleteFolderRules {
return fmt.Errorf("folder cannot be deleted: %w", models.ErrFolderContainsAlertRules)
return fmt.Errorf("folder cannot be deleted: %w", dashboards.ErrFolderContainsAlertRules)
}
// Delete all rules under this folder.
@ -836,7 +835,7 @@ func (d *DashboardStore) deleteAlertDefinition(dashboardId int64, sess *sqlstore
func (d *DashboardStore) GetDashboard(ctx context.Context, query *models.GetDashboardQuery) (*models.Dashboard, error) {
err := d.sqlStore.WithDbSession(ctx, func(sess *sqlstore.DBSession) error {
if query.Id == 0 && len(query.Slug) == 0 && len(query.Uid) == 0 {
return models.ErrDashboardIdentifierNotSet
return dashboards.ErrDashboardIdentifierNotSet
}
dashboard := models.Dashboard{Slug: query.Slug, OrgId: query.OrgId, Id: query.Id, Uid: query.Uid}
@ -845,7 +844,7 @@ func (d *DashboardStore) GetDashboard(ctx context.Context, query *models.GetDash
if err != nil {
return err
} else if !has {
return models.ErrDashboardNotFound
return dashboards.ErrDashboardNotFound
}
dashboard.SetId(dashboard.Id)
@ -865,7 +864,7 @@ func (d *DashboardStore) GetDashboardUIDById(ctx context.Context, query *models.
if err != nil {
return err
} else if !exists {
return models.ErrDashboardNotFound
return dashboards.ErrDashboardNotFound
}
query.Result = us
return nil

View File

@ -4,6 +4,7 @@ import (
"context"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/dashboards"
"github.com/grafana/grafana/pkg/services/sqlstore"
"github.com/grafana/grafana/pkg/util"
)
@ -11,7 +12,7 @@ import (
// retrieves public dashboard configuration
func (d *DashboardStore) GetPublicDashboard(ctx context.Context, accessToken string) (*models.PublicDashboard, *models.Dashboard, error) {
if accessToken == "" {
return nil, nil, models.ErrPublicDashboardIdentifierNotSet
return nil, nil, dashboards.ErrPublicDashboardIdentifierNotSet
}
// get public dashboard
@ -22,7 +23,7 @@ func (d *DashboardStore) GetPublicDashboard(ctx context.Context, accessToken str
return err
}
if !has {
return models.ErrPublicDashboardNotFound
return dashboards.ErrPublicDashboardNotFound
}
return nil
})
@ -39,7 +40,7 @@ func (d *DashboardStore) GetPublicDashboard(ctx context.Context, accessToken str
return err
}
if !has {
return models.ErrPublicDashboardNotFound
return dashboards.ErrPublicDashboardNotFound
}
return nil
})
@ -69,7 +70,7 @@ func (d *DashboardStore) GenerateNewPublicDashboardUid(ctx context.Context) (str
}
}
return models.ErrPublicDashboardFailedGenerateUniqueUid
return dashboards.ErrPublicDashboardFailedGenerateUniqueUid
})
if err != nil {
@ -82,7 +83,7 @@ func (d *DashboardStore) GenerateNewPublicDashboardUid(ctx context.Context) (str
// retrieves public dashboard configuration
func (d *DashboardStore) GetPublicDashboardConfig(ctx context.Context, orgId int64, dashboardUid string) (*models.PublicDashboard, error) {
if dashboardUid == "" {
return nil, models.ErrDashboardIdentifierNotSet
return nil, dashboards.ErrDashboardIdentifierNotSet
}
pdRes := &models.PublicDashboard{OrgId: orgId, DashboardUid: dashboardUid}

View File

@ -5,13 +5,15 @@ import (
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/dashboards"
"github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/services/sqlstore"
"github.com/grafana/grafana/pkg/util"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
// This is what the db sets empty time settings to
@ -58,13 +60,13 @@ func TestIntegrationGetPublicDashboard(t *testing.T) {
t.Run("returns ErrPublicDashboardNotFound with empty uid", func(t *testing.T) {
setup()
_, _, err := dashboardStore.GetPublicDashboard(context.Background(), "")
require.Error(t, models.ErrPublicDashboardIdentifierNotSet, err)
require.Error(t, dashboards.ErrPublicDashboardIdentifierNotSet, err)
})
t.Run("returns ErrPublicDashboardNotFound when PublicDashboard not found", func(t *testing.T) {
setup()
_, _, err := dashboardStore.GetPublicDashboard(context.Background(), "zzzzzz")
require.Error(t, models.ErrPublicDashboardNotFound, err)
require.Error(t, dashboards.ErrPublicDashboardNotFound, err)
})
t.Run("returns ErrDashboardNotFound when Dashboard not found", func(t *testing.T) {
@ -83,7 +85,7 @@ func TestIntegrationGetPublicDashboard(t *testing.T) {
})
require.NoError(t, err)
_, _, err = dashboardStore.GetPublicDashboard(context.Background(), "abc1234")
require.Error(t, models.ErrDashboardNotFound, err)
require.Error(t, dashboards.ErrDashboardNotFound, err)
})
}
@ -109,7 +111,7 @@ func TestIntegrationGetPublicDashboardConfig(t *testing.T) {
t.Run("returns dashboard errDashboardIdentifierNotSet", func(t *testing.T) {
setup()
_, err := dashboardStore.GetPublicDashboardConfig(context.Background(), savedDashboard.OrgId, "")
require.Error(t, models.ErrDashboardIdentifierNotSet, err)
require.Error(t, dashboards.ErrDashboardIdentifierNotSet, err)
})
t.Run("returns isPublic along with public dashboard when exists", func(t *testing.T) {

View File

@ -8,6 +8,7 @@ import (
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/dashboards"
"github.com/grafana/grafana/pkg/services/sqlstore"
"github.com/grafana/grafana/pkg/services/user"
)
@ -492,12 +493,12 @@ func TestIntegrationDashboardFolderDataAccess(t *testing.T) {
t.Run("should not find dashboard", func(t *testing.T) {
d, err := dashboardStore.GetFolderByUID(context.Background(), orgId, dash.Uid)
require.Nil(t, d)
require.ErrorIs(t, err, models.ErrFolderNotFound)
require.ErrorIs(t, err, dashboards.ErrFolderNotFound)
})
t.Run("should search in organization", func(t *testing.T) {
d, err := dashboardStore.GetFolderByUID(context.Background(), orgId+1, folder.Uid)
require.Nil(t, d)
require.ErrorIs(t, err, models.ErrFolderNotFound)
require.ErrorIs(t, err, dashboards.ErrFolderNotFound)
})
})
@ -516,12 +517,12 @@ func TestIntegrationDashboardFolderDataAccess(t *testing.T) {
t.Run("should not find dashboard", func(t *testing.T) {
d, err := dashboardStore.GetFolderByID(context.Background(), orgId, dash.Id)
require.Nil(t, d)
require.ErrorIs(t, err, models.ErrFolderNotFound)
require.ErrorIs(t, err, dashboards.ErrFolderNotFound)
})
t.Run("should search in organization", func(t *testing.T) {
d, err := dashboardStore.GetFolderByID(context.Background(), orgId+1, folder.Id)
require.Nil(t, d)
require.ErrorIs(t, err, models.ErrFolderNotFound)
require.ErrorIs(t, err, dashboards.ErrFolderNotFound)
})
})
})

View File

@ -124,7 +124,7 @@ func TestIntegrationDashboardDataAccess(t *testing.T) {
}
_, err := dashboardStore.GetDashboard(context.Background(), &query)
require.Equal(t, err, models.ErrDashboardIdentifierNotSet)
require.Equal(t, err, dashboards.ErrDashboardIdentifierNotSet)
})
t.Run("Should be able to get dashboards by IDs & UIDs", func(t *testing.T) {
@ -227,7 +227,7 @@ func TestIntegrationDashboardDataAccess(t *testing.T) {
setup()
deleteCmd := &models.DeleteDashboardCommand{Id: savedFolder.Id, ForceDeleteFolderRules: false}
err := dashboardStore.DeleteDashboard(context.Background(), deleteCmd)
require.True(t, errors.Is(err, models.ErrFolderContainsAlertRules))
require.True(t, errors.Is(err, dashboards.ErrFolderContainsAlertRules))
})
t.Run("Should be able to delete a dashboard folder and its children if force delete rules is enabled", func(t *testing.T) {
@ -274,7 +274,7 @@ func TestIntegrationDashboardDataAccess(t *testing.T) {
}
_, err := dashboardStore.SaveDashboard(cmd)
require.Equal(t, err, models.ErrDashboardNotFound)
require.Equal(t, err, dashboards.ErrDashboardNotFound)
})
t.Run("Should not return error if no dashboard is found for update when dashboard id is zero", func(t *testing.T) {

View File

@ -0,0 +1,197 @@
package dashboards
import (
"errors"
"github.com/grafana/grafana/pkg/util"
)
// Typed errors
var (
ErrDashboardNotFound = DashboardErr{
Reason: "Dashboard not found",
StatusCode: 404,
Status: "not-found",
}
ErrDashboardCorrupt = DashboardErr{
Reason: "Dashboard data is missing or corrupt",
StatusCode: 500,
Status: "not-found",
}
ErrDashboardPanelNotFound = DashboardErr{
Reason: "Dashboard panel not found",
StatusCode: 404,
Status: "not-found",
}
ErrDashboardFolderNotFound = DashboardErr{
Reason: "Folder not found",
StatusCode: 404,
}
ErrDashboardWithSameUIDExists = DashboardErr{
Reason: "A dashboard with the same uid already exists",
StatusCode: 400,
}
ErrDashboardWithSameNameInFolderExists = DashboardErr{
Reason: "A dashboard with the same name in the folder already exists",
StatusCode: 412,
Status: "name-exists",
}
ErrDashboardVersionMismatch = DashboardErr{
Reason: "The dashboard has been changed by someone else",
StatusCode: 412,
Status: "version-mismatch",
}
ErrDashboardTitleEmpty = DashboardErr{
Reason: "Dashboard title cannot be empty",
StatusCode: 400,
Status: "empty-name",
}
ErrDashboardFolderCannotHaveParent = DashboardErr{
Reason: "A Dashboard Folder cannot be added to another folder",
StatusCode: 400,
}
ErrDashboardsWithSameSlugExists = DashboardErr{
Reason: "Multiple dashboards with the same slug exists",
StatusCode: 412,
}
ErrDashboardFailedGenerateUniqueUid = DashboardErr{
Reason: "Failed to generate unique dashboard id",
StatusCode: 500,
}
ErrDashboardTypeMismatch = DashboardErr{
Reason: "Dashboard cannot be changed to a folder",
StatusCode: 400,
}
ErrDashboardFolderWithSameNameAsDashboard = DashboardErr{
Reason: "Folder name cannot be the same as one of its dashboards",
StatusCode: 400,
}
ErrDashboardWithSameNameAsFolder = DashboardErr{
Reason: "Dashboard name cannot be the same as folder",
StatusCode: 400,
Status: "name-match",
}
ErrDashboardFolderNameExists = DashboardErr{
Reason: "A folder with that name already exists",
StatusCode: 400,
}
ErrDashboardUpdateAccessDenied = DashboardErr{
Reason: "Access denied to save dashboard",
StatusCode: 403,
}
ErrDashboardInvalidUid = DashboardErr{
Reason: "uid contains illegal characters",
StatusCode: 400,
}
ErrDashboardUidTooLong = DashboardErr{
Reason: "uid too long, max 40 characters",
StatusCode: 400,
}
ErrDashboardCannotSaveProvisionedDashboard = DashboardErr{
Reason: "Cannot save provisioned dashboard",
StatusCode: 400,
}
ErrDashboardRefreshIntervalTooShort = DashboardErr{
Reason: "Dashboard refresh interval is too low",
StatusCode: 400,
}
ErrDashboardCannotDeleteProvisionedDashboard = DashboardErr{
Reason: "provisioned dashboard cannot be deleted",
StatusCode: 400,
}
ErrDashboardIdentifierNotSet = DashboardErr{
Reason: "Unique identifier needed to be able to get a dashboard",
StatusCode: 400,
}
ErrDashboardIdentifierInvalid = DashboardErr{
Reason: "Dashboard ID not a number",
StatusCode: 400,
}
ErrDashboardPanelIdentifierInvalid = DashboardErr{
Reason: "Dashboard panel ID not a number",
StatusCode: 400,
}
ErrDashboardOrPanelIdentifierNotSet = DashboardErr{
Reason: "Unique identifier needed to be able to get a dashboard panel",
StatusCode: 400,
}
ErrProvisionedDashboardNotFound = DashboardErr{
Reason: "Dashboard is not provisioned",
StatusCode: 404,
Status: "not-found",
}
ErrDashboardThumbnailNotFound = DashboardErr{
Reason: "Dashboard thumbnail not found",
StatusCode: 404,
Status: "not-found",
}
ErrPublicDashboardFailedGenerateUniqueUid = DashboardErr{
Reason: "Failed to generate unique public dashboard id",
StatusCode: 500,
}
ErrPublicDashboardFailedGenerateAccesstoken = DashboardErr{
Reason: "Failed to public dashboard access token",
StatusCode: 500,
}
ErrPublicDashboardNotFound = DashboardErr{
Reason: "Public dashboard not found",
StatusCode: 404,
Status: "not-found",
}
ErrPublicDashboardPanelNotFound = DashboardErr{
Reason: "Panel not found in dashboard",
StatusCode: 404,
Status: "not-found",
}
ErrPublicDashboardIdentifierNotSet = DashboardErr{
Reason: "No Uid for public dashboard specified",
StatusCode: 400,
}
ErrFolderNotFound = errors.New("folder not found")
ErrFolderVersionMismatch = errors.New("the folder has been changed by someone else")
ErrFolderTitleEmpty = errors.New("folder title cannot be empty")
ErrFolderWithSameUIDExists = errors.New("a folder/dashboard with the same uid already exists")
ErrFolderInvalidUID = errors.New("invalid uid for folder provided")
ErrFolderSameNameExists = errors.New("a folder or dashboard in the general folder with the same name already exists")
ErrFolderFailedGenerateUniqueUid = errors.New("failed to generate unique folder ID")
ErrFolderAccessDenied = errors.New("access denied to folder")
ErrFolderContainsAlertRules = errors.New("folder contains alert rules")
)
// DashboardErr represents a dashboard error.
type DashboardErr struct {
StatusCode int
Status string
Reason string
}
// Equal returns whether equal to another DashboardErr.
func (e DashboardErr) Equal(o DashboardErr) bool {
return o.StatusCode == e.StatusCode && o.Status == e.Status && o.Reason == e.Reason
}
// Error returns the error message.
func (e DashboardErr) Error() string {
if e.Reason != "" {
return e.Reason
}
return "Dashboard Error"
}
// Body returns the error's response body, if applicable.
func (e DashboardErr) Body() util.DynMap {
if e.Status == "" {
return nil
}
return util.DynMap{"status": e.Status, "message": e.Error()}
}
type UpdatePluginDashboardError struct {
PluginId string
}
func (d UpdatePluginDashboardError) Error() string {
return "Dashboard belongs to plugin"
}

View File

@ -6,6 +6,7 @@ import (
"time"
"github.com/gofrs/uuid"
"github.com/grafana/grafana/pkg/api/dtos"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/models"
@ -21,11 +22,11 @@ func (dr *DashboardServiceImpl) GetPublicDashboard(ctx context.Context, accessTo
}
if pubdash == nil || d == nil {
return nil, models.ErrPublicDashboardNotFound
return nil, dashboards.ErrPublicDashboardNotFound
}
if !pubdash.IsEnabled {
return nil, models.ErrPublicDashboardNotFound
return nil, dashboards.ErrPublicDashboardNotFound
}
ts := pubdash.BuildTimeSettings(d)
@ -49,7 +50,7 @@ func (dr *DashboardServiceImpl) GetPublicDashboardConfig(ctx context.Context, or
// to the database. It handles validations for sharing config and persistence
func (dr *DashboardServiceImpl) SavePublicDashboardConfig(ctx context.Context, dto *dashboards.SavePublicDashboardConfigDTO) (*models.PublicDashboard, error) {
if len(dto.DashboardUid) == 0 {
return nil, models.ErrDashboardIdentifierNotSet
return nil, dashboards.ErrDashboardIdentifierNotSet
}
// set default value for time settings
@ -125,13 +126,13 @@ func (dr *DashboardServiceImpl) updatePublicDashboardConfig(ctx context.Context,
// dashboard and returns a metrics request to be sent to query backend
func (dr *DashboardServiceImpl) BuildPublicDashboardMetricRequest(ctx context.Context, dashboard *models.Dashboard, publicDashboard *models.PublicDashboard, panelId int64) (dtos.MetricRequest, error) {
if !publicDashboard.IsEnabled {
return dtos.MetricRequest{}, models.ErrPublicDashboardNotFound
return dtos.MetricRequest{}, dashboards.ErrPublicDashboardNotFound
}
queriesByPanel := models.GetQueriesFromDashboard(dashboard.Data)
if _, ok := queriesByPanel[panelId]; !ok {
return dtos.MetricRequest{}, models.ErrPublicDashboardPanelNotFound
return dtos.MetricRequest{}, dashboards.ErrPublicDashboardPanelNotFound
}
ts := publicDashboard.BuildTimeSettings(dashboard)

View File

@ -6,15 +6,16 @@ import (
"time"
"github.com/gofrs/uuid"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/dashboards"
"github.com/grafana/grafana/pkg/services/dashboards/database"
"github.com/grafana/grafana/pkg/services/sqlstore"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
)
var timeSettings, _ = simplejson.NewJson([]byte(`{"from": "now-12", "to": "now"}`))
@ -66,21 +67,21 @@ func TestGetPublicDashboard(t *testing.T) {
d: &models.Dashboard{Uid: "mydashboard"},
err: nil,
},
ErrResp: models.ErrPublicDashboardNotFound,
ErrResp: dashboards.ErrPublicDashboardNotFound,
DashResp: nil,
},
{
Name: "returns ErrPublicDashboardNotFound if PublicDashboard missing",
AccessToken: "abc123",
StoreResp: &storeResp{pd: nil, d: nil, err: nil},
ErrResp: models.ErrPublicDashboardNotFound,
ErrResp: dashboards.ErrPublicDashboardNotFound,
DashResp: nil,
},
{
Name: "returns ErrPublicDashboardNotFound if Dashboard missing",
AccessToken: "abc123",
StoreResp: &storeResp{pd: nil, d: nil, err: nil},
ErrResp: models.ErrPublicDashboardNotFound,
ErrResp: dashboards.ErrPublicDashboardNotFound,
DashResp: nil,
},
}

View File

@ -83,21 +83,21 @@ func (dr *DashboardServiceImpl) BuildSaveDashboardCommand(ctx context.Context, d
dash.SetUid(strings.TrimSpace(dash.Uid))
if dash.Title == "" {
return nil, models.ErrDashboardTitleEmpty
return nil, dashboards.ErrDashboardTitleEmpty
}
if dash.IsFolder && dash.FolderId > 0 {
return nil, models.ErrDashboardFolderCannotHaveParent
return nil, dashboards.ErrDashboardFolderCannotHaveParent
}
if dash.IsFolder && strings.EqualFold(dash.Title, models.RootFolderName) {
return nil, models.ErrDashboardFolderNameExists
return nil, dashboards.ErrDashboardFolderNameExists
}
if !util.IsValidShortUID(dash.Uid) {
return nil, models.ErrDashboardInvalidUid
return nil, dashboards.ErrDashboardInvalidUid
} else if util.IsShortUIDTooLong(dash.Uid) {
return nil, models.ErrDashboardUidTooLong
return nil, dashboards.ErrDashboardUidTooLong
}
if err := validateDashboardRefreshInterval(dash); err != nil {
@ -123,7 +123,7 @@ func (dr *DashboardServiceImpl) BuildSaveDashboardCommand(ctx context.Context, d
if err != nil {
return nil, err
}
return nil, models.ErrDashboardUpdateAccessDenied
return nil, dashboards.ErrDashboardUpdateAccessDenied
}
}
@ -134,7 +134,7 @@ func (dr *DashboardServiceImpl) BuildSaveDashboardCommand(ctx context.Context, d
}
if provisionedData != nil {
return nil, models.ErrDashboardCannotSaveProvisionedDashboard
return nil, dashboards.ErrDashboardCannotSaveProvisionedDashboard
}
}
@ -144,14 +144,14 @@ func (dr *DashboardServiceImpl) BuildSaveDashboardCommand(ctx context.Context, d
if err != nil {
return nil, err
}
return nil, models.ErrDashboardUpdateAccessDenied
return nil, dashboards.ErrDashboardUpdateAccessDenied
}
} else {
if canSave, err := guard.CanSave(); err != nil || !canSave {
if err != nil {
return nil, err
}
return nil, models.ErrDashboardUpdateAccessDenied
return nil, dashboards.ErrDashboardUpdateAccessDenied
}
}
@ -202,7 +202,7 @@ func validateDashboardRefreshInterval(dash *models.Dashboard) error {
}
if d < minRefreshInterval {
return models.ErrDashboardRefreshIntervalTooShort
return dashboards.ErrDashboardRefreshIntervalTooShort
}
return nil
@ -414,7 +414,7 @@ func (dr *DashboardServiceImpl) deleteDashboard(ctx context.Context, dashboardId
}
if provisionedData != nil {
return models.ErrDashboardCannotDeleteProvisionedDashboard
return dashboards.ErrDashboardCannotDeleteProvisionedDashboard
}
}
cmd := &models.DeleteDashboardCommand{OrgId: orgId, Id: dashboardId}

View File

@ -11,7 +11,7 @@ import (
"github.com/grafana/grafana/pkg/models"
accesscontrolmock "github.com/grafana/grafana/pkg/services/accesscontrol/mock"
"github.com/grafana/grafana/pkg/services/alerting"
dashbboardservice "github.com/grafana/grafana/pkg/services/dashboards"
"github.com/grafana/grafana/pkg/services/dashboards"
"github.com/grafana/grafana/pkg/services/dashboards/database"
"github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/services/guardian"
@ -39,7 +39,7 @@ func TestIntegrationIntegratedDashboardService(t *testing.T) {
}
err := callSaveWithError(cmd, sc.sqlStore)
assert.Equal(t, models.ErrDashboardNotFound, err)
assert.Equal(t, dashboards.ErrDashboardNotFound, err)
})
// Given other organization
@ -59,7 +59,7 @@ func TestIntegrationIntegratedDashboardService(t *testing.T) {
}
err := callSaveWithError(cmd, sc.sqlStore)
assert.Equal(t, models.ErrDashboardNotFound, err)
assert.Equal(t, dashboards.ErrDashboardNotFound, err)
})
permissionScenario(t, "When creating a dashboard with same uid as dashboard in organization A, it should create a new dashboard in org B",
@ -101,7 +101,7 @@ func TestIntegrationIntegratedDashboardService(t *testing.T) {
}
err := callSaveWithError(cmd, sqlStore)
assert.Equal(t, models.ErrDashboardUpdateAccessDenied, err)
assert.Equal(t, dashboards.ErrDashboardUpdateAccessDenied, err)
assert.Equal(t, int64(0), sc.dashboardGuardianMock.DashId)
assert.Equal(t, cmd.OrgId, sc.dashboardGuardianMock.OrgId)
@ -121,7 +121,7 @@ func TestIntegrationIntegratedDashboardService(t *testing.T) {
}
err := callSaveWithError(cmd, sc.sqlStore)
require.Equal(t, models.ErrDashboardUpdateAccessDenied, err)
require.Equal(t, dashboards.ErrDashboardUpdateAccessDenied, err)
assert.Equal(t, sc.otherSavedFolder.Id, sc.dashboardGuardianMock.DashId)
assert.Equal(t, cmd.OrgId, sc.dashboardGuardianMock.OrgId)
@ -141,7 +141,7 @@ func TestIntegrationIntegratedDashboardService(t *testing.T) {
}
err := callSaveWithError(cmd, sc.sqlStore)
require.Equal(t, models.ErrDashboardUpdateAccessDenied, err)
require.Equal(t, dashboards.ErrDashboardUpdateAccessDenied, err)
assert.Equal(t, sc.savedDashInFolder.Id, sc.dashboardGuardianMock.DashId)
assert.Equal(t, cmd.OrgId, sc.dashboardGuardianMock.OrgId)
@ -162,7 +162,7 @@ func TestIntegrationIntegratedDashboardService(t *testing.T) {
}
err := callSaveWithError(cmd, sc.sqlStore)
require.Equal(t, models.ErrDashboardUpdateAccessDenied, err)
require.Equal(t, dashboards.ErrDashboardUpdateAccessDenied, err)
assert.Equal(t, sc.savedDashInFolder.Id, sc.dashboardGuardianMock.DashId)
assert.Equal(t, cmd.OrgId, sc.dashboardGuardianMock.OrgId)
@ -183,7 +183,7 @@ func TestIntegrationIntegratedDashboardService(t *testing.T) {
}
err := callSaveWithError(cmd, sc.sqlStore)
assert.Equal(t, models.ErrDashboardUpdateAccessDenied, err)
assert.Equal(t, dashboards.ErrDashboardUpdateAccessDenied, err)
assert.Equal(t, sc.savedDashInGeneralFolder.Id, sc.dashboardGuardianMock.DashId)
assert.Equal(t, cmd.OrgId, sc.dashboardGuardianMock.OrgId)
@ -204,7 +204,7 @@ func TestIntegrationIntegratedDashboardService(t *testing.T) {
}
err := callSaveWithError(cmd, sc.sqlStore)
require.Equal(t, models.ErrDashboardUpdateAccessDenied, err)
require.Equal(t, dashboards.ErrDashboardUpdateAccessDenied, err)
assert.Equal(t, sc.savedDashInFolder.Id, sc.dashboardGuardianMock.DashId)
assert.Equal(t, cmd.OrgId, sc.dashboardGuardianMock.OrgId)
@ -225,7 +225,7 @@ func TestIntegrationIntegratedDashboardService(t *testing.T) {
}
err := callSaveWithError(cmd, sc.sqlStore)
require.Equal(t, models.ErrDashboardUpdateAccessDenied, err)
require.Equal(t, dashboards.ErrDashboardUpdateAccessDenied, err)
assert.Equal(t, sc.savedDashInGeneralFolder.Id, sc.dashboardGuardianMock.DashId)
assert.Equal(t, cmd.OrgId, sc.dashboardGuardianMock.OrgId)
@ -246,7 +246,7 @@ func TestIntegrationIntegratedDashboardService(t *testing.T) {
}
err := callSaveWithError(cmd, sc.sqlStore)
assert.Equal(t, models.ErrDashboardUpdateAccessDenied, err)
assert.Equal(t, dashboards.ErrDashboardUpdateAccessDenied, err)
assert.Equal(t, sc.savedDashInFolder.Id, sc.dashboardGuardianMock.DashId)
assert.Equal(t, cmd.OrgId, sc.dashboardGuardianMock.OrgId)
@ -267,7 +267,7 @@ func TestIntegrationIntegratedDashboardService(t *testing.T) {
}
err := callSaveWithError(cmd, sc.sqlStore)
require.Equal(t, models.ErrDashboardUpdateAccessDenied, err)
require.Equal(t, dashboards.ErrDashboardUpdateAccessDenied, err)
assert.Equal(t, sc.savedDashInGeneralFolder.Id, sc.dashboardGuardianMock.DashId)
assert.Equal(t, cmd.OrgId, sc.dashboardGuardianMock.OrgId)
@ -288,7 +288,7 @@ func TestIntegrationIntegratedDashboardService(t *testing.T) {
}
err := callSaveWithError(cmd, sc.sqlStore)
require.Equal(t, models.ErrDashboardUpdateAccessDenied, err)
require.Equal(t, dashboards.ErrDashboardUpdateAccessDenied, err)
assert.Equal(t, sc.savedDashInFolder.Id, sc.dashboardGuardianMock.DashId)
assert.Equal(t, cmd.OrgId, sc.dashboardGuardianMock.OrgId)
@ -429,7 +429,7 @@ func TestIntegrationIntegratedDashboardService(t *testing.T) {
}
err := callSaveWithError(cmd, sc.sqlStore)
assert.Equal(t, models.ErrDashboardFolderNotFound, err)
assert.Equal(t, dashboards.ErrDashboardFolderNotFound, err)
})
permissionScenario(t, "When updating an existing dashboard by id without current version", canSave,
@ -445,7 +445,7 @@ func TestIntegrationIntegratedDashboardService(t *testing.T) {
}
err := callSaveWithError(cmd, sc.sqlStore)
assert.Equal(t, models.ErrDashboardVersionMismatch, err)
assert.Equal(t, dashboards.ErrDashboardVersionMismatch, err)
})
permissionScenario(t, "When updating an existing dashboard by id with current version", canSave,
@ -485,7 +485,7 @@ func TestIntegrationIntegratedDashboardService(t *testing.T) {
}
err := callSaveWithError(cmd, sc.sqlStore)
assert.Equal(t, models.ErrDashboardVersionMismatch, err)
assert.Equal(t, dashboards.ErrDashboardVersionMismatch, err)
})
permissionScenario(t, "When updating an existing dashboard by uid with current version", canSave,
@ -524,7 +524,7 @@ func TestIntegrationIntegratedDashboardService(t *testing.T) {
}
err := callSaveWithError(cmd, sc.sqlStore)
assert.Equal(t, models.ErrDashboardWithSameNameInFolderExists, err)
assert.Equal(t, dashboards.ErrDashboardWithSameNameInFolderExists, err)
})
permissionScenario(t, "When creating a dashboard with same name as dashboard in General folder",
@ -540,7 +540,7 @@ func TestIntegrationIntegratedDashboardService(t *testing.T) {
}
err := callSaveWithError(cmd, sc.sqlStore)
assert.Equal(t, models.ErrDashboardWithSameNameInFolderExists, err)
assert.Equal(t, dashboards.ErrDashboardWithSameNameInFolderExists, err)
})
permissionScenario(t, "When creating a folder with same name as existing folder", canSave,
@ -556,7 +556,7 @@ func TestIntegrationIntegratedDashboardService(t *testing.T) {
}
err := callSaveWithError(cmd, sc.sqlStore)
assert.Equal(t, models.ErrDashboardWithSameNameInFolderExists, err)
assert.Equal(t, dashboards.ErrDashboardWithSameNameInFolderExists, err)
})
})
@ -644,7 +644,7 @@ func TestIntegrationIntegratedDashboardService(t *testing.T) {
}
err := callSaveWithError(cmd, sc.sqlStore)
assert.Equal(t, models.ErrDashboardWithSameUIDExists, err)
assert.Equal(t, dashboards.ErrDashboardWithSameUIDExists, err)
})
permissionScenario(t, "When creating a dashboard with same name as dashboard in other folder", canSave,
@ -708,7 +708,7 @@ func TestIntegrationIntegratedDashboardService(t *testing.T) {
}
err := callSaveWithError(cmd, sc.sqlStore)
assert.Equal(t, models.ErrDashboardTypeMismatch, err)
assert.Equal(t, dashboards.ErrDashboardTypeMismatch, err)
})
permissionScenario(t, "When updating existing dashboard to a folder using id", canSave,
@ -724,7 +724,7 @@ func TestIntegrationIntegratedDashboardService(t *testing.T) {
}
err := callSaveWithError(cmd, sc.sqlStore)
assert.Equal(t, models.ErrDashboardTypeMismatch, err)
assert.Equal(t, dashboards.ErrDashboardTypeMismatch, err)
})
permissionScenario(t, "When updating existing folder to a dashboard using uid", canSave,
@ -740,7 +740,7 @@ func TestIntegrationIntegratedDashboardService(t *testing.T) {
}
err := callSaveWithError(cmd, sc.sqlStore)
assert.Equal(t, models.ErrDashboardTypeMismatch, err)
assert.Equal(t, dashboards.ErrDashboardTypeMismatch, err)
})
permissionScenario(t, "When updating existing dashboard to a folder using uid", canSave,
@ -756,7 +756,7 @@ func TestIntegrationIntegratedDashboardService(t *testing.T) {
}
err := callSaveWithError(cmd, sc.sqlStore)
assert.Equal(t, models.ErrDashboardTypeMismatch, err)
assert.Equal(t, dashboards.ErrDashboardTypeMismatch, err)
})
permissionScenario(t, "When updating existing folder to a dashboard using title", canSave,
@ -771,7 +771,7 @@ func TestIntegrationIntegratedDashboardService(t *testing.T) {
}
err := callSaveWithError(cmd, sc.sqlStore)
assert.Equal(t, models.ErrDashboardWithSameNameAsFolder, err)
assert.Equal(t, dashboards.ErrDashboardWithSameNameAsFolder, err)
})
permissionScenario(t, "When updating existing dashboard to a folder using title", canSave,
@ -786,7 +786,7 @@ func TestIntegrationIntegratedDashboardService(t *testing.T) {
}
err := callSaveWithError(cmd, sc.sqlStore)
assert.Equal(t, models.ErrDashboardFolderWithSameNameAsDashboard, err)
assert.Equal(t, dashboards.ErrDashboardFolderWithSameNameAsDashboard, err)
})
})
})
@ -796,7 +796,7 @@ func TestIntegrationIntegratedDashboardService(t *testing.T) {
type permissionScenarioContext struct {
dashboardGuardianMock *guardian.FakeDashboardGuardian
sqlStore *sqlstore.SQLStore
dashboardStore dashbboardservice.Store
dashboardStore dashboards.Store
savedFolder *models.Dashboard
savedDashInFolder *models.Dashboard
otherSavedFolder *models.Dashboard
@ -913,7 +913,7 @@ func saveTestDashboard(t *testing.T, title string, orgID, folderID int64, sqlSto
}),
}
dto := dashbboardservice.SaveDashboardDTO{
dto := dashboards.SaveDashboardDTO{
OrgId: orgID,
Dashboard: cmd.GetDashboardModel(),
User: &models.SignedInUser{
@ -950,7 +950,7 @@ func saveTestFolder(t *testing.T, title string, orgID int64, sqlStore *sqlstore.
}),
}
dto := dashbboardservice.SaveDashboardDTO{
dto := dashboards.SaveDashboardDTO{
OrgId: orgID,
Dashboard: cmd.GetDashboardModel(),
User: &models.SignedInUser{
@ -975,10 +975,10 @@ func saveTestFolder(t *testing.T, title string, orgID int64, sqlStore *sqlstore.
return res
}
func toSaveDashboardDto(cmd models.SaveDashboardCommand) dashbboardservice.SaveDashboardDTO {
func toSaveDashboardDto(cmd models.SaveDashboardCommand) dashboards.SaveDashboardDTO {
dash := (&cmd).GetDashboardModel()
return dashbboardservice.SaveDashboardDTO{
return dashboards.SaveDashboardDTO{
Dashboard: dash,
Message: cmd.Message,
OrgId: cmd.OrgId,

View File

@ -11,7 +11,7 @@ import (
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/models"
m "github.com/grafana/grafana/pkg/services/dashboards"
"github.com/grafana/grafana/pkg/services/dashboards"
"github.com/grafana/grafana/pkg/services/guardian"
"github.com/grafana/grafana/pkg/setting"
)
@ -21,7 +21,7 @@ func TestIntegrationDashboardService(t *testing.T) {
t.Skip("skipping integration test")
}
t.Run("Dashboard service tests", func(t *testing.T) {
fakeStore := m.FakeDashboardStore{}
fakeStore := dashboards.FakeDashboardStore{}
defer fakeStore.AssertExpectations(t)
service := &DashboardServiceImpl{
log: log.New("test.logger"),
@ -34,7 +34,7 @@ func TestIntegrationDashboardService(t *testing.T) {
guardian.MockDashboardGuardian(&guardian.FakeDashboardGuardian{CanSaveValue: true})
t.Run("Save dashboard validation", func(t *testing.T) {
dto := &m.SaveDashboardDTO{}
dto := &dashboards.SaveDashboardDTO{}
t.Run("When saving a dashboard with empty title it should return error", func(t *testing.T) {
titles := []string{"", " ", " \t "}
@ -42,7 +42,7 @@ func TestIntegrationDashboardService(t *testing.T) {
for _, title := range titles {
dto.Dashboard = models.NewDashboard(title)
_, err := service.SaveDashboard(context.Background(), dto, false)
require.Equal(t, err, models.ErrDashboardTitleEmpty)
require.Equal(t, err, dashboards.ErrDashboardTitleEmpty)
}
})
@ -50,13 +50,13 @@ func TestIntegrationDashboardService(t *testing.T) {
dto.Dashboard = models.NewDashboardFolder("Folder")
dto.Dashboard.FolderId = 1
_, err := service.SaveDashboard(context.Background(), dto, false)
require.Equal(t, err, models.ErrDashboardFolderCannotHaveParent)
require.Equal(t, err, dashboards.ErrDashboardFolderCannotHaveParent)
})
t.Run("Should return validation error if folder is named General", func(t *testing.T) {
dto.Dashboard = models.NewDashboardFolder("General")
_, err := service.SaveDashboard(context.Background(), dto, false)
require.Equal(t, err, models.ErrDashboardFolderNameExists)
require.Equal(t, err, dashboards.ErrDashboardFolderNameExists)
})
t.Run("When saving a dashboard should validate uid", func(t *testing.T) {
@ -68,9 +68,9 @@ func TestIntegrationDashboardService(t *testing.T) {
{Uid: " ", Error: nil},
{Uid: " \t ", Error: nil},
{Uid: "asdf90_-", Error: nil},
{Uid: "asdf/90", Error: models.ErrDashboardInvalidUid},
{Uid: "asdf/90", Error: dashboards.ErrDashboardInvalidUid},
{Uid: " asdfghjklqwertyuiopzxcvbnmasdfghjklqwer ", Error: nil},
{Uid: "asdfghjklqwertyuiopzxcvbnmasdfghjklqwertyuiopzxcvbnmasdfghjklqwertyuiopzxcvbnm", Error: models.ErrDashboardUidTooLong},
{Uid: "asdfghjklqwertyuiopzxcvbnmasdfghjklqwertyuiopzxcvbnmasdfghjklqwertyuiopzxcvbnm", Error: dashboards.ErrDashboardUidTooLong},
}
for _, tc := range testCases {
@ -94,7 +94,7 @@ func TestIntegrationDashboardService(t *testing.T) {
dto.Dashboard.SetId(3)
dto.User = &models.SignedInUser{UserId: 1}
_, err := service.SaveDashboard(context.Background(), dto, false)
require.Equal(t, err, models.ErrDashboardCannotSaveProvisionedDashboard)
require.Equal(t, err, dashboards.ErrDashboardCannotSaveProvisionedDashboard)
})
t.Run("Should not return validation error if dashboard is provisioned but UI updates allowed", func(t *testing.T) {
@ -123,7 +123,7 @@ func TestIntegrationDashboardService(t *testing.T) {
})
t.Run("Save provisioned dashboard validation", func(t *testing.T) {
dto := &m.SaveDashboardDTO{}
dto := &dashboards.SaveDashboardDTO{}
t.Run("Should not return validation error if dashboard is provisioned", func(t *testing.T) {
fakeStore.On("ValidateDashboardBeforeSave", mock.Anything, mock.Anything).Return(true, nil).Once()
@ -157,7 +157,7 @@ func TestIntegrationDashboardService(t *testing.T) {
})
t.Run("Import dashboard validation", func(t *testing.T) {
dto := &m.SaveDashboardDTO{}
dto := &dashboards.SaveDashboardDTO{}
t.Run("Should return validation error if dashboard is provisioned", func(t *testing.T) {
fakeStore.On("ValidateDashboardBeforeSave", mock.Anything, mock.Anything).Return(true, nil).Once()
@ -167,7 +167,7 @@ func TestIntegrationDashboardService(t *testing.T) {
dto.Dashboard.SetId(3)
dto.User = &models.SignedInUser{UserId: 1}
_, err := service.ImportDashboard(context.Background(), dto)
require.Equal(t, err, models.ErrDashboardCannotSaveProvisionedDashboard)
require.Equal(t, err, dashboards.ErrDashboardCannotSaveProvisionedDashboard)
})
})
@ -182,7 +182,7 @@ func TestIntegrationDashboardService(t *testing.T) {
t.Run("DeleteDashboard should fail to delete it when provisioning information is missing", func(t *testing.T) {
fakeStore.On("GetProvisionedDataByDashboardID", mock.Anything).Return(&models.DashboardProvisioning{}, nil).Once()
err := service.DeleteDashboard(context.Background(), 1, 1)
require.Equal(t, err, models.ErrDashboardCannotDeleteProvisionedDashboard)
require.Equal(t, err, dashboards.ErrDashboardCannotDeleteProvisionedDashboard)
})
})

View File

@ -94,7 +94,7 @@ func (f *FolderServiceImpl) GetFolderByID(ctx context.Context, user *models.Sign
if err != nil {
return nil, toFolderError(err)
}
return nil, models.ErrFolderAccessDenied
return nil, dashboards.ErrFolderAccessDenied
}
return dashFolder, nil
@ -111,7 +111,7 @@ func (f *FolderServiceImpl) GetFolderByUID(ctx context.Context, user *models.Sig
if err != nil {
return nil, toFolderError(err)
}
return nil, models.ErrFolderAccessDenied
return nil, dashboards.ErrFolderAccessDenied
}
return dashFolder, nil
@ -128,7 +128,7 @@ func (f *FolderServiceImpl) GetFolderByTitle(ctx context.Context, user *models.S
if err != nil {
return nil, toFolderError(err)
}
return nil, models.ErrFolderAccessDenied
return nil, dashboards.ErrFolderAccessDenied
}
return dashFolder, nil
@ -140,7 +140,7 @@ func (f *FolderServiceImpl) CreateFolder(ctx context.Context, user *models.Signe
trimmedUID := strings.TrimSpace(uid)
if trimmedUID == accesscontrol.GeneralFolderUID {
return nil, models.ErrFolderInvalidUID
return nil, dashboards.ErrFolderInvalidUID
}
dashFolder.SetUid(trimmedUID)
@ -201,7 +201,7 @@ func (f *FolderServiceImpl) UpdateFolder(ctx context.Context, user *models.Signe
dashFolder := query.Result
if !dashFolder.IsFolder {
return models.ErrFolderNotFound
return dashboards.ErrFolderNotFound
}
cmd.UpdateDashboardModel(dashFolder, orgID, user.UserId)
@ -254,7 +254,7 @@ func (f *FolderServiceImpl) DeleteFolder(ctx context.Context, user *models.Signe
if err != nil {
return nil, toFolderError(err)
}
return nil, models.ErrFolderAccessDenied
return nil, dashboards.ErrFolderAccessDenied
}
deleteCmd := models.DeleteDashboardCommand{OrgId: orgID, Id: dashFolder.Id, ForceDeleteFolderRules: forceDeleteRules}
@ -271,32 +271,32 @@ func (f *FolderServiceImpl) MakeUserAdmin(ctx context.Context, orgID int64, user
}
func toFolderError(err error) error {
if errors.Is(err, models.ErrDashboardTitleEmpty) {
return models.ErrFolderTitleEmpty
if errors.Is(err, dashboards.ErrDashboardTitleEmpty) {
return dashboards.ErrFolderTitleEmpty
}
if errors.Is(err, models.ErrDashboardUpdateAccessDenied) {
return models.ErrFolderAccessDenied
if errors.Is(err, dashboards.ErrDashboardUpdateAccessDenied) {
return dashboards.ErrFolderAccessDenied
}
if errors.Is(err, models.ErrDashboardWithSameNameInFolderExists) {
return models.ErrFolderSameNameExists
if errors.Is(err, dashboards.ErrDashboardWithSameNameInFolderExists) {
return dashboards.ErrFolderSameNameExists
}
if errors.Is(err, models.ErrDashboardWithSameUIDExists) {
return models.ErrFolderWithSameUIDExists
if errors.Is(err, dashboards.ErrDashboardWithSameUIDExists) {
return dashboards.ErrFolderWithSameUIDExists
}
if errors.Is(err, models.ErrDashboardVersionMismatch) {
return models.ErrFolderVersionMismatch
if errors.Is(err, dashboards.ErrDashboardVersionMismatch) {
return dashboards.ErrFolderVersionMismatch
}
if errors.Is(err, models.ErrDashboardNotFound) {
return models.ErrFolderNotFound
if errors.Is(err, dashboards.ErrDashboardNotFound) {
return dashboards.ErrFolderNotFound
}
if errors.Is(err, models.ErrDashboardFailedGenerateUniqueUid) {
err = models.ErrFolderFailedGenerateUniqueUid
if errors.Is(err, dashboards.ErrDashboardFailedGenerateUniqueUid) {
err = dashboards.ErrFolderFailedGenerateUniqueUid
}
return err

View File

@ -77,7 +77,7 @@ func TestIntegrationFolderService(t *testing.T) {
t.Run("When get folder by id should return access denied error", func(t *testing.T) {
_, err := service.GetFolderByID(context.Background(), user, folderId, orgID)
require.Equal(t, err, models.ErrFolderAccessDenied)
require.Equal(t, err, dashboards.ErrFolderAccessDenied)
})
t.Run("When get folder by id, with id = 0 should return default folder", func(t *testing.T) {
@ -88,13 +88,13 @@ func TestIntegrationFolderService(t *testing.T) {
t.Run("When get folder by uid should return access denied error", func(t *testing.T) {
_, err := service.GetFolderByUID(context.Background(), user, orgID, folderUID)
require.Equal(t, err, models.ErrFolderAccessDenied)
require.Equal(t, err, dashboards.ErrFolderAccessDenied)
})
t.Run("When creating folder should return access denied error", func(t *testing.T) {
store.On("ValidateDashboardBeforeSave", mock.Anything, mock.Anything).Return(true, nil).Times(2)
_, err := service.CreateFolder(context.Background(), user, orgID, folder.Title, folderUID)
require.Equal(t, err, models.ErrFolderAccessDenied)
require.Equal(t, err, dashboards.ErrFolderAccessDenied)
})
t.Run("When updating folder should return access denied error", func(t *testing.T) {
@ -107,13 +107,13 @@ func TestIntegrationFolderService(t *testing.T) {
Uid: folderUID,
Title: "Folder-TEST",
})
require.Equal(t, err, models.ErrFolderAccessDenied)
require.Equal(t, err, dashboards.ErrFolderAccessDenied)
})
t.Run("When deleting folder by uid should return access denied error", func(t *testing.T) {
_, err := service.DeleteFolder(context.Background(), user, orgID, folderUID, false)
require.Error(t, err)
require.Equal(t, err, models.ErrFolderAccessDenied)
require.Equal(t, err, dashboards.ErrFolderAccessDenied)
})
t.Cleanup(func() {
@ -144,7 +144,7 @@ func TestIntegrationFolderService(t *testing.T) {
dash.Id = rand.Int63()
_, err := service.CreateFolder(context.Background(), user, orgID, dash.Title, "general")
require.ErrorIs(t, err, models.ErrFolderInvalidUID)
require.ErrorIs(t, err, dashboards.ErrFolderInvalidUID)
})
t.Run("When updating folder should not return access denied error", func(t *testing.T) {
@ -238,14 +238,14 @@ func TestIntegrationFolderService(t *testing.T) {
ActualError error
ExpectedError error
}{
{ActualError: models.ErrDashboardTitleEmpty, ExpectedError: models.ErrFolderTitleEmpty},
{ActualError: models.ErrDashboardUpdateAccessDenied, ExpectedError: models.ErrFolderAccessDenied},
{ActualError: models.ErrDashboardWithSameNameInFolderExists, ExpectedError: models.ErrFolderSameNameExists},
{ActualError: models.ErrDashboardWithSameUIDExists, ExpectedError: models.ErrFolderWithSameUIDExists},
{ActualError: models.ErrDashboardVersionMismatch, ExpectedError: models.ErrFolderVersionMismatch},
{ActualError: models.ErrDashboardNotFound, ExpectedError: models.ErrFolderNotFound},
{ActualError: models.ErrDashboardFailedGenerateUniqueUid, ExpectedError: models.ErrFolderFailedGenerateUniqueUid},
{ActualError: models.ErrDashboardInvalidUid, ExpectedError: models.ErrDashboardInvalidUid},
{ActualError: dashboards.ErrDashboardTitleEmpty, ExpectedError: dashboards.ErrFolderTitleEmpty},
{ActualError: dashboards.ErrDashboardUpdateAccessDenied, ExpectedError: dashboards.ErrFolderAccessDenied},
{ActualError: dashboards.ErrDashboardWithSameNameInFolderExists, ExpectedError: dashboards.ErrFolderSameNameExists},
{ActualError: dashboards.ErrDashboardWithSameUIDExists, ExpectedError: dashboards.ErrFolderWithSameUIDExists},
{ActualError: dashboards.ErrDashboardVersionMismatch, ExpectedError: dashboards.ErrFolderVersionMismatch},
{ActualError: dashboards.ErrDashboardNotFound, ExpectedError: dashboards.ErrFolderNotFound},
{ActualError: dashboards.ErrDashboardFailedGenerateUniqueUid, ExpectedError: dashboards.ErrFolderFailedGenerateUniqueUid},
{ActualError: dashboards.ErrDashboardInvalidUid, ExpectedError: dashboards.ErrDashboardInvalidUid},
}
for _, tc := range testCases {

View File

@ -91,7 +91,7 @@ func (d *DashboardSnapshotStore) GetDashboardSnapshot(ctx context.Context, query
if err != nil {
return err
} else if !has {
return models.ErrDashboardSnapshotNotFound
return dashboardsnapshots.ErrDashboardSnapshotNotFound
}
query.Result = &snapshot

View File

@ -0,0 +1,8 @@
package dashboardsnapshots
import "github.com/grafana/grafana/pkg/services/dashboards"
var ErrDashboardSnapshotNotFound = dashboards.DashboardErr{
Reason: "Dashboard snapshot not found",
StatusCode: 404,
}

View File

@ -7,6 +7,7 @@ import (
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/dashboards"
dashver "github.com/grafana/grafana/pkg/services/dashboardversion"
"github.com/grafana/grafana/pkg/services/sqlstore"
"github.com/grafana/grafana/pkg/util"
@ -134,7 +135,7 @@ func getDashboard(t *testing.T, sqlStore *sqlstore.SQLStore, dashboard *models.D
if err != nil {
return err
} else if !has {
return models.ErrDashboardNotFound
return dashboards.ErrDashboardNotFound
}
dashboard.SetId(dashboard.Id)
@ -188,7 +189,7 @@ func insertTestDashboard(t *testing.T, sqlStore *sqlstore.SQLStore, title string
if affectedRows, err := sess.Insert(dashVersion); err != nil {
return err
} else if affectedRows == 0 {
return models.ErrDashboardNotFound
return dashboards.ErrDashboardNotFound
}
return nil
@ -250,7 +251,7 @@ func updateTestDashboard(t *testing.T, sqlStore *sqlstore.SQLStore, dashboard *m
if affectedRows, err := sess.Insert(dashVersion); err != nil {
return err
} else if affectedRows == 0 {
return models.ErrDashboardNotFound
return dashboards.ErrDashboardNotFound
}
return nil

View File

@ -8,6 +8,7 @@ import (
"github.com/grafana/grafana/pkg/api/routing"
"github.com/grafana/grafana/pkg/middleware"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/dashboards"
"github.com/grafana/grafana/pkg/web"
)
@ -173,11 +174,11 @@ func toLibraryElementError(err error, message string) response.Response {
if errors.Is(err, errLibraryElementVersionMismatch) {
return response.Error(412, errLibraryElementVersionMismatch.Error(), err)
}
if errors.Is(err, models.ErrFolderNotFound) {
return response.Error(404, models.ErrFolderNotFound.Error(), err)
if errors.Is(err, dashboards.ErrFolderNotFound) {
return response.Error(404, dashboards.ErrFolderNotFound.Error(), err)
}
if errors.Is(err, models.ErrFolderAccessDenied) {
return response.Error(403, models.ErrFolderAccessDenied.Error(), err)
if errors.Is(err, dashboards.ErrFolderAccessDenied) {
return response.Error(403, dashboards.ErrFolderAccessDenied.Error(), err)
}
if errors.Is(err, errLibraryElementHasConnections) {
return response.Error(403, errLibraryElementHasConnections.Error(), err)

View File

@ -10,6 +10,7 @@ import (
"github.com/grafana/grafana/pkg/api/dtos"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/dashboards"
"github.com/grafana/grafana/pkg/services/search"
"github.com/grafana/grafana/pkg/services/sqlstore"
"github.com/grafana/grafana/pkg/services/sqlstore/migrator"
@ -707,7 +708,7 @@ func (l *LibraryElementService) deleteLibraryElementsInFolderUID(c context.Conte
}
if len(folderUIDs) == 0 {
return models.ErrFolderNotFound
return dashboards.ErrFolderNotFound
}
if len(folderUIDs) != 1 {

View File

@ -4,6 +4,7 @@ import (
"context"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/dashboards"
"github.com/grafana/grafana/pkg/services/guardian"
)
@ -29,7 +30,7 @@ func (l *LibraryElementService) requireEditPermissionsOnFolder(ctx context.Conte
}
if isGeneralFolder(folderID) && user.HasRole(models.ROLE_VIEWER) {
return models.ErrFolderAccessDenied
return dashboards.ErrFolderAccessDenied
}
folder, err := l.folderService.GetFolderByID(ctx, user, folderID, user.OrgId)
if err != nil {
@ -43,7 +44,7 @@ func (l *LibraryElementService) requireEditPermissionsOnFolder(ctx context.Conte
return err
}
if !canEdit {
return models.ErrFolderAccessDenied
return dashboards.ErrFolderAccessDenied
}
return nil
@ -66,7 +67,7 @@ func (l *LibraryElementService) requireViewPermissionsOnFolder(ctx context.Conte
return err
}
if !canView {
return models.ErrFolderAccessDenied
return dashboards.ErrFolderAccessDenied
}
return nil
@ -80,7 +81,7 @@ func (l *LibraryElementService) requireEditPermissionsOnDashboard(ctx context.Co
return err
}
if !canEdit {
return models.ErrDashboardUpdateAccessDenied
return dashboards.ErrDashboardUpdateAccessDenied
}
return nil

View File

@ -77,7 +77,7 @@ func TestDeleteLibraryPanelsInFolder(t *testing.T) {
scenarioWithPanel(t, "When an admin tries to delete a folder uid that doesn't exist, it should fail",
func(t *testing.T, sc scenarioContext) {
err := sc.service.DeleteLibraryElementsInFolder(sc.reqContext.Req.Context(), sc.reqContext.SignedInUser, sc.folder.Uid+"xxxx")
require.EqualError(t, err, models.ErrFolderNotFound.Error())
require.EqualError(t, err, dashboards.ErrFolderNotFound.Error())
})
scenarioWithPanel(t, "When an admin tries to delete a folder that contains disconnected elements, it should delete all disconnected elements too",

View File

@ -9,6 +9,7 @@ import (
"time"
"github.com/grafana/grafana/pkg/services/accesscontrol"
"github.com/grafana/grafana/pkg/services/dashboards"
"github.com/grafana/grafana/pkg/services/datasources"
"github.com/grafana/grafana/pkg/services/ngalert/provisioning"
"github.com/grafana/grafana/pkg/services/ngalert/store"
@ -495,7 +496,7 @@ func toNamespaceErrorResponse(err error) response.Response {
if errors.Is(err, ngmodels.ErrCannotEditNamespace) {
return ErrResp(http.StatusForbidden, err, err.Error())
}
if errors.Is(err, models.ErrDashboardIdentifierNotSet) {
if errors.Is(err, dashboards.ErrDashboardIdentifierNotSet) {
return ErrResp(http.StatusBadRequest, err, err.Error())
}
return apierrors.ToFolderErrorResponse(err)

View File

@ -9,7 +9,6 @@ import (
"github.com/prometheus/client_golang/prometheus"
"github.com/grafana/grafana/pkg/components/imguploader"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/dashboards"
ngmodels "github.com/grafana/grafana/pkg/services/ngalert/models"
"github.com/grafana/grafana/pkg/services/ngalert/store"
@ -111,7 +110,7 @@ func (s *ScreenshotImageService) NewImage(ctx context.Context, r *ngmodels.Alert
if err != nil {
// TODO: Check for screenshot upload failures. These images should still be
// stored because we have a local disk path that could be useful.
if errors.Is(err, models.ErrDashboardNotFound) {
if errors.Is(err, dashboards.ErrDashboardNotFound) {
return nil, ErrNoDashboard
}
return nil, err

View File

@ -302,12 +302,12 @@ func (fr *FileReader) getOrCreateFolderID(ctx context.Context, cfg *config, serv
cmd := &models.GetDashboardQuery{Slug: models.SlugifyTitle(folderName), OrgId: cfg.OrgID}
err := fr.dashboardStore.GetDashboard(ctx, cmd)
if err != nil && !errors.Is(err, models.ErrDashboardNotFound) {
if err != nil && !errors.Is(err, dashboards.ErrDashboardNotFound) {
return 0, err
}
// dashboard folder not found. create one.
if errors.Is(err, models.ErrDashboardNotFound) {
if errors.Is(err, dashboards.ErrDashboardNotFound) {
dash := &dashboards.SaveDashboardDTO{}
dash.Dashboard = models.NewDashboardFolder(folderName)
dash.Dashboard.IsFolder = true
@ -315,7 +315,7 @@ func (fr *FileReader) getOrCreateFolderID(ctx context.Context, cfg *config, serv
dash.OrgId = cfg.OrgID
// set dashboard folderUid if given
if cfg.FolderUID == accesscontrol.GeneralFolderUID {
return 0, models.ErrFolderInvalidUID
return 0, dashboards.ErrFolderInvalidUID
}
dash.Dashboard.SetUid(cfg.FolderUID)
dbDash, err := service.SaveFolderForProvisionedDashboards(ctx, dash)

View File

@ -8,13 +8,14 @@ import (
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/dashboards"
"github.com/grafana/grafana/pkg/util"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
)
const (
@ -405,7 +406,7 @@ func TestDashboardFileReader(t *testing.T) {
require.NoError(t, err)
_, err = r.getOrCreateFolderID(context.Background(), cfg, fakeService, cfg.Folder)
require.ErrorIs(t, err, models.ErrFolderInvalidUID)
require.ErrorIs(t, err, dashboards.ErrFolderInvalidUID)
})
t.Run("Walking the folder with dashboards", func(t *testing.T) {
@ -513,5 +514,5 @@ func (ffi FakeFileInfo) Sys() interface{} {
type fakeDashboardStore struct{}
func (fds *fakeDashboardStore) GetDashboard(_ context.Context, _ *models.GetDashboardQuery) error {
return models.ErrDashboardNotFound
return dashboards.ErrDashboardNotFound
}

View File

@ -67,7 +67,7 @@ func createDashboardJSON(data *simplejson.Json, lastModified time.Time, cfg *con
dash.Dashboard.FolderId = folderID
if dash.Dashboard.Title == "" {
return nil, models.ErrDashboardTitleEmpty
return nil, dashboards.ErrDashboardTitleEmpty
}
return dash, nil

View File

@ -79,7 +79,7 @@ func TestBrowserScreenshotService(t *testing.T) {
s := NewBrowserScreenshotService(&d, r)
// a non-existent dashboard should return error
d.On("GetDashboard", mock.Anything, mock.AnythingOfType("*models.GetDashboardQuery")).Return(models.ErrDashboardNotFound).Once()
d.On("GetDashboard", mock.Anything, mock.AnythingOfType("*models.GetDashboardQuery")).Return(dashboards.ErrDashboardNotFound).Once()
ctx := context.Background()
opts := ScreenshotOptions{}
screenshot, err := s.Take(ctx, opts)

View File

@ -6,6 +6,7 @@ import (
"time"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/dashboards"
)
func (ss *SQLStore) GetThumbnail(ctx context.Context, query *models.GetDashboardThumbnailCommand) (*models.DashboardThumbnail, error) {
@ -25,7 +26,7 @@ func (ss *SQLStore) SaveThumbnail(ctx context.Context, cmd *models.SaveDashboard
err := ss.WithTransactionalDbSession(ctx, func(sess *DBSession) error {
existing, err := findThumbnailByMeta(sess, cmd.DashboardThumbnailMeta)
if err != nil && !errors.Is(err, models.ErrDashboardThumbnailNotFound) {
if err != nil && !errors.Is(err, dashboards.ErrDashboardThumbnailNotFound) {
return err
}
@ -150,7 +151,7 @@ func findThumbnailByMeta(sess *DBSession, meta models.DashboardThumbnailMeta) (*
exists, err := sess.Get(result)
if !exists {
return nil, models.ErrDashboardThumbnailNotFound
return nil, dashboards.ErrDashboardThumbnailNotFound
}
if err != nil {
@ -174,7 +175,7 @@ func findDashboardIdByThumbMeta(sess *DBSession, meta models.DashboardThumbnailM
return nil, err
}
if !exists {
return nil, models.ErrDashboardNotFound
return nil, dashboards.ErrDashboardNotFound
}
return result, err

View File

@ -5,11 +5,13 @@ import (
"testing"
"time"
"github.com/stretchr/testify/require"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/dashboards"
dashver "github.com/grafana/grafana/pkg/services/dashboardversion"
"github.com/grafana/grafana/pkg/util"
"github.com/stretchr/testify/require"
)
var theme = models.ThemeDark
@ -313,7 +315,7 @@ func updateTestDashboard(t *testing.T, sqlStore *SQLStore, dashboard *models.Das
if affectedRows, err := sess.Insert(dashVersion); err != nil {
return err
} else if affectedRows == 0 {
return models.ErrDashboardNotFound
return dashboards.ErrDashboardNotFound
}
return nil

View File

@ -7,6 +7,7 @@ import (
"xorm.io/xorm"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/services/dashboards"
dashver "github.com/grafana/grafana/pkg/services/dashboardversion"
"github.com/grafana/grafana/pkg/services/sqlstore/migrator"
"github.com/grafana/grafana/pkg/util"
@ -151,7 +152,7 @@ func (m *folderHelper) generateNewDashboardUid(orgId int64) (string, error) {
}
}
return "", models.ErrDashboardFailedGenerateUniqueUid
return "", dashboards.ErrDashboardFailedGenerateUniqueUid
}
// based on SQLStore.UpdateDashboardACL()

View File

@ -11,6 +11,7 @@ import (
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/accesscontrol"
"github.com/grafana/grafana/pkg/services/dashboards"
dashver "github.com/grafana/grafana/pkg/services/dashboardversion"
"github.com/grafana/grafana/pkg/services/user"
"github.com/grafana/grafana/pkg/util"
@ -461,7 +462,7 @@ func insertTestDashboard(t *testing.T, sqlStore *SQLStore, title string, orgId i
if affectedRows, err := sess.Insert(dashVersion); err != nil {
return err
} else if affectedRows == 0 {
return models.ErrDashboardNotFound
return dashboards.ErrDashboardNotFound
}
return nil

View File

@ -222,7 +222,7 @@ func (hs *thumbService) GetImage(c *models.ReqContext) {
Kind: models.ThumbnailKindDefault,
})
if errors.Is(err, models.ErrDashboardThumbnailNotFound) {
if errors.Is(err, dashboards.ErrDashboardThumbnailNotFound) {
c.Resp.WriteHeader(404)
return
}

View File

@ -12,15 +12,17 @@ import (
"path/filepath"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/dashboardimport"
"github.com/grafana/grafana/pkg/services/dashboards"
"github.com/grafana/grafana/pkg/services/plugindashboards"
"github.com/grafana/grafana/pkg/services/sqlstore"
"github.com/grafana/grafana/pkg/services/user"
"github.com/grafana/grafana/pkg/tests/testinfra"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestDashboardQuota(t *testing.T) {
@ -173,19 +175,19 @@ providers:
desc: "when updating provisioned dashboard using ID it should fail",
dashboardData: fmt.Sprintf(`{"title":"just testing", "id": %d, "version": 1}`, dashboardID),
expStatus: http.StatusBadRequest,
expErrReason: models.ErrDashboardCannotSaveProvisionedDashboard.Reason,
expErrReason: dashboards.ErrDashboardCannotSaveProvisionedDashboard.Reason,
},
{
desc: "when updating provisioned dashboard using UID it should fail",
dashboardData: fmt.Sprintf(`{"title":"just testing", "uid": %q, "version": 1}`, dashboardUID),
expStatus: http.StatusBadRequest,
expErrReason: models.ErrDashboardCannotSaveProvisionedDashboard.Reason,
expErrReason: dashboards.ErrDashboardCannotSaveProvisionedDashboard.Reason,
},
{
desc: "when updating dashboard using unknown ID, it should fail",
dashboardData: `{"title":"just testing", "id": 42, "version": 1}`,
expStatus: http.StatusNotFound,
expErrReason: models.ErrDashboardNotFound.Reason,
expErrReason: dashboards.ErrDashboardNotFound.Reason,
},
{
desc: "when updating dashboard using unknown UID, it should succeed",
@ -247,7 +249,7 @@ providers:
dashboardErr := &errorResponseBody{}
err = json.Unmarshal(b, dashboardErr)
require.NoError(t, err)
assert.Equal(t, models.ErrDashboardCannotDeleteProvisionedDashboard.Reason, dashboardErr.Message)
assert.Equal(t, dashboards.ErrDashboardCannotDeleteProvisionedDashboard.Reason, dashboardErr.Message)
})
})
}