| 
									
										
										
										
											2025-08-29 00:51:32 +08:00
										 |  |  | package legacy | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"context" | 
					
						
							|  |  |  | 	"fmt" | 
					
						
							| 
									
										
										
										
											2025-09-05 03:49:49 +08:00
										 |  |  | 	"math/rand" | 
					
						
							| 
									
										
										
										
											2025-10-07 02:08:10 +08:00
										 |  |  | 	"slices" | 
					
						
							| 
									
										
										
										
											2025-08-29 00:51:32 +08:00
										 |  |  | 	"strconv" | 
					
						
							|  |  |  | 	"strings" | 
					
						
							|  |  |  | 	"time" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-23 22:13:05 +08:00
										 |  |  | 	apiserrors "k8s.io/apimachinery/pkg/api/errors" | 
					
						
							| 
									
										
										
										
											2025-08-29 00:51:32 +08:00
										 |  |  | 	"k8s.io/apimachinery/pkg/apis/meta/internalversion" | 
					
						
							|  |  |  | 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | 
					
						
							|  |  |  | 	"k8s.io/apimachinery/pkg/runtime" | 
					
						
							| 
									
										
										
										
											2025-10-07 02:08:10 +08:00
										 |  |  | 	"k8s.io/apimachinery/pkg/runtime/schema" | 
					
						
							| 
									
										
										
										
											2025-08-29 00:51:32 +08:00
										 |  |  | 	"k8s.io/apiserver/pkg/registry/rest" | 
					
						
							| 
									
										
										
										
											2025-09-05 03:49:49 +08:00
										 |  |  | 	"k8s.io/utils/ptr" | 
					
						
							| 
									
										
										
										
											2025-08-29 00:51:32 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	authlib "github.com/grafana/authlib/types" | 
					
						
							|  |  |  | 	dashboardsV1 "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v1beta1" | 
					
						
							|  |  |  | 	preferences "github.com/grafana/grafana/apps/preferences/pkg/apis/preferences/v1alpha1" | 
					
						
							| 
									
										
										
										
											2025-09-27 03:44:02 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/apimachinery/identity" | 
					
						
							| 
									
										
										
										
											2025-09-05 03:49:49 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/registry/apis/preferences/utils" | 
					
						
							| 
									
										
										
										
											2025-08-29 00:51:32 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/services/apiserver/endpoints/request" | 
					
						
							| 
									
										
										
										
											2025-09-05 03:49:49 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/services/star" | 
					
						
							|  |  |  | 	"github.com/grafana/grafana/pkg/services/user" | 
					
						
							| 
									
										
										
										
											2025-08-29 00:51:32 +08:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var ( | 
					
						
							| 
									
										
										
										
											2025-09-05 03:49:49 +08:00
										 |  |  | 	_ rest.Scoper               = (*DashboardStarsStorage)(nil) | 
					
						
							|  |  |  | 	_ rest.SingularNameProvider = (*DashboardStarsStorage)(nil) | 
					
						
							|  |  |  | 	_ rest.Getter               = (*DashboardStarsStorage)(nil) | 
					
						
							|  |  |  | 	_ rest.Lister               = (*DashboardStarsStorage)(nil) | 
					
						
							|  |  |  | 	_ rest.Storage              = (*DashboardStarsStorage)(nil) | 
					
						
							|  |  |  | 	_ rest.Creater              = (*DashboardStarsStorage)(nil) | 
					
						
							|  |  |  | 	_ rest.Updater              = (*DashboardStarsStorage)(nil) | 
					
						
							|  |  |  | 	_ rest.GracefulDeleter      = (*DashboardStarsStorage)(nil) | 
					
						
							|  |  |  | 	_ rest.CollectionDeleter    = (*DashboardStarsStorage)(nil) | 
					
						
							| 
									
										
										
										
											2025-08-29 00:51:32 +08:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-05 03:49:49 +08:00
										 |  |  | func NewDashboardStarsStorage( | 
					
						
							|  |  |  | 	stars star.Service, | 
					
						
							|  |  |  | 	users user.Service, | 
					
						
							|  |  |  | 	namespacer request.NamespaceMapper, | 
					
						
							|  |  |  | 	sql *LegacySQL, | 
					
						
							|  |  |  | ) *DashboardStarsStorage { | 
					
						
							|  |  |  | 	return &DashboardStarsStorage{ | 
					
						
							|  |  |  | 		stars:          stars, | 
					
						
							|  |  |  | 		users:          users, | 
					
						
							| 
									
										
										
										
											2025-08-29 00:51:32 +08:00
										 |  |  | 		namespacer:     namespacer, | 
					
						
							|  |  |  | 		sql:            sql, | 
					
						
							|  |  |  | 		tableConverter: preferences.StarsResourceInfo.TableConverter(), | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-05 03:49:49 +08:00
										 |  |  | type DashboardStarsStorage struct { | 
					
						
							| 
									
										
										
										
											2025-08-29 00:51:32 +08:00
										 |  |  | 	namespacer     request.NamespaceMapper | 
					
						
							|  |  |  | 	tableConverter rest.TableConvertor | 
					
						
							|  |  |  | 	sql            *LegacySQL | 
					
						
							| 
									
										
										
										
											2025-09-05 03:49:49 +08:00
										 |  |  | 	stars          star.Service | 
					
						
							|  |  |  | 	users          user.Service | 
					
						
							| 
									
										
										
										
											2025-08-29 00:51:32 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-05 03:49:49 +08:00
										 |  |  | func (s *DashboardStarsStorage) New() runtime.Object { | 
					
						
							| 
									
										
										
										
											2025-08-29 00:51:32 +08:00
										 |  |  | 	return preferences.StarsKind().ZeroValue() | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-05 03:49:49 +08:00
										 |  |  | func (s *DashboardStarsStorage) Destroy() {} | 
					
						
							| 
									
										
										
										
											2025-08-29 00:51:32 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-05 03:49:49 +08:00
										 |  |  | func (s *DashboardStarsStorage) NamespaceScoped() bool { | 
					
						
							| 
									
										
										
										
											2025-08-29 00:51:32 +08:00
										 |  |  | 	return true // namespace == org
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-05 03:49:49 +08:00
										 |  |  | func (s *DashboardStarsStorage) GetSingularName() string { | 
					
						
							| 
									
										
										
										
											2025-08-29 00:51:32 +08:00
										 |  |  | 	return strings.ToLower(preferences.StarsKind().Kind()) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-05 03:49:49 +08:00
										 |  |  | func (s *DashboardStarsStorage) NewList() runtime.Object { | 
					
						
							| 
									
										
										
										
											2025-08-29 00:51:32 +08:00
										 |  |  | 	return preferences.StarsKind().ZeroListValue() | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-05 03:49:49 +08:00
										 |  |  | func (s *DashboardStarsStorage) ConvertToTable(ctx context.Context, object runtime.Object, tableOptions runtime.Object) (*metav1.Table, error) { | 
					
						
							| 
									
										
										
										
											2025-08-29 00:51:32 +08:00
										 |  |  | 	return s.tableConverter.ConvertToTable(ctx, object, tableOptions) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-05 03:49:49 +08:00
										 |  |  | func (s *DashboardStarsStorage) List(ctx context.Context, options *internalversion.ListOptions) (runtime.Object, error) { | 
					
						
							| 
									
										
										
										
											2025-08-29 00:51:32 +08:00
										 |  |  | 	ns, err := request.NamespaceInfoFrom(ctx, false) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if ns.Value == "" { | 
					
						
							|  |  |  | 		return nil, fmt.Errorf("cross cluster listing is not supported") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-27 03:44:02 +08:00
										 |  |  | 	userInfo, err := identity.GetRequester(ctx) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-10-03 02:58:08 +08:00
										 |  |  | 	user := userInfo.GetIdentifier() | 
					
						
							|  |  |  | 	if userInfo.GetIdentityType() == authlib.TypeAccessPolicy { | 
					
						
							| 
									
										
										
										
											2025-09-27 03:44:02 +08:00
										 |  |  | 		user = "" // can see everything
 | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-08-29 00:51:32 +08:00
										 |  |  | 	list := &preferences.StarsList{} | 
					
						
							| 
									
										
										
										
											2025-10-03 02:58:08 +08:00
										 |  |  | 	found, rv, err := s.sql.getDashboardStars(ctx, ns.OrgID, user) | 
					
						
							| 
									
										
										
										
											2025-08-29 00:51:32 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2025-10-07 02:08:10 +08:00
										 |  |  | 	history, err := s.sql.getHistoryStars(ctx, ns.OrgID, "") | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2025-08-29 00:51:32 +08:00
										 |  |  | 	for _, v := range found { | 
					
						
							| 
									
										
										
										
											2025-10-07 02:08:10 +08:00
										 |  |  | 		list.Items = append(list.Items, | 
					
						
							|  |  |  | 			asStarsResource(s.namespacer(v.OrgID), &v, history[v.UserUID])) | 
					
						
							| 
									
										
										
										
											2025-08-29 00:51:32 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	if rv > 0 { | 
					
						
							|  |  |  | 		list.ResourceVersion = strconv.FormatInt(rv, 10) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return list, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-05 03:49:49 +08:00
										 |  |  | func getNamespaceAndOwner(ctx context.Context, name string) (authlib.NamespaceInfo, utils.OwnerReference, error) { | 
					
						
							| 
									
										
										
										
											2025-08-29 00:51:32 +08:00
										 |  |  | 	info, err := request.NamespaceInfoFrom(ctx, true) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2025-09-05 03:49:49 +08:00
										 |  |  | 		return info, utils.OwnerReference{}, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	owner, ok := utils.ParseOwnerFromName(name) | 
					
						
							|  |  |  | 	if !ok { | 
					
						
							|  |  |  | 		return info, owner, fmt.Errorf("invalid name %w", err) | 
					
						
							| 
									
										
										
										
											2025-08-29 00:51:32 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2025-09-05 03:49:49 +08:00
										 |  |  | 	if owner.Owner != utils.UserResourceOwner { | 
					
						
							|  |  |  | 		return info, owner, fmt.Errorf("expecting name with prefix: %s-", utils.UserResourceOwner) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return info, owner, nil | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2025-08-29 00:51:32 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-05 03:49:49 +08:00
										 |  |  | func (s *DashboardStarsStorage) Get(ctx context.Context, name string, options *metav1.GetOptions) (runtime.Object, error) { | 
					
						
							|  |  |  | 	ns, owner, err := getNamespaceAndOwner(ctx, name) | 
					
						
							| 
									
										
										
										
											2025-08-29 00:51:32 +08:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2025-09-05 03:49:49 +08:00
										 |  |  | 		return nil, err | 
					
						
							| 
									
										
										
										
											2025-08-29 00:51:32 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-10-03 02:58:08 +08:00
										 |  |  | 	found, _, err := s.sql.getDashboardStars(ctx, ns.OrgID, owner.Identifier) | 
					
						
							| 
									
										
										
										
											2025-09-23 22:13:05 +08:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2025-08-29 00:51:32 +08:00
										 |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2025-10-07 02:08:10 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	history, err := s.sql.getHistoryStars(ctx, ns.OrgID, owner.Identifier) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-23 22:13:05 +08:00
										 |  |  | 	if len(found) == 0 || len(found[0].Dashboards) == 0 { | 
					
						
							|  |  |  | 		return nil, apiserrors.NewNotFound(preferences.StarsResourceInfo.GroupResource(), name) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2025-10-07 02:08:10 +08:00
										 |  |  | 	obj := asStarsResource(ns.Value, &found[0], history[owner.Identifier]) | 
					
						
							| 
									
										
										
										
											2025-08-29 00:51:32 +08:00
										 |  |  | 	return &obj, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-10-07 02:08:10 +08:00
										 |  |  | func getStars(stars *preferences.Stars, gk schema.GroupKind) []string { | 
					
						
							| 
									
										
										
										
											2025-09-05 03:49:49 +08:00
										 |  |  | 	if stars == nil || len(stars.Spec.Resource) == 0 { | 
					
						
							|  |  |  | 		return []string{} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	for _, r := range stars.Spec.Resource { | 
					
						
							| 
									
										
										
										
											2025-10-07 02:08:10 +08:00
										 |  |  | 		if r.Group == gk.Group && r.Kind == gk.Kind { | 
					
						
							| 
									
										
										
										
											2025-09-05 03:49:49 +08:00
										 |  |  | 			return r.Names | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return []string{} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Create implements rest.Creater.
 | 
					
						
							| 
									
										
										
										
											2025-10-07 02:08:10 +08:00
										 |  |  | func (s *DashboardStarsStorage) write(ctx context.Context, obj *preferences.Stars) (runtime.Object, error) { | 
					
						
							| 
									
										
										
										
											2025-09-05 03:49:49 +08:00
										 |  |  | 	ns, owner, err := getNamespaceAndOwner(ctx, obj.Name) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	user, err := s.users.GetByUID(ctx, &user.GetUserByUIDQuery{ | 
					
						
							| 
									
										
										
										
											2025-09-27 03:44:02 +08:00
										 |  |  | 		UID: owner.Identifier, | 
					
						
							| 
									
										
										
										
											2025-09-05 03:49:49 +08:00
										 |  |  | 	}) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if user.OrgID != ns.OrgID { | 
					
						
							|  |  |  | 		return nil, fmt.Errorf("namespace mismatch") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-10-07 02:08:10 +08:00
										 |  |  | 	stars := getStars(obj, schema.GroupKind{Group: "dashboard.grafana.app", Kind: "Dashboard"}) | 
					
						
							| 
									
										
										
										
											2025-09-05 03:49:49 +08:00
										 |  |  | 	if len(stars) == 0 { | 
					
						
							|  |  |  | 		err = s.stars.DeleteByUser(ctx, user.ID) | 
					
						
							|  |  |  | 		return &preferences.Stars{ObjectMeta: metav1.ObjectMeta{ | 
					
						
							|  |  |  | 			Name:              obj.Name, | 
					
						
							|  |  |  | 			Namespace:         obj.Namespace, | 
					
						
							|  |  |  | 			DeletionTimestamp: ptr.To(metav1.Now()), | 
					
						
							|  |  |  | 		}}, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-10-03 02:58:08 +08:00
										 |  |  | 	current, _, err := s.sql.getDashboardStars(ctx, ns.OrgID, owner.Identifier) | 
					
						
							| 
									
										
										
										
											2025-09-23 22:13:05 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-05 03:49:49 +08:00
										 |  |  | 	changed := false | 
					
						
							|  |  |  | 	now := time.Now() | 
					
						
							|  |  |  | 	randID := now.UnixNano() + rand.Int63n(5000) | 
					
						
							|  |  |  | 	previous := make(map[string]bool) | 
					
						
							| 
									
										
										
										
											2025-09-23 22:13:05 +08:00
										 |  |  | 	if len(current) > 0 { | 
					
						
							|  |  |  | 		for _, v := range current[0].Dashboards { | 
					
						
							|  |  |  | 			previous[v] = true | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2025-09-05 03:49:49 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	for _, dashboard := range stars { | 
					
						
							|  |  |  | 		if previous[dashboard] { | 
					
						
							|  |  |  | 			delete(previous, dashboard) | 
					
						
							|  |  |  | 			continue // nothing needed
 | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		err = s.stars.Add(ctx, &star.StarDashboardCommand{ | 
					
						
							|  |  |  | 			UserID:       user.ID, | 
					
						
							|  |  |  | 			OrgID:        user.OrgID, | 
					
						
							|  |  |  | 			DashboardUID: dashboard, | 
					
						
							|  |  |  | 			DashboardID:  randID, | 
					
						
							|  |  |  | 			Updated:      now, | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return nil, err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		changed = true | 
					
						
							|  |  |  | 		randID++ | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for k := range previous { | 
					
						
							|  |  |  | 		err = s.stars.Delete(ctx, &star.UnstarDashboardCommand{ | 
					
						
							|  |  |  | 			UserID:       user.ID, | 
					
						
							|  |  |  | 			OrgID:        user.OrgID, | 
					
						
							|  |  |  | 			DashboardUID: k, | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return nil, err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		changed = true | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-10-07 02:08:10 +08:00
										 |  |  | 	// Apply history stars
 | 
					
						
							|  |  |  | 	stars = getStars(obj, schema.GroupKind{Group: "history.grafana.app", Kind: "Query"}) | 
					
						
							|  |  |  | 	res, err := s.sql.getHistoryStars(ctx, user.OrgID, user.UID) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	history := res[user.UID] | 
					
						
							|  |  |  | 	if !slices.Equal(stars, history) { | 
					
						
							|  |  |  | 		changed = true | 
					
						
							|  |  |  | 		if len(stars) == 0 { | 
					
						
							|  |  |  | 			err = s.sql.removeHistoryStar(ctx, user, nil) | 
					
						
							|  |  |  | 			if err != nil { | 
					
						
							|  |  |  | 				return nil, err | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			added, removed, _ := preferences.Changes(history, stars) | 
					
						
							|  |  |  | 			if len(removed) > 0 { | 
					
						
							|  |  |  | 				_ = s.sql.removeHistoryStar(ctx, user, nil) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			for _, v := range added { | 
					
						
							|  |  |  | 				_ = s.sql.addHistoryStar(ctx, user, v) // one at a time so duplicates do not fail everything
 | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-05 03:49:49 +08:00
										 |  |  | 	if changed { | 
					
						
							|  |  |  | 		return s.Get(ctx, obj.Name, &metav1.GetOptions{}) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return obj, nil // nothing required
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Create implements rest.Creater.
 | 
					
						
							|  |  |  | func (s *DashboardStarsStorage) Create(ctx context.Context, obj runtime.Object, createValidation rest.ValidateObjectFunc, options *metav1.CreateOptions) (runtime.Object, error) { | 
					
						
							|  |  |  | 	stars, ok := obj.(*preferences.Stars) | 
					
						
							|  |  |  | 	if !ok { | 
					
						
							|  |  |  | 		return nil, fmt.Errorf("expected stars object") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-10-07 02:08:10 +08:00
										 |  |  | 	return s.write(ctx, stars) | 
					
						
							| 
									
										
										
										
											2025-09-05 03:49:49 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Update implements rest.Updater.
 | 
					
						
							|  |  |  | func (s *DashboardStarsStorage) Update(ctx context.Context, name string, objInfo rest.UpdatedObjectInfo, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc, forceAllowCreate bool, options *metav1.UpdateOptions) (runtime.Object, bool, error) { | 
					
						
							|  |  |  | 	old, err := s.Get(ctx, name, &metav1.GetOptions{}) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, false, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	obj, err := objInfo.UpdatedObject(ctx, old) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, false, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	stars, ok := obj.(*preferences.Stars) | 
					
						
							|  |  |  | 	if !ok { | 
					
						
							|  |  |  | 		return nil, false, fmt.Errorf("expected stars object") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-10-07 02:08:10 +08:00
										 |  |  | 	obj, err = s.write(ctx, stars) | 
					
						
							| 
									
										
										
										
											2025-09-05 03:49:49 +08:00
										 |  |  | 	return obj, false, err | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Delete implements rest.GracefulDeleter.
 | 
					
						
							|  |  |  | func (s *DashboardStarsStorage) Delete(ctx context.Context, name string, deleteValidation rest.ValidateObjectFunc, options *metav1.DeleteOptions) (runtime.Object, bool, error) { | 
					
						
							| 
									
										
										
										
											2025-10-07 02:08:10 +08:00
										 |  |  | 	obj, err := s.write(ctx, &preferences.Stars{ObjectMeta: metav1.ObjectMeta{Name: name}}) | 
					
						
							| 
									
										
										
										
											2025-09-05 03:49:49 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, false, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return obj, true, err | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // DeleteCollection implements rest.CollectionDeleter.
 | 
					
						
							|  |  |  | func (s *DashboardStarsStorage) DeleteCollection(ctx context.Context, deleteValidation rest.ValidateObjectFunc, options *metav1.DeleteOptions, listOptions *internalversion.ListOptions) (runtime.Object, error) { | 
					
						
							|  |  |  | 	return nil, fmt.Errorf("not implemented yet") | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-10-07 02:08:10 +08:00
										 |  |  | func asStarsResource(ns string, v *dashboardStars, history []string) preferences.Stars { | 
					
						
							|  |  |  | 	stars := preferences.Stars{ | 
					
						
							| 
									
										
										
										
											2025-08-29 00:51:32 +08:00
										 |  |  | 		ObjectMeta: metav1.ObjectMeta{ | 
					
						
							| 
									
										
										
										
											2025-09-05 03:49:49 +08:00
										 |  |  | 			Name:              fmt.Sprintf("user-%s", v.UserUID), | 
					
						
							| 
									
										
										
										
											2025-08-29 00:51:32 +08:00
										 |  |  | 			Namespace:         ns, | 
					
						
							|  |  |  | 			ResourceVersion:   strconv.FormatInt(v.Last, 10), | 
					
						
							|  |  |  | 			CreationTimestamp: metav1.NewTime(time.UnixMilli(v.First)), | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		Spec: preferences.StarsSpec{ | 
					
						
							|  |  |  | 			Resource: []preferences.StarsResource{{ | 
					
						
							|  |  |  | 				Group: dashboardsV1.APIGroup, | 
					
						
							|  |  |  | 				Kind:  "Dashboard", | 
					
						
							|  |  |  | 				Names: v.Dashboards, | 
					
						
							|  |  |  | 			}}, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2025-10-07 02:08:10 +08:00
										 |  |  | 	if len(history) > 0 { | 
					
						
							|  |  |  | 		stars.Spec.Resource = append(stars.Spec.Resource, preferences.StarsResource{ | 
					
						
							|  |  |  | 			Group: "history.grafana.app", | 
					
						
							|  |  |  | 			Kind:  "Query", | 
					
						
							|  |  |  | 			Names: history, | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	stars.Spec.Normalize() | 
					
						
							|  |  |  | 	return stars | 
					
						
							| 
									
										
										
										
											2025-08-29 00:51:32 +08:00
										 |  |  | } |