The open and composable observability and data visualization platform. Visualize metrics, logs, and traces from multiple sources like Prometheus, Loki, Elasticsearch, InfluxDB, Postgres and many more.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
grafana/pkg/services/folder/folderimpl/folder.go

446 lines
13 KiB

package folderimpl
import (
"context"
"errors"
PluginManager: Make Plugins, Renderer and DataSources non-global (#31866) * PluginManager: Make Plugins and DataSources non-global Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Fix integration tests Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Replace outdated command Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * DashboardService: Ensure it gets constructed with necessary parameters Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Fix build Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * DashboardService: Ensure it gets constructed with necessary parameters Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Remove dead code Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Fix test Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Fix test Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Remove FocusConvey Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Fix test Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Remove dead code Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Undo interface changes Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Backend: Move tsdbifaces.RequestHandler to plugins.DataRequestHandler Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Rename to DataSourceCount Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Consolidate dashboard interfaces into one Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Fix tests Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Fix tests Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Fix test Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Fix tests Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Fix tests Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Fix tests Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Fix tests Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Fix dashboard integration tests Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com>
4 years ago
"strings"
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/events"
"github.com/grafana/grafana/pkg/infra/appcontext"
"github.com/grafana/grafana/pkg/infra/db"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/accesscontrol"
"github.com/grafana/grafana/pkg/services/dashboards"
"github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/services/folder"
"github.com/grafana/grafana/pkg/services/guardian"
"github.com/grafana/grafana/pkg/services/org"
"github.com/grafana/grafana/pkg/services/search"
"github.com/grafana/grafana/pkg/services/user"
"github.com/grafana/grafana/pkg/setting"
)
type Service struct {
store store
log log.Logger
cfg *setting.Cfg
dashboardService dashboards.DashboardService
dashboardStore dashboards.Store
searchService *search.SearchService
features *featuremgmt.FeatureManager
permissions accesscontrol.FolderPermissionsService
// bus is currently used to publish events that cause scheduler to update rules.
bus bus.Bus
}
func ProvideService(
ac accesscontrol.AccessControl,
bus bus.Bus,
cfg *setting.Cfg,
dashboardService dashboards.DashboardService,
dashboardStore dashboards.Store,
db db.DB, // DB for the (new) nested folder store
features *featuremgmt.FeatureManager,
folderPermissionsService accesscontrol.FolderPermissionsService,
searchService *search.SearchService,
) folder.Service {
ac.RegisterScopeAttributeResolver(dashboards.NewFolderNameScopeResolver(dashboardStore))
ac.RegisterScopeAttributeResolver(dashboards.NewFolderIDScopeResolver(dashboardStore))
store := ProvideStore(db, cfg, features)
return &Service{
cfg: cfg,
log: log.New("folder-service"),
dashboardService: dashboardService,
dashboardStore: dashboardStore,
store: store,
searchService: searchService,
features: features,
permissions: folderPermissionsService,
bus: bus,
}
}
func (s *Service) GetFolders(ctx context.Context, user *user.SignedInUser, orgID int64, limit int64, page int64) ([]*models.Folder, error) {
searchQuery := search.Query{
SignedInUser: user,
DashboardIds: make([]int64, 0),
FolderIds: make([]int64, 0),
Limit: limit,
OrgId: orgID,
Type: "dash-folder",
Permission: models.PERMISSION_VIEW,
Page: page,
}
if err := s.searchService.SearchHandler(ctx, &searchQuery); err != nil {
return nil, err
}
folders := make([]*models.Folder, 0)
for _, hit := range searchQuery.Result {
folders = append(folders, &models.Folder{
Id: hit.ID,
Uid: hit.UID,
Title: hit.Title,
})
}
return folders, nil
}
func (s *Service) GetFolderByID(ctx context.Context, user *user.SignedInUser, id int64, orgID int64) (*models.Folder, error) {
if id == 0 {
return &models.Folder{Id: id, Title: "General"}, nil
}
dashFolder, err := s.dashboardStore.GetFolderByID(ctx, orgID, id)
if err != nil {
return nil, err
}
g := guardian.New(ctx, dashFolder.Id, orgID, user)
if canView, err := g.CanView(); err != nil || !canView {
if err != nil {
return nil, toFolderError(err)
}
return nil, dashboards.ErrFolderAccessDenied
}
return dashFolder, nil
}
func (s *Service) GetFolderByUID(ctx context.Context, user *user.SignedInUser, orgID int64, uid string) (*models.Folder, error) {
dashFolder, err := s.dashboardStore.GetFolderByUID(ctx, orgID, uid)
if err != nil {
return nil, err
}
g := guardian.New(ctx, dashFolder.Id, orgID, user)
if canView, err := g.CanView(); err != nil || !canView {
if err != nil {
return nil, toFolderError(err)
}
return nil, dashboards.ErrFolderAccessDenied
}
return dashFolder, nil
}
func (s *Service) GetFolderByTitle(ctx context.Context, user *user.SignedInUser, orgID int64, title string) (*models.Folder, error) {
dashFolder, err := s.dashboardStore.GetFolderByTitle(ctx, orgID, title)
if err != nil {
return nil, err
}
g := guardian.New(ctx, dashFolder.Id, orgID, user)
if canView, err := g.CanView(); err != nil || !canView {
if err != nil {
return nil, toFolderError(err)
}
return nil, dashboards.ErrFolderAccessDenied
}
return dashFolder, nil
}
func (s *Service) Create(ctx context.Context, cmd *folder.CreateFolderCommand) (*folder.Folder, error) {
dashFolder := models.NewDashboardFolder(cmd.Title)
dashFolder.OrgId = cmd.OrgID
trimmedUID := strings.TrimSpace(cmd.UID)
if trimmedUID == accesscontrol.GeneralFolderUID {
return nil, dashboards.ErrFolderInvalidUID
}
dashFolder.SetUid(trimmedUID)
user, err := appcontext.User(ctx)
if err != nil {
return nil, err
}
userID := user.UserID
PluginManager: Make Plugins, Renderer and DataSources non-global (#31866) * PluginManager: Make Plugins and DataSources non-global Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Fix integration tests Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Replace outdated command Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * DashboardService: Ensure it gets constructed with necessary parameters Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Fix build Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * DashboardService: Ensure it gets constructed with necessary parameters Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Remove dead code Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Fix test Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Fix test Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Remove FocusConvey Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Fix test Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Remove dead code Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Undo interface changes Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Backend: Move tsdbifaces.RequestHandler to plugins.DataRequestHandler Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Rename to DataSourceCount Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Consolidate dashboard interfaces into one Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Fix tests Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Fix tests Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Fix test Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Fix tests Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Fix tests Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Fix tests Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Fix tests Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Fix dashboard integration tests Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com>
4 years ago
if userID == 0 {
userID = -1
}
dashFolder.CreatedBy = userID
dashFolder.UpdatedBy = userID
dashFolder.UpdateSlug()
dto := &dashboards.SaveDashboardDTO{
Dashboard: dashFolder,
OrgId: cmd.OrgID,
User: user,
}
saveDashboardCmd, err := s.dashboardService.BuildSaveDashboardCommand(ctx, dto, false, false)
if err != nil {
PluginManager: Make Plugins, Renderer and DataSources non-global (#31866) * PluginManager: Make Plugins and DataSources non-global Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Fix integration tests Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Replace outdated command Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * DashboardService: Ensure it gets constructed with necessary parameters Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Fix build Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * DashboardService: Ensure it gets constructed with necessary parameters Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Remove dead code Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Fix test Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Fix test Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Remove FocusConvey Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Fix test Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Remove dead code Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Undo interface changes Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Backend: Move tsdbifaces.RequestHandler to plugins.DataRequestHandler Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Rename to DataSourceCount Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Consolidate dashboard interfaces into one Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Fix tests Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Fix tests Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Fix test Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Fix tests Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Fix tests Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Fix tests Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Fix tests Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Fix dashboard integration tests Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com>
4 years ago
return nil, toFolderError(err)
}
dash, err := s.dashboardStore.SaveDashboard(ctx, *saveDashboardCmd)
if err != nil {
PluginManager: Make Plugins, Renderer and DataSources non-global (#31866) * PluginManager: Make Plugins and DataSources non-global Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Fix integration tests Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Replace outdated command Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * DashboardService: Ensure it gets constructed with necessary parameters Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Fix build Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * DashboardService: Ensure it gets constructed with necessary parameters Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Remove dead code Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Fix test Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Fix test Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Remove FocusConvey Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Fix test Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Remove dead code Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Undo interface changes Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Backend: Move tsdbifaces.RequestHandler to plugins.DataRequestHandler Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Rename to DataSourceCount Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Consolidate dashboard interfaces into one Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Fix tests Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Fix tests Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Fix test Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Fix tests Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Fix tests Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Fix tests Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Fix tests Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Fix dashboard integration tests Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com>
4 years ago
return nil, toFolderError(err)
}
var createdFolder *models.Folder
createdFolder, err = s.dashboardStore.GetFolderByID(ctx, cmd.OrgID, dash.Id)
if err != nil {
return nil, err
}
var permissionErr error
if !accesscontrol.IsDisabled(s.cfg) {
var permissions []accesscontrol.SetResourcePermissionCommand
if user.IsRealUser() && !user.IsAnonymous {
permissions = append(permissions, accesscontrol.SetResourcePermissionCommand{
UserID: userID, Permission: models.PERMISSION_ADMIN.String(),
})
}
permissions = append(permissions, []accesscontrol.SetResourcePermissionCommand{
{BuiltinRole: string(org.RoleEditor), Permission: models.PERMISSION_EDIT.String()},
{BuiltinRole: string(org.RoleViewer), Permission: models.PERMISSION_VIEW.String()},
}...)
_, permissionErr = s.permissions.SetPermissions(ctx, cmd.OrgID, createdFolder.Uid, permissions...)
} else if s.cfg.EditorsCanAdmin && user.IsRealUser() && !user.IsAnonymous {
permissionErr = s.MakeUserAdmin(ctx, cmd.OrgID, userID, createdFolder.Id, true)
}
if permissionErr != nil {
s.log.Error("Could not make user admin", "folder", createdFolder.Title, "user", userID, "error", permissionErr)
}
if s.features.IsEnabled(featuremgmt.FlagNestedFolders) {
var description string
if dash.Data != nil {
description = dash.Data.Get("description").MustString()
}
parentUID := folder.RootFolderUID
if cmd.ParentUID != "" {
parentUID = cmd.ParentUID
}
_, err := s.store.Create(ctx, folder.CreateFolderCommand{
// TODO: Today, if a UID isn't specified, the dashboard store
// generates a new UID. The new folder store will need to do this as
// well, but for now we take the UID from the newly created folder.
UID: dash.Uid,
OrgID: cmd.OrgID,
Title: cmd.Title,
Description: description,
ParentUID: parentUID,
})
if err != nil {
// We'll log the error and also roll back the previously-created
// (legacy) folder.
s.log.Error("error saving folder to nested folder store", err)
err = s.DeleteFolder(ctx, &folder.DeleteFolderCommand{UID: createdFolder.Uid, OrgID: cmd.OrgID, ForceDeleteRules: true})
if err != nil {
s.log.Error("error deleting folder after failed save to nested folder store", err)
}
return folder.FromDashboard(dash), err
}
// The folder UID is specified (or generated) during creation, so we'll
// stop here and return the created model.Folder.
}
return folder.FromDashboard(dash), nil
}
func (s *Service) UpdateFolder(ctx context.Context, user *user.SignedInUser, orgID int64, existingUid string, cmd *models.UpdateFolderCommand) error {
query := models.GetDashboardQuery{OrgId: orgID, Uid: existingUid}
if _, err := s.dashboardStore.GetDashboard(ctx, &query); err != nil {
return toFolderError(err)
}
dashFolder := query.Result
currentTitle := dashFolder.Title
if !dashFolder.IsFolder {
return dashboards.ErrFolderNotFound
}
cmd.UpdateDashboardModel(dashFolder, orgID, user.UserID)
dto := &dashboards.SaveDashboardDTO{
Dashboard: dashFolder,
OrgId: orgID,
User: user,
Overwrite: cmd.Overwrite,
}
saveDashboardCmd, err := s.dashboardService.BuildSaveDashboardCommand(ctx, dto, false, false)
if err != nil {
return toFolderError(err)
}
dash, err := s.dashboardStore.SaveDashboard(ctx, *saveDashboardCmd)
if err != nil {
return toFolderError(err)
}
var folder *models.Folder
folder, err = s.dashboardStore.GetFolderByID(ctx, orgID, dash.Id)
if err != nil {
return err
}
cmd.Result = folder
if currentTitle != folder.Title {
if err := s.bus.Publish(ctx, &events.FolderTitleUpdated{
Timestamp: folder.Updated,
Title: folder.Title,
ID: dash.Id,
UID: dash.Uid,
OrgID: orgID,
}); err != nil {
s.log.Error("failed to publish FolderTitleUpdated event", "folder", folder.Title, "user", user.UserID, "error", err)
}
}
return nil
}
func (s *Service) DeleteFolder(ctx context.Context, cmd *folder.DeleteFolderCommand) error {
if s.features.IsEnabled(featuremgmt.FlagNestedFolders) {
err := s.Delete(ctx, cmd)
if err != nil {
s.log.Error("the delete folder on folder table failed with err: ", err.Error())
}
}
user, err := appcontext.User(ctx)
if err != nil {
return err
}
dashFolder, err := s.dashboardStore.GetFolderByUID(ctx, cmd.OrgID, cmd.UID)
if err != nil {
return err
}
guard := guardian.New(ctx, dashFolder.Id, cmd.OrgID, user)
Access control: Use access control for dashboard and folder (#44702) * Add actions and scopes * add resource service for dashboard and folder * Add dashboard guardian with fgac permission evaluation * Add CanDelete function to guardian interface * Add CanDelete property to folder and dashboard dto and set values * change to correct function name * Add accesscontrol to folder endpoints * add access control to dashboard endpoints * check access for nav links * Add fixed roles for dashboard and folders * use correct package * add hack to override guardian Constructor if accesscontrol is enabled * Add services * Add function to handle api backward compatability * Add permissionServices to HttpServer * Set permission when new dashboard is created * Add default permission when creating new dashboard * Set default permission when creating folder and dashboard * Add access control filter for dashboard search * Add to accept list * Add accesscontrol to dashboardimport * Disable access control in tests * Add check to see if user is allow to create a dashboard * Use SetPermissions * Use function to set several permissions at once * remove permissions for folder and dashboard on delete * update required permission * set permission for provisioning * Add CanCreate to dashboard guardian and set correct permisisons for provisioning * Dont set admin on folder / dashboard creation * Add dashboard and folder permission migrations * Add tests for CanCreate * Add roles and update descriptions * Solve uid to id for dashboard and folder permissions * Add folder and dashboard actions to permission filter * Handle viewer_can_edit flag * set folder and dashboard permissions services * Add dashboard permissions when importing a new dashboard * Set access control permissions on provisioning * Pass feature flags and only set permissions if access control is enabled * only add default permissions for folders and dashboards without folders * Batch create permissions in migrations * Remove `dashboards:edit` action * Remove unused function from interface * Update pkg/services/guardian/accesscontrol_guardian_test.go Co-authored-by: Gabriel MABILLE <gamab@users.noreply.github.com> Co-authored-by: Ieva <ieva.vasiljeva@grafana.com>
3 years ago
if canSave, err := guard.CanDelete(); err != nil || !canSave {
if err != nil {
return toFolderError(err)
}
return dashboards.ErrFolderAccessDenied
}
deleteCmd := models.DeleteDashboardCommand{OrgId: cmd.OrgID, Id: dashFolder.Id, ForceDeleteFolderRules: cmd.ForceDeleteRules}
if err := s.dashboardStore.DeleteDashboard(ctx, &deleteCmd); err != nil {
return toFolderError(err)
}
return nil
}
func (s *Service) Update(ctx context.Context, cmd *folder.UpdateFolderCommand) (*folder.Folder, error) {
// check the flag, if old - do whatever did before
// for new only the store
return s.store.Update(ctx, *cmd)
}
func (s *Service) Move(ctx context.Context, cmd *folder.MoveFolderCommand) (*folder.Folder, error) {
// check the flag, if old - do whatever did before
// for new only the store
foldr, err := s.Get(ctx, &folder.GetFolderQuery{
UID: &cmd.UID,
OrgID: cmd.OrgID,
})
if err != nil {
return nil, err
}
return s.store.Update(ctx, folder.UpdateFolderCommand{
Folder: foldr,
NewParentUID: &cmd.NewParentUID,
})
}
func (s *Service) Delete(ctx context.Context, cmd *folder.DeleteFolderCommand) error {
_, err := s.Get(ctx, &folder.GetFolderQuery{
UID: &cmd.UID,
OrgID: cmd.OrgID,
})
if err != nil {
return err
}
folders, err := s.store.GetChildren(ctx, folder.GetTreeQuery{UID: cmd.UID, OrgID: cmd.OrgID})
if err != nil {
return err
}
for _, f := range folders {
err := s.Delete(ctx, &folder.DeleteFolderCommand{UID: f.UID, OrgID: f.OrgID, ForceDeleteRules: cmd.ForceDeleteRules})
if err != nil {
return err
}
}
err = s.store.Delete(ctx, cmd.UID, cmd.OrgID)
if err != nil {
return err
}
return nil
}
func (s *Service) Get(ctx context.Context, cmd *folder.GetFolderQuery) (*folder.Folder, error) {
// check the flag, if old - do whatever did before
// for new only the store
return s.store.Get(ctx, *cmd)
}
func (s *Service) GetParents(ctx context.Context, cmd *folder.GetParentsQuery) ([]*folder.Folder, error) {
// check the flag, if old - do whatever did before
// for new only the store
return s.store.GetParents(ctx, *cmd)
}
func (s *Service) GetTree(ctx context.Context, cmd *folder.GetTreeQuery) ([]*folder.Folder, error) {
// check the flag, if old - do whatever did before
// for new only the store
return s.store.GetChildren(ctx, *cmd)
}
func (s *Service) MakeUserAdmin(ctx context.Context, orgID int64, userID, folderID int64, setViewAndEditPermissions bool) error {
return s.dashboardService.MakeUserAdmin(ctx, orgID, userID, folderID, setViewAndEditPermissions)
}
func toFolderError(err error) error {
if errors.Is(err, dashboards.ErrDashboardTitleEmpty) {
return dashboards.ErrFolderTitleEmpty
}
if errors.Is(err, dashboards.ErrDashboardUpdateAccessDenied) {
return dashboards.ErrFolderAccessDenied
}
if errors.Is(err, dashboards.ErrDashboardWithSameNameInFolderExists) {
return dashboards.ErrFolderSameNameExists
}
if errors.Is(err, dashboards.ErrDashboardWithSameUIDExists) {
return dashboards.ErrFolderWithSameUIDExists
}
if errors.Is(err, dashboards.ErrDashboardVersionMismatch) {
return dashboards.ErrFolderVersionMismatch
}
if errors.Is(err, dashboards.ErrDashboardNotFound) {
return dashboards.ErrFolderNotFound
}
if errors.Is(err, dashboards.ErrDashboardFailedGenerateUniqueUid) {
err = dashboards.ErrFolderFailedGenerateUniqueUid
}
return err
}