Files

198 lines
5.0 KiB
Go

package folderimpl
import (
"context"
"fmt"
"strconv"
"strings"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
authlib "github.com/grafana/authlib/types"
"github.com/grafana/grafana/pkg/apimachinery/utils"
"github.com/grafana/grafana/pkg/infra/slugify"
"github.com/grafana/grafana/pkg/services/dashboards"
"github.com/grafana/grafana/pkg/services/folder"
"github.com/grafana/grafana/pkg/services/user"
)
func convertUnstructuredToFolder(item *unstructured.Unstructured, identifiers map[string]*user.User) (*folder.Folder, error) {
meta, err := utils.MetaAccessor(item)
if err != nil {
return nil, err
}
info, _ := authlib.ParseNamespace(meta.GetNamespace())
if info.OrgID < 0 {
info.OrgID = 1 // This resolves all test cases that assume org 1
}
title, _, _ := unstructured.NestedString(item.Object, "spec", "title")
description, _, _ := unstructured.NestedString(item.Object, "spec", "description")
uid := meta.GetName()
url := ""
if uid != folder.RootFolder.UID {
slug := slugify.Slugify(title)
url = dashboards.GetFolderURL(uid, slug)
}
created := meta.GetCreationTimestamp().Local()
updated, _ := meta.GetUpdatedTimestamp()
if updated == nil {
updated = &created
} else {
tmp := updated.Local()
updated = &tmp
}
createdBy, updatedBy := int64(0), int64(0)
createdByUID, updatedByUID := "", ""
if len(identifiers) > 0 {
user, ok := identifiers[meta.GetCreatedBy()]
if ok {
createdBy = user.ID
createdByUID = user.UID
}
user, ok = identifiers[meta.GetUpdatedBy()]
if ok {
updatedBy = user.ID
updatedByUID = user.UID
}
}
manager, _ := meta.GetManagerProperties()
return &folder.Folder{
UID: uid,
Title: title,
Description: description,
ID: meta.GetDeprecatedInternalID(), // nolint:staticcheck
ParentUID: meta.GetFolder(),
Version: int(meta.GetGeneration()),
ManagedBy: manager.Kind,
Fullpath: meta.GetFullpath(),
FullpathUIDs: meta.GetFullpathUIDs(),
URL: url,
Created: created,
Updated: *updated,
OrgID: info.OrgID,
CreatedBy: createdBy,
CreatedByUID: createdByUID,
UpdatedBy: updatedBy,
UpdatedByUID: updatedByUID,
}, nil
}
func (ss *FolderUnifiedStoreImpl) UnstructuredToLegacyFolder(ctx context.Context, item *unstructured.Unstructured) (*folder.Folder, error) {
meta, err := utils.MetaAccessor(item)
if err != nil {
return nil, err
}
identifiers := make(map[string]struct{}, 0)
identifiers[meta.GetCreatedBy()] = struct{}{}
identifiers[meta.GetUpdatedBy()] = struct{}{}
folderUserIdentifiers, err := ss.getFolderIdentifiers(ctx, identifiers)
if err != nil {
return nil, err
}
folder, err := convertUnstructuredToFolder(item, folderUserIdentifiers)
if err != nil {
return nil, err
}
return folder, nil
}
func (ss *FolderUnifiedStoreImpl) UnstructuredToLegacyFolderList(ctx context.Context, unstructuredList *unstructured.UnstructuredList) ([]*folder.Folder, error) {
identifiers := make(map[string]struct{}, 0)
for _, item := range unstructuredList.Items {
meta, err := utils.MetaAccessor(&item)
if err != nil {
return nil, fmt.Errorf("unable to convert unstructured item to legacy folder %w", err)
}
identifiers[meta.GetCreatedBy()] = struct{}{}
identifiers[meta.GetUpdatedBy()] = struct{}{}
}
folderUserIdentifiers, err := ss.getFolderIdentifiers(ctx, identifiers)
if err != nil {
return nil, err
}
folders := make([]*folder.Folder, 0)
for _, item := range unstructuredList.Items {
folder, err := convertUnstructuredToFolder(&item, folderUserIdentifiers)
if err != nil {
return nil, err
}
folders = append(folders, folder)
}
return folders, nil
}
func (ss *FolderUnifiedStoreImpl) getFolderIdentifiers(ctx context.Context, identifiers map[string]struct{}) (map[string]*user.User, error) {
identifierMap, userUIDs, userIds := separateUIDsAndIDs(identifiers)
if len(userUIDs) == 0 && len(userIds) == 0 {
return nil, nil
}
users, err := ss.userService.ListByIdOrUID(ctx, userUIDs, userIds)
if err != nil {
return nil, err
}
userMap := make(map[string]*user.User, len(users))
for _, u := range users {
if _, ok := identifierMap[fmt.Sprintf("user:%d", u.ID)]; ok {
userMap[fmt.Sprintf("user:%d", u.ID)] = u
}
if _, ok := identifierMap[fmt.Sprintf("user:%s", u.UID)]; ok {
userMap[fmt.Sprintf("user:%s", u.UID)] = u
}
}
return userMap, nil
}
func parseIdentifier(identifier string) string {
parts := strings.Split(identifier, ":")
if len(parts) < 2 {
return ""
}
if parts[0] != "user" {
return ""
}
return parts[1]
}
func separateUIDsAndIDs(identifiers map[string]struct{}) (map[string]string, []string, []int64) {
uids := make([]string, 0)
ids := make([]int64, 0)
identifierMap := make(map[string]string, 0)
for identifier := range identifiers {
value := parseIdentifier(identifier)
if value == "" {
continue
}
identifierMap[identifier] = value
id, err := strconv.ParseInt(value, 10, 64)
if err == nil {
ids = append(ids, id)
} else {
uids = append(uids, value)
}
}
return identifierMap, uids, ids
}