|
|
|
|
@ -2,15 +2,145 @@ package api |
|
|
|
|
|
|
|
|
|
import ( |
|
|
|
|
"net/http" |
|
|
|
|
"strings" |
|
|
|
|
|
|
|
|
|
"k8s.io/apimachinery/pkg/api/errors" |
|
|
|
|
v1 "k8s.io/apimachinery/pkg/apis/meta/v1" |
|
|
|
|
"k8s.io/apimachinery/pkg/runtime/schema" |
|
|
|
|
"k8s.io/client-go/dynamic" |
|
|
|
|
|
|
|
|
|
"github.com/grafana/grafana/pkg/api/dtos" |
|
|
|
|
"github.com/grafana/grafana/pkg/api/response" |
|
|
|
|
"github.com/grafana/grafana/pkg/api/routing" |
|
|
|
|
"github.com/grafana/grafana/pkg/apis/playlist/v0alpha1" |
|
|
|
|
"github.com/grafana/grafana/pkg/middleware" |
|
|
|
|
contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model" |
|
|
|
|
"github.com/grafana/grafana/pkg/services/featuremgmt" |
|
|
|
|
"github.com/grafana/grafana/pkg/services/grafana-apiserver/endpoints/request" |
|
|
|
|
"github.com/grafana/grafana/pkg/services/playlist" |
|
|
|
|
"github.com/grafana/grafana/pkg/util/errutil/errhttp" |
|
|
|
|
"github.com/grafana/grafana/pkg/web" |
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
func (hs *HTTPServer) ValidateOrgPlaylist(c *contextmodel.ReqContext) { |
|
|
|
|
type playlistAPIHandler struct { |
|
|
|
|
SearchPlaylists []web.Handler |
|
|
|
|
GetPlaylist []web.Handler |
|
|
|
|
GetPlaylistItems []web.Handler |
|
|
|
|
DeletePlaylist []web.Handler |
|
|
|
|
UpdatePlaylist []web.Handler |
|
|
|
|
CreatePlaylist []web.Handler |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func chainHandlers(h ...web.Handler) []web.Handler { |
|
|
|
|
return h |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (hs *HTTPServer) registerPlaylistAPI(apiRoute routing.RouteRegister) { |
|
|
|
|
handler := playlistAPIHandler{ |
|
|
|
|
SearchPlaylists: chainHandlers(routing.Wrap(hs.SearchPlaylists)), |
|
|
|
|
GetPlaylist: chainHandlers(hs.validateOrgPlaylist, routing.Wrap(hs.GetPlaylist)), |
|
|
|
|
GetPlaylistItems: chainHandlers(hs.validateOrgPlaylist, routing.Wrap(hs.GetPlaylistItems)), |
|
|
|
|
DeletePlaylist: chainHandlers(middleware.ReqEditorRole, hs.validateOrgPlaylist, routing.Wrap(hs.DeletePlaylist)), |
|
|
|
|
UpdatePlaylist: chainHandlers(middleware.ReqEditorRole, hs.validateOrgPlaylist, routing.Wrap(hs.UpdatePlaylist)), |
|
|
|
|
CreatePlaylist: chainHandlers(middleware.ReqEditorRole, routing.Wrap(hs.CreatePlaylist)), |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Alternative implementations for k8s
|
|
|
|
|
if hs.Features.IsEnabled(featuremgmt.FlagKubernetesPlaylistsAPI) { |
|
|
|
|
namespacer := request.GetNamespaceMapper(hs.Cfg) |
|
|
|
|
gvr := schema.GroupVersionResource{ |
|
|
|
|
Group: v0alpha1.GroupName, |
|
|
|
|
Version: v0alpha1.VersionID, |
|
|
|
|
Resource: "playlists", |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
clientGetter := func(c *contextmodel.ReqContext) (dynamic.ResourceInterface, bool) { |
|
|
|
|
dyn, err := dynamic.NewForConfig(hs.clientConfigProvider.GetDirectRestConfig(c)) |
|
|
|
|
if err != nil { |
|
|
|
|
c.JsonApiErr(500, "client", err) |
|
|
|
|
return nil, false |
|
|
|
|
} |
|
|
|
|
return dyn.Resource(gvr).Namespace(namespacer(c.OrgID)), true |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
errorWriter := func(c *contextmodel.ReqContext, err error) { |
|
|
|
|
//nolint:errorlint
|
|
|
|
|
statusError, ok := err.(*errors.StatusError) |
|
|
|
|
if ok { |
|
|
|
|
c.JsonApiErr(int(statusError.Status().Code), |
|
|
|
|
statusError.Status().Message, err) |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
errhttp.Write(c.Req.Context(), err, c.Resp) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
handler.SearchPlaylists = []web.Handler{func(c *contextmodel.ReqContext) { |
|
|
|
|
client, ok := clientGetter(c) |
|
|
|
|
if !ok { |
|
|
|
|
return // error is already sent
|
|
|
|
|
} |
|
|
|
|
out, err := client.List(c.Req.Context(), v1.ListOptions{}) |
|
|
|
|
if err != nil { |
|
|
|
|
errorWriter(c, err) |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
query := strings.ToUpper(c.Query("query")) |
|
|
|
|
playlists := []playlist.Playlist{} |
|
|
|
|
for _, item := range out.Items { |
|
|
|
|
p := v0alpha1.UnstructuredToLegacyPlaylist(item) |
|
|
|
|
if p == nil { |
|
|
|
|
continue |
|
|
|
|
} |
|
|
|
|
if query != "" && !strings.Contains(strings.ToUpper(p.Name), query) { |
|
|
|
|
continue // query filter
|
|
|
|
|
} |
|
|
|
|
playlists = append(playlists, *p) |
|
|
|
|
} |
|
|
|
|
c.JSON(http.StatusOK, playlists) |
|
|
|
|
}} |
|
|
|
|
|
|
|
|
|
handler.GetPlaylist = []web.Handler{func(c *contextmodel.ReqContext) { |
|
|
|
|
client, ok := clientGetter(c) |
|
|
|
|
if !ok { |
|
|
|
|
return // error is already sent
|
|
|
|
|
} |
|
|
|
|
uid := web.Params(c.Req)[":uid"] |
|
|
|
|
out, err := client.Get(c.Req.Context(), uid, v1.GetOptions{}) |
|
|
|
|
if err != nil { |
|
|
|
|
errorWriter(c, err) |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
c.JSON(http.StatusOK, v0alpha1.UnstructuredToLegacyPlaylistDTO(*out)) |
|
|
|
|
}} |
|
|
|
|
|
|
|
|
|
handler.GetPlaylistItems = []web.Handler{func(c *contextmodel.ReqContext) { |
|
|
|
|
client, ok := clientGetter(c) |
|
|
|
|
if !ok { |
|
|
|
|
return // error is already sent
|
|
|
|
|
} |
|
|
|
|
uid := web.Params(c.Req)[":uid"] |
|
|
|
|
out, err := client.Get(c.Req.Context(), uid, v1.GetOptions{}) |
|
|
|
|
if err != nil { |
|
|
|
|
errorWriter(c, err) |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
c.JSON(http.StatusOK, v0alpha1.UnstructuredToLegacyPlaylistDTO(*out).Items) |
|
|
|
|
}} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Register the actual handlers
|
|
|
|
|
apiRoute.Group("/playlists", func(playlistRoute routing.RouteRegister) { |
|
|
|
|
playlistRoute.Get("/", handler.SearchPlaylists...) |
|
|
|
|
playlistRoute.Get("/:uid", handler.GetPlaylist...) |
|
|
|
|
playlistRoute.Get("/:uid/items", handler.GetPlaylistItems...) |
|
|
|
|
playlistRoute.Delete("/:uid", handler.DeletePlaylist...) |
|
|
|
|
playlistRoute.Put("/:uid", handler.UpdatePlaylist...) |
|
|
|
|
playlistRoute.Post("/", handler.CreatePlaylist...) |
|
|
|
|
}) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (hs *HTTPServer) validateOrgPlaylist(c *contextmodel.ReqContext) { |
|
|
|
|
uid := web.Params(c.Req)[":uid"] |
|
|
|
|
query := playlist.GetPlaylistByUidQuery{UID: uid, OrgId: c.SignedInUser.GetOrgID()} |
|
|
|
|
p, err := hs.playlistService.GetWithoutItems(c.Req.Context(), &query) |
|
|
|
|
|