Merge pull request #13644 from grafana/backend-hooks-service

Adds backend hooks service so extensions can modify index data
This commit is contained in:
Torkel Ödegaard 2018-10-12 13:47:40 +02:00 committed by GitHub
commit e78c1b4abc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 103 additions and 77 deletions

View File

@ -22,66 +22,66 @@ func (hs *HTTPServer) registerRoutes() {
r := hs.RouteRegister r := hs.RouteRegister
// not logged in views // not logged in views
r.Get("/", reqSignedIn, Index) r.Get("/", reqSignedIn, hs.Index)
r.Get("/logout", Logout) r.Get("/logout", Logout)
r.Post("/login", quota("session"), bind(dtos.LoginCommand{}), Wrap(LoginPost)) r.Post("/login", quota("session"), bind(dtos.LoginCommand{}), Wrap(LoginPost))
r.Get("/login/:name", quota("session"), OAuthLogin) r.Get("/login/:name", quota("session"), OAuthLogin)
r.Get("/login", LoginView) r.Get("/login", hs.LoginView)
r.Get("/invite/:code", Index) r.Get("/invite/:code", hs.Index)
// authed views // authed views
r.Get("/profile/", reqSignedIn, Index) r.Get("/profile/", reqSignedIn, hs.Index)
r.Get("/profile/password", reqSignedIn, Index) r.Get("/profile/password", reqSignedIn, hs.Index)
r.Get("/profile/switch-org/:id", reqSignedIn, ChangeActiveOrgAndRedirectToHome) r.Get("/profile/switch-org/:id", reqSignedIn, hs.ChangeActiveOrgAndRedirectToHome)
r.Get("/org/", reqSignedIn, Index) r.Get("/org/", reqSignedIn, hs.Index)
r.Get("/org/new", reqSignedIn, Index) r.Get("/org/new", reqSignedIn, hs.Index)
r.Get("/datasources/", reqSignedIn, Index) r.Get("/datasources/", reqSignedIn, hs.Index)
r.Get("/datasources/new", reqSignedIn, Index) r.Get("/datasources/new", reqSignedIn, hs.Index)
r.Get("/datasources/edit/*", reqSignedIn, Index) r.Get("/datasources/edit/*", reqSignedIn, hs.Index)
r.Get("/org/users", reqSignedIn, Index) r.Get("/org/users", reqSignedIn, hs.Index)
r.Get("/org/users/new", reqSignedIn, Index) r.Get("/org/users/new", reqSignedIn, hs.Index)
r.Get("/org/users/invite", reqSignedIn, Index) r.Get("/org/users/invite", reqSignedIn, hs.Index)
r.Get("/org/teams", reqSignedIn, Index) r.Get("/org/teams", reqSignedIn, hs.Index)
r.Get("/org/teams/*", reqSignedIn, Index) r.Get("/org/teams/*", reqSignedIn, hs.Index)
r.Get("/org/apikeys/", reqSignedIn, Index) r.Get("/org/apikeys/", reqSignedIn, hs.Index)
r.Get("/dashboard/import/", reqSignedIn, Index) r.Get("/dashboard/import/", reqSignedIn, hs.Index)
r.Get("/configuration", reqGrafanaAdmin, Index) r.Get("/configuration", reqGrafanaAdmin, hs.Index)
r.Get("/admin", reqGrafanaAdmin, Index) r.Get("/admin", reqGrafanaAdmin, hs.Index)
r.Get("/admin/settings", reqGrafanaAdmin, Index) r.Get("/admin/settings", reqGrafanaAdmin, hs.Index)
r.Get("/admin/users", reqGrafanaAdmin, Index) r.Get("/admin/users", reqGrafanaAdmin, hs.Index)
r.Get("/admin/users/create", reqGrafanaAdmin, Index) r.Get("/admin/users/create", reqGrafanaAdmin, hs.Index)
r.Get("/admin/users/edit/:id", reqGrafanaAdmin, Index) r.Get("/admin/users/edit/:id", reqGrafanaAdmin, hs.Index)
r.Get("/admin/orgs", reqGrafanaAdmin, Index) r.Get("/admin/orgs", reqGrafanaAdmin, hs.Index)
r.Get("/admin/orgs/edit/:id", reqGrafanaAdmin, Index) r.Get("/admin/orgs/edit/:id", reqGrafanaAdmin, hs.Index)
r.Get("/admin/stats", reqGrafanaAdmin, Index) r.Get("/admin/stats", reqGrafanaAdmin, hs.Index)
r.Get("/styleguide", reqSignedIn, Index) r.Get("/styleguide", reqSignedIn, hs.Index)
r.Get("/plugins", reqSignedIn, Index) r.Get("/plugins", reqSignedIn, hs.Index)
r.Get("/plugins/:id/edit", reqSignedIn, Index) r.Get("/plugins/:id/edit", reqSignedIn, hs.Index)
r.Get("/plugins/:id/page/:page", reqSignedIn, Index) r.Get("/plugins/:id/page/:page", reqSignedIn, hs.Index)
r.Get("/d/:uid/:slug", reqSignedIn, Index) r.Get("/d/:uid/:slug", reqSignedIn, hs.Index)
r.Get("/d/:uid", reqSignedIn, Index) r.Get("/d/:uid", reqSignedIn, hs.Index)
r.Get("/dashboard/db/:slug", reqSignedIn, redirectFromLegacyDashboardURL, Index) r.Get("/dashboard/db/:slug", reqSignedIn, redirectFromLegacyDashboardURL, hs.Index)
r.Get("/dashboard/script/*", reqSignedIn, Index) r.Get("/dashboard/script/*", reqSignedIn, hs.Index)
r.Get("/dashboard-solo/snapshot/*", Index) r.Get("/dashboard-solo/snapshot/*", hs.Index)
r.Get("/d-solo/:uid/:slug", reqSignedIn, Index) r.Get("/d-solo/:uid/:slug", reqSignedIn, hs.Index)
r.Get("/dashboard-solo/db/:slug", reqSignedIn, redirectFromLegacyDashboardSoloURL, Index) r.Get("/dashboard-solo/db/:slug", reqSignedIn, redirectFromLegacyDashboardSoloURL, hs.Index)
r.Get("/dashboard-solo/script/*", reqSignedIn, Index) r.Get("/dashboard-solo/script/*", reqSignedIn, hs.Index)
r.Get("/import/dashboard", reqSignedIn, Index) r.Get("/import/dashboard", reqSignedIn, hs.Index)
r.Get("/dashboards/", reqSignedIn, Index) r.Get("/dashboards/", reqSignedIn, hs.Index)
r.Get("/dashboards/*", reqSignedIn, Index) r.Get("/dashboards/*", reqSignedIn, hs.Index)
r.Get("/explore", reqEditorRole, Index) r.Get("/explore", reqEditorRole, hs.Index)
r.Get("/playlists/", reqSignedIn, Index) r.Get("/playlists/", reqSignedIn, hs.Index)
r.Get("/playlists/*", reqSignedIn, Index) r.Get("/playlists/*", reqSignedIn, hs.Index)
r.Get("/alerting/", reqSignedIn, Index) r.Get("/alerting/", reqSignedIn, hs.Index)
r.Get("/alerting/*", reqSignedIn, Index) r.Get("/alerting/*", reqSignedIn, hs.Index)
// sign up // sign up
r.Get("/signup", Index) r.Get("/signup", hs.Index)
r.Get("/api/user/signup/options", Wrap(GetSignUpOptions)) r.Get("/api/user/signup/options", Wrap(GetSignUpOptions))
r.Post("/api/user/signup", quota("user"), bind(dtos.SignUpForm{}), Wrap(SignUp)) r.Post("/api/user/signup", quota("user"), bind(dtos.SignUpForm{}), Wrap(SignUp))
r.Post("/api/user/signup/step2", bind(dtos.SignUpStep2Form{}), Wrap(SignUpStep2)) r.Post("/api/user/signup/step2", bind(dtos.SignUpStep2Form{}), Wrap(SignUpStep2))
@ -91,15 +91,15 @@ func (hs *HTTPServer) registerRoutes() {
r.Post("/api/user/invite/complete", bind(dtos.CompleteInviteForm{}), Wrap(CompleteInvite)) r.Post("/api/user/invite/complete", bind(dtos.CompleteInviteForm{}), Wrap(CompleteInvite))
// reset password // reset password
r.Get("/user/password/send-reset-email", Index) r.Get("/user/password/send-reset-email", hs.Index)
r.Get("/user/password/reset", Index) r.Get("/user/password/reset", hs.Index)
r.Post("/api/user/password/send-reset-email", bind(dtos.SendResetPasswordEmailForm{}), Wrap(SendResetPasswordEmail)) r.Post("/api/user/password/send-reset-email", bind(dtos.SendResetPasswordEmailForm{}), Wrap(SendResetPasswordEmail))
r.Post("/api/user/password/reset", bind(dtos.ResetUserPasswordForm{}), Wrap(ResetPassword)) r.Post("/api/user/password/reset", bind(dtos.ResetUserPasswordForm{}), Wrap(ResetPassword))
// dashboard snapshots // dashboard snapshots
r.Get("/dashboard/snapshot/*", Index) r.Get("/dashboard/snapshot/*", hs.Index)
r.Get("/dashboard/snapshots/", reqSignedIn, Index) r.Get("/dashboard/snapshots/", reqSignedIn, hs.Index)
// api for dashboard snapshots // api for dashboard snapshots
r.Post("/api/snapshots/", bind(m.CreateDashboardSnapshotCommand{}), CreateDashboardSnapshot) r.Post("/api/snapshots/", bind(m.CreateDashboardSnapshotCommand{}), CreateDashboardSnapshot)

View File

@ -28,6 +28,7 @@ import (
"github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/plugins" "github.com/grafana/grafana/pkg/plugins"
"github.com/grafana/grafana/pkg/registry" "github.com/grafana/grafana/pkg/registry"
"github.com/grafana/grafana/pkg/services/hooks"
"github.com/grafana/grafana/pkg/services/rendering" "github.com/grafana/grafana/pkg/services/rendering"
"github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/setting"
) )
@ -52,6 +53,7 @@ type HTTPServer struct {
Bus bus.Bus `inject:""` Bus bus.Bus `inject:""`
RenderService rendering.Service `inject:""` RenderService rendering.Service `inject:""`
Cfg *setting.Cfg `inject:""` Cfg *setting.Cfg `inject:""`
HooksService *hooks.HooksService `inject:""`
} }
func (hs *HTTPServer) Init() error { func (hs *HTTPServer) Init() error {
@ -184,7 +186,7 @@ func (hs *HTTPServer) applyRoutes() {
// then custom app proxy routes // then custom app proxy routes
hs.initAppPluginRoutes(hs.macaron) hs.initAppPluginRoutes(hs.macaron)
// lastly not found route // lastly not found route
hs.macaron.NotFound(NotFoundHandler) hs.macaron.NotFound(hs.NotFoundHandler)
} }
func (hs *HTTPServer) addMiddlewaresAndStaticRoutes() { func (hs *HTTPServer) addMiddlewaresAndStaticRoutes() {

View File

@ -17,7 +17,7 @@ const (
darkName = "dark" darkName = "dark"
) )
func setIndexViewData(c *m.ReqContext) (*dtos.IndexViewData, error) { func (hs *HTTPServer) setIndexViewData(c *m.ReqContext) (*dtos.IndexViewData, error) {
settings, err := getFrontendSettingsMap(c) settings, err := getFrontendSettingsMap(c)
if err != nil { if err != nil {
return nil, err return nil, err
@ -316,19 +316,6 @@ func setIndexViewData(c *m.ReqContext) (*dtos.IndexViewData, error) {
} }
if c.IsGrafanaAdmin { if c.IsGrafanaAdmin {
children := []*dtos.NavLink{
{Text: "Users", Id: "global-users", Url: setting.AppSubUrl + "/admin/users", Icon: "gicon gicon-user"},
{Text: "Orgs", Id: "global-orgs", Url: setting.AppSubUrl + "/admin/orgs", Icon: "gicon gicon-org"},
{Text: "Settings", Id: "server-settings", Url: setting.AppSubUrl + "/admin/settings", Icon: "gicon gicon-preferences"},
{Text: "Stats", Id: "server-stats", Url: setting.AppSubUrl + "/admin/stats", Icon: "fa fa-fw fa-bar-chart"},
}
if setting.IsEnterprise {
children = append(children, &dtos.NavLink{Text: "Licensing", Id: "licensing", Url: setting.AppSubUrl + "/admin/licensing", Icon: "fa fa-fw fa-unlock-alt"})
}
children = append(children, &dtos.NavLink{Text: "Style Guide", Id: "styleguide", Url: setting.AppSubUrl + "/styleguide", Icon: "fa fa-fw fa-eyedropper"})
cfgNode.Children = append(cfgNode.Children, &dtos.NavLink{ cfgNode.Children = append(cfgNode.Children, &dtos.NavLink{
Text: "Server Admin", Text: "Server Admin",
HideFromTabs: true, HideFromTabs: true,
@ -336,7 +323,13 @@ func setIndexViewData(c *m.ReqContext) (*dtos.IndexViewData, error) {
Id: "admin", Id: "admin",
Icon: "gicon gicon-shield", Icon: "gicon gicon-shield",
Url: setting.AppSubUrl + "/admin/users", Url: setting.AppSubUrl + "/admin/users",
Children: children, Children: []*dtos.NavLink{
{Text: "Users", Id: "global-users", Url: setting.AppSubUrl + "/admin/users", Icon: "gicon gicon-user"},
{Text: "Orgs", Id: "global-orgs", Url: setting.AppSubUrl + "/admin/orgs", Icon: "gicon gicon-org"},
{Text: "Settings", Id: "server-settings", Url: setting.AppSubUrl + "/admin/settings", Icon: "gicon gicon-preferences"},
{Text: "Stats", Id: "server-stats", Url: setting.AppSubUrl + "/admin/stats", Icon: "fa fa-fw fa-bar-chart"},
{Text: "Style Guide", Id: "styleguide", Url: setting.AppSubUrl + "/styleguide", Icon: "fa fa-fw fa-eyedropper"},
},
}) })
} }
@ -357,11 +350,12 @@ func setIndexViewData(c *m.ReqContext) (*dtos.IndexViewData, error) {
}, },
}) })
hs.HooksService.RunIndexDataHooks(&data)
return &data, nil return &data, nil
} }
func Index(c *m.ReqContext) { func (hs *HTTPServer) Index(c *m.ReqContext) {
data, err := setIndexViewData(c) data, err := hs.setIndexViewData(c)
if err != nil { if err != nil {
c.Handle(500, "Failed to get settings", err) c.Handle(500, "Failed to get settings", err)
return return
@ -369,13 +363,13 @@ func Index(c *m.ReqContext) {
c.HTML(200, "index", data) c.HTML(200, "index", data)
} }
func NotFoundHandler(c *m.ReqContext) { func (hs *HTTPServer) NotFoundHandler(c *m.ReqContext) {
if c.IsApiRequest() { if c.IsApiRequest() {
c.JsonApiErr(404, "Not found", nil) c.JsonApiErr(404, "Not found", nil)
return return
} }
data, err := setIndexViewData(c) data, err := hs.setIndexViewData(c)
if err != nil { if err != nil {
c.Handle(500, "Failed to get settings", err) c.Handle(500, "Failed to get settings", err)
return return

View File

@ -17,8 +17,8 @@ const (
ViewIndex = "index" ViewIndex = "index"
) )
func LoginView(c *m.ReqContext) { func (hs *HTTPServer) LoginView(c *m.ReqContext) {
viewData, err := setIndexViewData(c) viewData, err := hs.setIndexViewData(c)
if err != nil { if err != nil {
c.Handle(500, "Failed to get settings", err) c.Handle(500, "Failed to get settings", err)
return return

View File

@ -177,17 +177,17 @@ func UserSetUsingOrg(c *m.ReqContext) Response {
} }
// GET /profile/switch-org/:id // GET /profile/switch-org/:id
func ChangeActiveOrgAndRedirectToHome(c *m.ReqContext) { func (hs *HTTPServer) ChangeActiveOrgAndRedirectToHome(c *m.ReqContext) {
orgID := c.ParamsInt64(":id") orgID := c.ParamsInt64(":id")
if !validateUsingOrg(c.UserId, orgID) { if !validateUsingOrg(c.UserId, orgID) {
NotFoundHandler(c) hs.NotFoundHandler(c)
} }
cmd := m.SetUsingOrgCommand{UserId: c.UserId, OrgId: orgID} cmd := m.SetUsingOrgCommand{UserId: c.UserId, OrgId: orgID}
if err := bus.Dispatch(&cmd); err != nil { if err := bus.Dispatch(&cmd); err != nil {
NotFoundHandler(c) hs.NotFoundHandler(c)
} }
c.Redirect(setting.AppSubUrl + "/") c.Redirect(setting.AppSubUrl + "/")

View File

@ -0,0 +1,30 @@
package hooks
import (
"github.com/grafana/grafana/pkg/api/dtos"
"github.com/grafana/grafana/pkg/registry"
)
type IndexDataHook func(indexData *dtos.IndexViewData)
type HooksService struct {
indexDataHooks []IndexDataHook
}
func init() {
registry.RegisterService(&HooksService{})
}
func (srv *HooksService) Init() error {
return nil
}
func (srv *HooksService) AddIndexDataHook(hook IndexDataHook) {
srv.indexDataHooks = append(srv.indexDataHooks, hook)
}
func (srv *HooksService) RunIndexDataHooks(indexData *dtos.IndexViewData) {
for _, hook := range srv.indexDataHooks {
hook(indexData)
}
}