From bbdd1fc3b176bab613fc79c242902077082e83ae Mon Sep 17 00:00:00 2001 From: Ryan McKinley Date: Wed, 27 Sep 2023 08:28:16 -0700 Subject: [PATCH] Playlist: Remove unused/deprecated api and unused wrapper (#75503) --- docs/sources/developers/http_api/playlist.md | 32 --- pkg/api/api.go | 1 - pkg/api/playlist.go | 21 -- pkg/api/playlist_play.go | 110 ---------- .../playlist/playlistimpl/entity_store.go | 188 ------------------ .../playlist/playlistimpl/playlist.go | 17 +- public/api-merged.json | 34 ---- public/openapi3.json | 36 ---- 8 files changed, 2 insertions(+), 437 deletions(-) delete mode 100644 pkg/api/playlist_play.go delete mode 100644 pkg/services/playlist/playlistimpl/entity_store.go diff --git a/docs/sources/developers/http_api/playlist.md b/docs/sources/developers/http_api/playlist.md index f25c1ba301f..d1e3a4e7c90 100644 --- a/docs/sources/developers/http_api/playlist.md +++ b/docs/sources/developers/http_api/playlist.md @@ -132,38 +132,6 @@ Content-Type: application/json ] ``` -## Get Playlist dashboards - -`GET /api/playlists/:uid/dashboards` - -**Example Request**: - -```http -GET /api/playlists/1/dashboards HTTP/1.1 -Accept: application/json -Authorization: Bearer eyJrIjoiT0tTcG1pUlY2RnVKZTFVaDFsNFZXdE9ZWmNrMkZYbk -``` - -**Example Response**: - -```http -HTTP/1.1 200 -Content-Type: application/json -[ - { - "id": 3, - "title": "my third dashboard", - "order": 1, - }, - { - "id": 5, - "title":"my other dashboard" - "order": 2, - - } -] -``` - ## Create a playlist `POST /api/playlists/` diff --git a/pkg/api/api.go b/pkg/api/api.go index e2f856f7035..cad49e0c4c6 100644 --- a/pkg/api/api.go +++ b/pkg/api/api.go @@ -520,7 +520,6 @@ func (hs *HTTPServer) registerRoutes() { playlistRoute.Get("/", routing.Wrap(hs.SearchPlaylists)) playlistRoute.Get("/:uid", hs.ValidateOrgPlaylist, routing.Wrap(hs.GetPlaylist)) playlistRoute.Get("/:uid/items", hs.ValidateOrgPlaylist, routing.Wrap(hs.GetPlaylistItems)) - playlistRoute.Get("/:uid/dashboards", hs.ValidateOrgPlaylist, routing.Wrap(hs.GetPlaylistDashboards)) playlistRoute.Delete("/:uid", reqEditorRole, hs.ValidateOrgPlaylist, routing.Wrap(hs.DeletePlaylist)) playlistRoute.Put("/:uid", reqEditorRole, hs.ValidateOrgPlaylist, routing.Wrap(hs.UpdatePlaylist)) playlistRoute.Post("/", reqEditorRole, routing.Wrap(hs.CreatePlaylist)) diff --git a/pkg/api/playlist.go b/pkg/api/playlist.go index b9303bff7b3..da4c7c112cc 100644 --- a/pkg/api/playlist.go +++ b/pkg/api/playlist.go @@ -104,27 +104,6 @@ func (hs *HTTPServer) GetPlaylistItems(c *contextmodel.ReqContext) response.Resp return response.JSON(http.StatusOK, dto.Items) } -// swagger:route GET /playlists/{uid}/dashboards playlists getPlaylistDashboards -// -// Get playlist dashboards. -// -// Responses: -// 200: getPlaylistDashboardsResponse -// 401: unauthorisedError -// 403: forbiddenError -// 404: notFoundError -// 500: internalServerError -func (hs *HTTPServer) GetPlaylistDashboards(c *contextmodel.ReqContext) response.Response { - playlistUID := web.Params(c.Req)[":uid"] - - playlists, err := hs.LoadPlaylistDashboards(c.Req.Context(), c.OrgID, c.SignedInUser, playlistUID) - if err != nil { - return response.Error(500, "Could not load dashboards", err) - } - - return response.JSON(http.StatusOK, playlists) -} - // swagger:route DELETE /playlists/{uid} playlists deletePlaylist // // Delete playlist. diff --git a/pkg/api/playlist_play.go b/pkg/api/playlist_play.go deleted file mode 100644 index 5a33185d855..00000000000 --- a/pkg/api/playlist_play.go +++ /dev/null @@ -1,110 +0,0 @@ -package api - -import ( - "context" - "errors" - "sort" - "strconv" - - "github.com/grafana/grafana/pkg/api/dtos" - _ "github.com/grafana/grafana/pkg/infra/log" - "github.com/grafana/grafana/pkg/services/dashboards" - "github.com/grafana/grafana/pkg/services/playlist" - "github.com/grafana/grafana/pkg/services/search" - "github.com/grafana/grafana/pkg/services/user" -) - -func (hs *HTTPServer) populateDashboardsByID(ctx context.Context, dashboardByIDs []int64, dashboardIDOrder map[int64]int) (dtos.PlaylistDashboardsSlice, error) { - result := make(dtos.PlaylistDashboardsSlice, 0) - - if len(dashboardByIDs) > 0 { - dashboardQuery := dashboards.GetDashboardsQuery{DashboardIDs: dashboardByIDs} - dashboardQueryResult, err := hs.DashboardService.GetDashboards(ctx, &dashboardQuery) - if err != nil { - return result, err - } - - for _, item := range dashboardQueryResult { - result = append(result, dtos.PlaylistDashboard{ - Id: item.ID, - Slug: item.Slug, - Title: item.Title, - Uri: "db/" + item.Slug, - Url: dashboards.GetDashboardURL(item.UID, item.Slug), - Order: dashboardIDOrder[item.ID], - }) - } - } - - return result, nil -} - -func (hs *HTTPServer) populateDashboardsByTag(ctx context.Context, orgID int64, signedInUser *user.SignedInUser, dashboardByTag []string, dashboardTagOrder map[string]int) dtos.PlaylistDashboardsSlice { - result := make(dtos.PlaylistDashboardsSlice, 0) - - for _, tag := range dashboardByTag { - searchQuery := search.Query{ - Title: "", - Tags: []string{tag}, - SignedInUser: signedInUser, - Limit: 100, - IsStarred: false, - OrgId: orgID, - } - - hits, err := hs.SearchService.SearchHandler(ctx, &searchQuery) - if err == nil { - for _, item := range hits { - result = append(result, dtos.PlaylistDashboard{ - Id: item.ID, - Slug: item.Slug, - Title: item.Title, - Uri: item.URI, - Url: item.URL, - Order: dashboardTagOrder[tag], - }) - } - } - } - - return result -} - -// Deprecated -- the frontend can do this better -func (hs *HTTPServer) LoadPlaylistDashboards(ctx context.Context, orgID int64, signedInUser *user.SignedInUser, playlistUID string) (dtos.PlaylistDashboardsSlice, error) { - result := make(dtos.PlaylistDashboardsSlice, 0) - dto, err := hs.playlistService.Get(ctx, - &playlist.GetPlaylistByUidQuery{UID: playlistUID, OrgId: orgID}) - if err != nil || dto == nil || dto.Items == nil { - return result, err - } - - playlistItems := dto.Items - - dashboardByIDs := make([]int64, 0) - dashboardByTag := make([]string, 0) - dashboardIDOrder := make(map[int64]int) - dashboardTagOrder := make(map[string]int) - - for i, item := range playlistItems { - switch item.Type { - case "dashboard_by_id": - dashboardID, _ := strconv.ParseInt(item.Value, 10, 64) - dashboardByIDs = append(dashboardByIDs, dashboardID) - dashboardIDOrder[dashboardID] = i - case "dashboard_by_tag": - dashboardByTag = append(dashboardByTag, item.Value) - dashboardTagOrder[item.Value] = i - case "dashboard_by_uid": - return nil, errors.New("dashboard_by_uid not supported by this deprecated API") - default: - } - } - - k, _ := hs.populateDashboardsByID(ctx, dashboardByIDs, dashboardIDOrder) - result = append(result, k...) - result = append(result, hs.populateDashboardsByTag(ctx, orgID, signedInUser, dashboardByTag, dashboardTagOrder)...) - - sort.Sort(result) - return result, nil -} diff --git a/pkg/services/playlist/playlistimpl/entity_store.go b/pkg/services/playlist/playlistimpl/entity_store.go deleted file mode 100644 index 0f1ff1da7a5..00000000000 --- a/pkg/services/playlist/playlistimpl/entity_store.go +++ /dev/null @@ -1,188 +0,0 @@ -package playlistimpl - -import ( - "context" - "encoding/json" - "fmt" - - "github.com/grafana/grafana/pkg/infra/appcontext" - "github.com/grafana/grafana/pkg/infra/grn" - "github.com/grafana/grafana/pkg/services/playlist" - "github.com/grafana/grafana/pkg/services/sqlstore/session" - "github.com/grafana/grafana/pkg/services/store/entity" - "github.com/grafana/grafana/pkg/services/user" -) - -// This is a playlist implementation that will: -// 1. CREATE/UPDATE/DELETE everythign with existing direct SQL store -// 2. CREATE/UPDATE/DELETE same items to the object store -// 3. Use the object store for all read operations -// This givs us a safe test bed to work with the store but still roll back without any lost work -type entityStoreImpl struct { - sess *session.SessionDB - sqlimpl *Service - store entity.EntityStoreServer -} - -var _ playlist.Service = &entityStoreImpl{} - -func (s *entityStoreImpl) sync() { - type Info struct { - OrgID int64 `db:"org_id"` - UID string `db:"uid"` - } - results := []Info{} - err := s.sess.Select(context.Background(), &results, "SELECT org_id,uid FROM playlist ORDER BY org_id asc") - if err != nil { - fmt.Printf("error loading playlists") - return - } - - // Change the org_id with each row - rowUser := &user.SignedInUser{ - OrgID: 0, // gets filled in from each row - UserID: 0, // Admin user - IsGrafanaAdmin: true, - } - ctx := appcontext.WithUser(context.Background(), rowUser) - for _, info := range results { - dto, err := s.sqlimpl.Get(ctx, &playlist.GetPlaylistByUidQuery{ - OrgId: info.OrgID, - UID: info.UID, - }) - if err != nil { - fmt.Printf("error loading playlist: %v", err) - return - } - body, _ := json.Marshal(dto) - _, _ = s.store.Write(ctx, &entity.WriteEntityRequest{ - GRN: &grn.GRN{ - TenantID: info.OrgID, - ResourceIdentifier: info.UID, - ResourceKind: entity.StandardKindPlaylist, - }, - Body: body, - }) - } -} - -func (s *entityStoreImpl) Create(ctx context.Context, cmd *playlist.CreatePlaylistCommand) (*playlist.Playlist, error) { - rsp, err := s.sqlimpl.store.Insert(ctx, cmd) - if err == nil && rsp != nil { - body, err := json.Marshal(cmd) - if err != nil { - return rsp, fmt.Errorf("unable to write playlist to store") - } - _, err = s.store.Write(ctx, &entity.WriteEntityRequest{ - GRN: &grn.GRN{ - ResourceKind: entity.StandardKindPlaylist, - ResourceIdentifier: rsp.UID, - }, - Body: body, - }) - if err != nil { - return rsp, fmt.Errorf("unable to write playlist to store") - } - } - return rsp, err -} - -func (s *entityStoreImpl) Update(ctx context.Context, cmd *playlist.UpdatePlaylistCommand) (*playlist.PlaylistDTO, error) { - rsp, err := s.sqlimpl.store.Update(ctx, cmd) - if err == nil { - body, err := json.Marshal(cmd) - if err != nil { - return rsp, fmt.Errorf("unable to write playlist to store") - } - _, err = s.store.Write(ctx, &entity.WriteEntityRequest{ - GRN: &grn.GRN{ - ResourceIdentifier: rsp.Uid, - ResourceKind: entity.StandardKindPlaylist, - }, - Body: body, - }) - if err != nil { - return rsp, fmt.Errorf("unable to write playlist to store") - } - } - return rsp, err -} - -func (s *entityStoreImpl) Delete(ctx context.Context, cmd *playlist.DeletePlaylistCommand) error { - err := s.sqlimpl.store.Delete(ctx, cmd) - if err == nil { - _, err = s.store.Delete(ctx, &entity.DeleteEntityRequest{ - GRN: &grn.GRN{ - ResourceIdentifier: cmd.UID, - ResourceKind: entity.StandardKindPlaylist, - }, - }) - if err != nil { - return fmt.Errorf("unable to delete playlist to store") - } - } - return err -} - -//------------------------------------------------------ -// Read access is managed entirely by the object store -//------------------------------------------------------ - -func (s *entityStoreImpl) GetWithoutItems(ctx context.Context, q *playlist.GetPlaylistByUidQuery) (*playlist.Playlist, error) { - p, err := s.Get(ctx, q) // OrgID is actually picked from the user! - if err != nil { - return nil, err - } - return &playlist.Playlist{ - UID: p.Uid, - OrgId: q.OrgId, - Name: p.Name, - Interval: p.Interval, - }, nil -} - -func (s *entityStoreImpl) Get(ctx context.Context, q *playlist.GetPlaylistByUidQuery) (*playlist.PlaylistDTO, error) { - rsp, err := s.store.Read(ctx, &entity.ReadEntityRequest{ - GRN: &grn.GRN{ - ResourceIdentifier: q.UID, - ResourceKind: entity.StandardKindPlaylist, - }, - WithBody: true, - }) - if err != nil { - return nil, err - } - if rsp == nil || rsp.Body == nil { - return nil, fmt.Errorf("missing object") - } - - // Get the object from payload - found := &playlist.PlaylistDTO{} - err = json.Unmarshal(rsp.Body, found) - return found, err -} - -func (s *entityStoreImpl) Search(ctx context.Context, q *playlist.GetPlaylistsQuery) (playlist.Playlists, error) { - playlists := make(playlist.Playlists, 0) - - rsp, err := s.store.Search(ctx, &entity.EntitySearchRequest{ - Kind: []string{entity.StandardKindPlaylist}, - WithBody: true, - Limit: 1000, - }) - if err != nil { - return nil, err - } - for _, res := range rsp.Results { - found := &playlist.PlaylistDTO{} - if res.Body != nil { - err = json.Unmarshal(res.Body, found) - } - playlists = append(playlists, &playlist.Playlist{ - UID: res.GRN.ResourceIdentifier, - Name: res.Name, - Interval: found.Interval, - }) - } - return playlists, err -} diff --git a/pkg/services/playlist/playlistimpl/playlist.go b/pkg/services/playlist/playlistimpl/playlist.go index 93d98e6e929..054b96a7257 100644 --- a/pkg/services/playlist/playlistimpl/playlist.go +++ b/pkg/services/playlist/playlistimpl/playlist.go @@ -19,7 +19,7 @@ func ProvideService(db db.DB, toggles featuremgmt.FeatureToggles, objserver enti var sqlstore store // 🐢🐢🐢 pick the store - if toggles.IsEnabled(featuremgmt.FlagNewDBLibrary) { // hymmm not a registered feature flag + if toggles.IsEnabled(featuremgmt.FlagNewDBLibrary) { sqlstore = &sqlxStore{ sess: db.GetSqlxSession(), } @@ -28,20 +28,7 @@ func ProvideService(db db.DB, toggles featuremgmt.FeatureToggles, objserver enti db: db, } } - svc := &Service{store: sqlstore} - - // FlagObjectStore is only supported in development mode - if toggles.IsEnabled(featuremgmt.FlagEntityStore) { - impl := &entityStoreImpl{ - sqlimpl: svc, - store: objserver, - sess: db.GetSqlxSession(), - } - impl.sync() // load everythign from the existing SQL setup into the new object store - return impl - } - - return svc + return &Service{store: sqlstore} } func (s *Service) Create(ctx context.Context, cmd *playlist.CreatePlaylistCommand) (*playlist.Playlist, error) { diff --git a/public/api-merged.json b/public/api-merged.json index 25228fd5a18..e4f369b625c 100644 --- a/public/api-merged.json +++ b/public/api-merged.json @@ -7677,40 +7677,6 @@ } } }, - "/playlists/{uid}/dashboards": { - "get": { - "tags": [ - "playlists" - ], - "summary": "Get playlist dashboards.", - "operationId": "getPlaylistDashboards", - "parameters": [ - { - "type": "string", - "name": "uid", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "$ref": "#/responses/getPlaylistDashboardsResponse" - }, - "401": { - "$ref": "#/responses/unauthorisedError" - }, - "403": { - "$ref": "#/responses/forbiddenError" - }, - "404": { - "$ref": "#/responses/notFoundError" - }, - "500": { - "$ref": "#/responses/internalServerError" - } - } - } - }, "/playlists/{uid}/items": { "get": { "tags": [ diff --git a/public/openapi3.json b/public/openapi3.json index d01cd4911ce..2b10c35dbdc 100644 --- a/public/openapi3.json +++ b/public/openapi3.json @@ -19667,42 +19667,6 @@ ] } }, - "/playlists/{uid}/dashboards": { - "get": { - "operationId": "getPlaylistDashboards", - "parameters": [ - { - "in": "path", - "name": "uid", - "required": true, - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "$ref": "#/components/responses/getPlaylistDashboardsResponse" - }, - "401": { - "$ref": "#/components/responses/unauthorisedError" - }, - "403": { - "$ref": "#/components/responses/forbiddenError" - }, - "404": { - "$ref": "#/components/responses/notFoundError" - }, - "500": { - "$ref": "#/components/responses/internalServerError" - } - }, - "summary": "Get playlist dashboards.", - "tags": [ - "playlists" - ] - } - }, "/playlists/{uid}/items": { "get": { "operationId": "getPlaylistItems",