mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
parent
522a31c479
commit
2d4065600c
@ -89,6 +89,7 @@ import (
|
|||||||
"github.com/grafana/grafana/pkg/services/sqlstore"
|
"github.com/grafana/grafana/pkg/services/sqlstore"
|
||||||
"github.com/grafana/grafana/pkg/services/sqlstore/db"
|
"github.com/grafana/grafana/pkg/services/sqlstore/db"
|
||||||
"github.com/grafana/grafana/pkg/services/sqlstore/mockstore"
|
"github.com/grafana/grafana/pkg/services/sqlstore/mockstore"
|
||||||
|
"github.com/grafana/grafana/pkg/services/star/starimpl"
|
||||||
"github.com/grafana/grafana/pkg/services/store"
|
"github.com/grafana/grafana/pkg/services/store"
|
||||||
"github.com/grafana/grafana/pkg/services/teamguardian"
|
"github.com/grafana/grafana/pkg/services/teamguardian"
|
||||||
teamguardianDatabase "github.com/grafana/grafana/pkg/services/teamguardian/database"
|
teamguardianDatabase "github.com/grafana/grafana/pkg/services/teamguardian/database"
|
||||||
@ -258,6 +259,7 @@ var wireBasicSet = wire.NewSet(
|
|||||||
wire.Bind(new(accesscontrol.FolderPermissionsService), new(*ossaccesscontrol.FolderPermissionsService)),
|
wire.Bind(new(accesscontrol.FolderPermissionsService), new(*ossaccesscontrol.FolderPermissionsService)),
|
||||||
ossaccesscontrol.ProvideDashboardPermissions,
|
ossaccesscontrol.ProvideDashboardPermissions,
|
||||||
wire.Bind(new(accesscontrol.DashboardPermissionsService), new(*ossaccesscontrol.DashboardPermissionsService)),
|
wire.Bind(new(accesscontrol.DashboardPermissionsService), new(*ossaccesscontrol.DashboardPermissionsService)),
|
||||||
|
starimpl.ProvideService,
|
||||||
)
|
)
|
||||||
|
|
||||||
var wireSet = wire.NewSet(
|
var wireSet = wire.NewSet(
|
||||||
|
54
pkg/services/star/model.go
Normal file
54
pkg/services/star/model.go
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
package star
|
||||||
|
|
||||||
|
import "errors"
|
||||||
|
|
||||||
|
var ErrCommandValidationFailed = errors.New("command missing required fields")
|
||||||
|
|
||||||
|
type Star struct {
|
||||||
|
ID int64 `xorm:"pk autoincr 'id'"`
|
||||||
|
UserID int64 `xorm:"user_id"`
|
||||||
|
DashboardID int64 `xorm:"dashboard_id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------
|
||||||
|
// COMMANDS
|
||||||
|
|
||||||
|
type StarDashboardCommand struct {
|
||||||
|
UserID int64 `xorm:"user_id"`
|
||||||
|
DashboardID int64 `xorm:"dashboard_id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cmd *StarDashboardCommand) Validate() error {
|
||||||
|
if cmd.DashboardID == 0 || cmd.UserID == 0 {
|
||||||
|
return ErrCommandValidationFailed
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type UnstarDashboardCommand struct {
|
||||||
|
UserID int64 `xorm:"user_id"`
|
||||||
|
DashboardID int64 `xorm:"dashboard_id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cmd *UnstarDashboardCommand) Validate() error {
|
||||||
|
if cmd.DashboardID == 0 || cmd.UserID == 0 {
|
||||||
|
return ErrCommandValidationFailed
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------
|
||||||
|
// QUERIES
|
||||||
|
|
||||||
|
type GetUserStarsQuery struct {
|
||||||
|
UserID int64 `xorm:"user_id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type IsStarredByUserQuery struct {
|
||||||
|
UserID int64 `xorm:"user_id"`
|
||||||
|
DashboardID int64 `xorm:"dashboard_id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type GetUserStarsResult struct {
|
||||||
|
UserStars map[int64]bool
|
||||||
|
}
|
12
pkg/services/star/star.go
Normal file
12
pkg/services/star/star.go
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
package star
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Service interface {
|
||||||
|
Add(ctx context.Context, cmd *StarDashboardCommand) error
|
||||||
|
Delete(ctx context.Context, cmd *UnstarDashboardCommand) error
|
||||||
|
IsStarredByUser(ctx context.Context, query *IsStarredByUserQuery) (bool, error)
|
||||||
|
GetByUser(ctx context.Context, cmd *GetUserStarsQuery) (*GetUserStarsResult, error)
|
||||||
|
}
|
42
pkg/services/star/starimpl/star.go
Normal file
42
pkg/services/star/starimpl/star.go
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
package starimpl
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/grafana/grafana/pkg/services/sqlstore/db"
|
||||||
|
"github.com/grafana/grafana/pkg/services/star"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Service struct {
|
||||||
|
store store
|
||||||
|
}
|
||||||
|
|
||||||
|
func ProvideService(db db.DB) *Service {
|
||||||
|
return &Service{
|
||||||
|
store: &sqlStore{
|
||||||
|
db: db,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) Add(ctx context.Context, cmd *star.StarDashboardCommand) error {
|
||||||
|
if err := cmd.Validate(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return s.store.Insert(ctx, cmd)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) Delete(ctx context.Context, cmd *star.UnstarDashboardCommand) error {
|
||||||
|
if err := cmd.Validate(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return s.store.Delete(ctx, cmd)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) IsStarredByUser(ctx context.Context, query *star.IsStarredByUserQuery) (bool, error) {
|
||||||
|
return s.store.Get(ctx, query)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) GetByUser(ctx context.Context, cmd *star.GetUserStarsQuery) (*star.GetUserStarsResult, error) {
|
||||||
|
return s.store.List(ctx, cmd)
|
||||||
|
}
|
69
pkg/services/star/starimpl/store.go
Normal file
69
pkg/services/star/starimpl/store.go
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
package starimpl
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/grafana/grafana/pkg/services/sqlstore"
|
||||||
|
"github.com/grafana/grafana/pkg/services/sqlstore/db"
|
||||||
|
"github.com/grafana/grafana/pkg/services/star"
|
||||||
|
)
|
||||||
|
|
||||||
|
type store interface {
|
||||||
|
Get(ctx context.Context, query *star.IsStarredByUserQuery) (bool, error)
|
||||||
|
Insert(ctx context.Context, cmd *star.StarDashboardCommand) error
|
||||||
|
Delete(ctx context.Context, cmd *star.UnstarDashboardCommand) error
|
||||||
|
List(ctx context.Context, query *star.GetUserStarsQuery) (*star.GetUserStarsResult, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type sqlStore struct {
|
||||||
|
db db.DB
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *sqlStore) Get(ctx context.Context, query *star.IsStarredByUserQuery) (bool, error) {
|
||||||
|
var isStarred bool
|
||||||
|
err := s.db.WithDbSession(ctx, func(sess *sqlstore.DBSession) error {
|
||||||
|
rawSQL := "SELECT 1 from star where user_id=? and dashboard_id=?"
|
||||||
|
results, err := sess.Query(rawSQL, query.UserID, query.DashboardID)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
isStarred = len(results) != 0
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
return isStarred, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *sqlStore) Insert(ctx context.Context, cmd *star.StarDashboardCommand) error {
|
||||||
|
return s.db.WithTransactionalDbSession(ctx, func(sess *sqlstore.DBSession) error {
|
||||||
|
entity := star.Star{
|
||||||
|
UserID: cmd.UserID,
|
||||||
|
DashboardID: cmd.DashboardID,
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := sess.Insert(&entity)
|
||||||
|
return err
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *sqlStore) Delete(ctx context.Context, cmd *star.UnstarDashboardCommand) error {
|
||||||
|
return s.db.WithTransactionalDbSession(ctx, func(sess *sqlstore.DBSession) error {
|
||||||
|
var rawSQL = "DELETE FROM star WHERE user_id=? and dashboard_id=?"
|
||||||
|
_, err := sess.Exec(rawSQL, cmd.UserID, cmd.DashboardID)
|
||||||
|
return err
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *sqlStore) List(ctx context.Context, query *star.GetUserStarsQuery) (*star.GetUserStarsResult, error) {
|
||||||
|
userStars := make(map[int64]bool)
|
||||||
|
err := s.db.WithDbSession(ctx, func(dbSession *sqlstore.DBSession) error {
|
||||||
|
var stars = make([]star.Star, 0)
|
||||||
|
err := dbSession.Where("user_id=?", query.UserID).Find(&stars)
|
||||||
|
for _, star := range stars {
|
||||||
|
userStars[star.DashboardID] = true
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
})
|
||||||
|
return &star.GetUserStarsResult{UserStars: userStars}, err
|
||||||
|
}
|
60
pkg/services/star/starimpl/store_test.go
Normal file
60
pkg/services/star/starimpl/store_test.go
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
//go:build integration
|
||||||
|
// +build integration
|
||||||
|
|
||||||
|
package starimpl
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/grafana/grafana/pkg/services/sqlstore"
|
||||||
|
"github.com/grafana/grafana/pkg/services/star"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestUserStarsDataAccess(t *testing.T) {
|
||||||
|
t.Run("Testing User Stars Data Access", func(t *testing.T) {
|
||||||
|
ss := sqlstore.InitTestDB(t)
|
||||||
|
starStore := sqlStore{db: ss}
|
||||||
|
|
||||||
|
t.Run("Given saved star", func(t *testing.T) {
|
||||||
|
cmd := star.StarDashboardCommand{
|
||||||
|
DashboardID: 10,
|
||||||
|
UserID: 12,
|
||||||
|
}
|
||||||
|
err := starStore.Insert(context.Background(), &cmd)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
t.Run("IsStarredByUser should return true when starred", func(t *testing.T) {
|
||||||
|
query := star.IsStarredByUserQuery{UserID: 12, DashboardID: 10}
|
||||||
|
isStarred, err := starStore.Get(context.Background(), &query)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.True(t, isStarred)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("IsStarredByUser should return false when not starred", func(t *testing.T) {
|
||||||
|
query := star.IsStarredByUserQuery{UserID: 12, DashboardID: 12}
|
||||||
|
isStarred, err := starStore.Get(context.Background(), &query)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.False(t, isStarred)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("List should return a list of size 1", func(t *testing.T) {
|
||||||
|
query := star.GetUserStarsQuery{UserID: 12}
|
||||||
|
result, err := starStore.List(context.Background(), &query)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, 1, len(result.UserStars))
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Delete should remove the star", func(t *testing.T) {
|
||||||
|
deleteQuery := star.UnstarDashboardCommand{DashboardID: 10, UserID: 12}
|
||||||
|
err := starStore.Delete(context.Background(), &deleteQuery)
|
||||||
|
require.NoError(t, err)
|
||||||
|
getQuery := star.IsStarredByUserQuery{UserID: 12, DashboardID: 10}
|
||||||
|
isStarred, err := starStore.Get(context.Background(), &getQuery)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.False(t, isStarred)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
33
pkg/services/star/startest/fake.go
Normal file
33
pkg/services/star/startest/fake.go
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
package startest
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/grafana/grafana/pkg/services/star"
|
||||||
|
)
|
||||||
|
|
||||||
|
type FakeStarService struct {
|
||||||
|
ExpectedStars *star.Star
|
||||||
|
ExpectedError error
|
||||||
|
ExpectedUserStars *star.GetUserStarsResult
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewStarServiceFake() *FakeStarService {
|
||||||
|
return &FakeStarService{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FakeStarService) IsStarredByUser(ctx context.Context, query *star.IsStarredByUserQuery) (bool, error) {
|
||||||
|
return true, f.ExpectedError
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FakeStarService) Add(ctx context.Context, cmd *star.StarDashboardCommand) error {
|
||||||
|
return f.ExpectedError
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FakeStarService) Delete(ctx context.Context, cmd *star.UnstarDashboardCommand) error {
|
||||||
|
return f.ExpectedError
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FakeStarService) GetByUser(ctx context.Context, query *star.GetUserStarsQuery) (*star.GetUserStarsResult, error) {
|
||||||
|
return f.ExpectedUserStars, f.ExpectedError
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user