Skip to content

Commit e5b3f27

Browse files
committed
Merge branch 'apps'
2 parents f7fecdc + a15984b commit e5b3f27

File tree

160 files changed

+1768
-1177
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

160 files changed

+1768
-1177
lines changed

pkg/api/api.go

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,8 @@ func Register(r *macaron.Macaron) {
4141
r.Get("/admin/orgs", reqGrafanaAdmin, Index)
4242
r.Get("/admin/orgs/edit/:id", reqGrafanaAdmin, Index)
4343

44-
r.Get("/plugins", reqSignedIn, Index)
45-
r.Get("/plugins/edit/*", reqSignedIn, Index)
44+
r.Get("/apps", reqSignedIn, Index)
45+
r.Get("/apps/edit/*", reqSignedIn, Index)
4646

4747
r.Get("/dashboard/*", reqSignedIn, Index)
4848
r.Get("/dashboard-solo/*", reqSignedIn, Index)
@@ -120,6 +120,11 @@ func Register(r *macaron.Macaron) {
120120
r.Get("/invites", wrap(GetPendingOrgInvites))
121121
r.Post("/invites", quota("user"), bind(dtos.AddInviteForm{}), wrap(AddOrgInvite))
122122
r.Patch("/invites/:code/revoke", wrap(RevokeInvite))
123+
124+
// apps
125+
r.Get("/apps", wrap(GetOrgAppsList))
126+
r.Get("/apps/:appId/settings", wrap(GetAppSettingsById))
127+
r.Post("/apps/:appId/settings", bind(m.UpdateAppSettingsCmd{}), wrap(UpdateAppSettings))
123128
}, reqOrgAdmin)
124129

125130
// create new org
@@ -205,5 +210,7 @@ func Register(r *macaron.Macaron) {
205210
// rendering
206211
r.Get("/render/*", reqSignedIn, RenderToPng)
207212

213+
InitApiPluginRoutes(r)
214+
208215
r.NotFound(NotFoundHandler)
209216
}

pkg/api/api_plugin.go

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
package api
2+
3+
import (
4+
"encoding/json"
5+
"net/http"
6+
"net/http/httputil"
7+
"net/url"
8+
9+
"github.com/Unknwon/macaron"
10+
"github.com/grafana/grafana/pkg/log"
11+
"github.com/grafana/grafana/pkg/middleware"
12+
m "github.com/grafana/grafana/pkg/models"
13+
"github.com/grafana/grafana/pkg/plugins"
14+
"github.com/grafana/grafana/pkg/util"
15+
)
16+
17+
func InitApiPluginRoutes(r *macaron.Macaron) {
18+
for _, plugin := range plugins.ApiPlugins {
19+
log.Info("Plugin: Adding proxy routes for api plugin")
20+
for _, route := range plugin.Routes {
21+
url := util.JoinUrlFragments("/api/plugin-proxy/", route.Path)
22+
handlers := make([]macaron.Handler, 0)
23+
if route.ReqSignedIn {
24+
handlers = append(handlers, middleware.Auth(&middleware.AuthOptions{ReqSignedIn: true}))
25+
}
26+
if route.ReqGrafanaAdmin {
27+
handlers = append(handlers, middleware.Auth(&middleware.AuthOptions{ReqSignedIn: true, ReqGrafanaAdmin: true}))
28+
}
29+
if route.ReqSignedIn && route.ReqRole != "" {
30+
if route.ReqRole == m.ROLE_ADMIN {
31+
handlers = append(handlers, middleware.RoleAuth(m.ROLE_ADMIN))
32+
} else if route.ReqRole == m.ROLE_EDITOR {
33+
handlers = append(handlers, middleware.RoleAuth(m.ROLE_EDITOR, m.ROLE_ADMIN))
34+
}
35+
}
36+
handlers = append(handlers, ApiPlugin(route.Url))
37+
r.Route(url, route.Method, handlers...)
38+
log.Info("Plugin: Adding route %s", url)
39+
}
40+
}
41+
}
42+
43+
func ApiPlugin(routeUrl string) macaron.Handler {
44+
return func(c *middleware.Context) {
45+
path := c.Params("*")
46+
47+
//Create a HTTP header with the context in it.
48+
ctx, err := json.Marshal(c.SignedInUser)
49+
if err != nil {
50+
c.JsonApiErr(500, "failed to marshal context to json.", err)
51+
return
52+
}
53+
targetUrl, _ := url.Parse(routeUrl)
54+
proxy := NewApiPluginProxy(string(ctx), path, targetUrl)
55+
proxy.Transport = dataProxyTransport
56+
proxy.ServeHTTP(c.RW(), c.Req.Request)
57+
}
58+
}
59+
60+
func NewApiPluginProxy(ctx string, proxyPath string, targetUrl *url.URL) *httputil.ReverseProxy {
61+
director := func(req *http.Request) {
62+
req.URL.Scheme = targetUrl.Scheme
63+
req.URL.Host = targetUrl.Host
64+
req.Host = targetUrl.Host
65+
66+
req.URL.Path = util.JoinUrlFragments(targetUrl.Path, proxyPath)
67+
68+
// clear cookie headers
69+
req.Header.Del("Cookie")
70+
req.Header.Del("Set-Cookie")
71+
req.Header.Add("Grafana-Context", ctx)
72+
}
73+
74+
return &httputil.ReverseProxy{Director: director}
75+
}

pkg/api/app_settings.go

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
package api
2+
3+
import (
4+
"github.com/grafana/grafana/pkg/api/dtos"
5+
"github.com/grafana/grafana/pkg/bus"
6+
"github.com/grafana/grafana/pkg/middleware"
7+
m "github.com/grafana/grafana/pkg/models"
8+
"github.com/grafana/grafana/pkg/plugins"
9+
)
10+
11+
func GetOrgAppsList(c *middleware.Context) Response {
12+
orgApps, err := plugins.GetOrgAppSettings(c.OrgId)
13+
14+
if err != nil {
15+
return ApiError(500, "Failed to list of apps", err)
16+
}
17+
18+
result := make([]*dtos.AppSettings, 0)
19+
for _, app := range plugins.Apps {
20+
orgApp := orgApps[app.Id]
21+
result = append(result, dtos.NewAppSettingsDto(app, orgApp))
22+
}
23+
24+
return Json(200, result)
25+
}
26+
27+
func GetAppSettingsById(c *middleware.Context) Response {
28+
appId := c.Params(":appId")
29+
30+
if pluginDef, exists := plugins.Apps[appId]; !exists {
31+
return ApiError(404, "PluginId not found, no installed plugin with that id", nil)
32+
} else {
33+
orgApps, err := plugins.GetOrgAppSettings(c.OrgId)
34+
if err != nil {
35+
return ApiError(500, "Failed to get org app settings ", nil)
36+
}
37+
orgApp := orgApps[appId]
38+
39+
return Json(200, dtos.NewAppSettingsDto(pluginDef, orgApp))
40+
}
41+
}
42+
43+
func UpdateAppSettings(c *middleware.Context, cmd m.UpdateAppSettingsCmd) Response {
44+
appId := c.Params(":appId")
45+
46+
cmd.OrgId = c.OrgId
47+
cmd.AppId = appId
48+
49+
if _, ok := plugins.Apps[cmd.AppId]; !ok {
50+
return ApiError(404, "App type not installed.", nil)
51+
}
52+
53+
err := bus.Dispatch(&cmd)
54+
if err != nil {
55+
return ApiError(500, "Failed to update App Plugin", err)
56+
}
57+
58+
return ApiSuccess("App updated")
59+
}

pkg/api/datasources.go

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package api
33
import (
44
"github.com/grafana/grafana/pkg/api/dtos"
55
"github.com/grafana/grafana/pkg/bus"
6+
//"github.com/grafana/grafana/pkg/log"
67
"github.com/grafana/grafana/pkg/middleware"
78
m "github.com/grafana/grafana/pkg/models"
89
"github.com/grafana/grafana/pkg/plugins"
@@ -115,13 +116,19 @@ func UpdateDataSource(c *middleware.Context, cmd m.UpdateDataSourceCommand) {
115116
}
116117

117118
func GetDataSourcePlugins(c *middleware.Context) {
118-
dsList := make(map[string]interface{})
119+
dsList := make(map[string]*plugins.DataSourcePlugin)
119120

120-
for key, value := range plugins.DataSources {
121-
if !value.BuiltIn {
122-
dsList[key] = value
121+
if enabledPlugins, err := plugins.GetEnabledPlugins(c.OrgId); err != nil {
122+
c.JsonApiErr(500, "Failed to get org apps", err)
123+
return
124+
} else {
125+
126+
for key, value := range enabledPlugins.DataSources {
127+
if !value.BuiltIn {
128+
dsList[key] = value
129+
}
123130
}
124-
}
125131

126-
c.JSON(200, dsList)
132+
c.JSON(200, dsList)
133+
}
127134
}

pkg/api/dtos/apps.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package dtos
2+
3+
import (
4+
"github.com/grafana/grafana/pkg/models"
5+
"github.com/grafana/grafana/pkg/plugins"
6+
)
7+
8+
type AppSettings struct {
9+
Name string `json:"name"`
10+
AppId string `json:"appId"`
11+
Enabled bool `json:"enabled"`
12+
Pinned bool `json:"pinned"`
13+
Info *plugins.PluginInfo `json:"info"`
14+
Pages []*plugins.AppPluginPage `json:"pages"`
15+
JsonData map[string]interface{} `json:"jsonData"`
16+
}
17+
18+
func NewAppSettingsDto(def *plugins.AppPlugin, data *models.AppSettings) *AppSettings {
19+
dto := &AppSettings{
20+
AppId: def.Id,
21+
Name: def.Name,
22+
Info: &def.Info,
23+
Pages: def.Pages,
24+
}
25+
26+
if data != nil {
27+
dto.Enabled = data.Enabled
28+
dto.Pinned = data.Pinned
29+
dto.Info = &def.Info
30+
}
31+
32+
return dto
33+
}

pkg/api/dtos/index.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@ type IndexViewData struct {
88
GoogleAnalyticsId string
99
GoogleTagManagerId string
1010

11-
PluginCss []*PluginCss
12-
PluginJs []string
13-
MainNavLinks []*NavLink
11+
PluginCss []*PluginCss
12+
PluginModules []string
13+
MainNavLinks []*NavLink
1414
}
1515

1616
type PluginCss struct {
@@ -21,5 +21,6 @@ type PluginCss struct {
2121
type NavLink struct {
2222
Text string `json:"text"`
2323
Icon string `json:"icon"`
24-
Href string `json:"href"`
24+
Img string `json:"img"`
25+
Url string `json:"url"`
2526
}

pkg/api/dtos/plugin_bundle.go

Lines changed: 0 additions & 8 deletions
This file was deleted.

pkg/api/frontendsettings.go

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,11 @@ func getFrontendSettingsMap(c *middleware.Context) (map[string]interface{}, erro
2929
datasources := make(map[string]interface{})
3030
var defaultDatasource string
3131

32+
enabledPlugins, err := plugins.GetEnabledPlugins(c.OrgId)
33+
if err != nil {
34+
return nil, err
35+
}
36+
3237
for _, ds := range orgDataSources {
3338
url := ds.Url
3439

@@ -42,7 +47,7 @@ func getFrontendSettingsMap(c *middleware.Context) (map[string]interface{}, erro
4247
"url": url,
4348
}
4449

45-
meta, exists := plugins.DataSources[ds.Type]
50+
meta, exists := enabledPlugins.DataSources[ds.Type]
4651
if !exists {
4752
log.Error(3, "Could not find plugin definition for data source: %v", ds.Type)
4853
continue
@@ -110,8 +115,8 @@ func getFrontendSettingsMap(c *middleware.Context) (map[string]interface{}, erro
110115
}
111116

112117
panels := map[string]interface{}{}
113-
for _, panel := range plugins.Panels {
114-
panels[panel.Type] = map[string]interface{}{
118+
for _, panel := range enabledPlugins.Panels {
119+
panels[panel.Id] = map[string]interface{}{
115120
"module": panel.Module,
116121
"name": panel.Name,
117122
}

pkg/api/index.go

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"github.com/grafana/grafana/pkg/api/dtos"
55
"github.com/grafana/grafana/pkg/middleware"
66
m "github.com/grafana/grafana/pkg/models"
7+
"github.com/grafana/grafana/pkg/plugins"
78
"github.com/grafana/grafana/pkg/setting"
89
)
910

@@ -50,7 +51,7 @@ func setIndexViewData(c *middleware.Context) (*dtos.IndexViewData, error) {
5051
data.MainNavLinks = append(data.MainNavLinks, &dtos.NavLink{
5152
Text: "Dashboards",
5253
Icon: "fa fa-fw fa-th-large",
53-
Href: "/",
54+
Url: "/",
5455
})
5556

5657
data.MainNavLinks = append(data.MainNavLinks, &dtos.NavLink{
@@ -63,8 +64,37 @@ func setIndexViewData(c *middleware.Context) (*dtos.IndexViewData, error) {
6364
data.MainNavLinks = append(data.MainNavLinks, &dtos.NavLink{
6465
Text: "Data Sources",
6566
Icon: "fa fa-fw fa-database",
66-
Href: "/datasources",
67+
Url: "/datasources",
6768
})
69+
70+
data.MainNavLinks = append(data.MainNavLinks, &dtos.NavLink{
71+
Text: "Apps",
72+
Icon: "fa fa-fw fa-cubes",
73+
Url: "/apps",
74+
})
75+
}
76+
77+
enabledPlugins, err := plugins.GetEnabledPlugins(c.OrgId)
78+
if err != nil {
79+
return nil, err
80+
}
81+
82+
for _, plugin := range enabledPlugins.Apps {
83+
if plugin.Module != "" {
84+
data.PluginModules = append(data.PluginModules, plugin.Module)
85+
}
86+
87+
if plugin.Css != nil {
88+
data.PluginCss = append(data.PluginCss, &dtos.PluginCss{Light: plugin.Css.Light, Dark: plugin.Css.Dark})
89+
}
90+
91+
if plugin.Pinned {
92+
data.MainNavLinks = append(data.MainNavLinks, &dtos.NavLink{
93+
Text: plugin.Name,
94+
Url: "/apps/edit/" + plugin.Id,
95+
Img: plugin.Info.Logos.Small,
96+
})
97+
}
6898
}
6999

70100
return &data, nil

pkg/cmd/web.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,9 @@ func newMacaron() *macaron.Macaron {
3030
}
3131

3232
for _, route := range plugins.StaticRoutes {
33-
pluginRoute := path.Join("/public/plugins/", route.Url)
34-
log.Info("Plugin: Adding static route %s -> %s", pluginRoute, route.Path)
35-
mapStatic(m, route.Path, "", pluginRoute)
33+
pluginRoute := path.Join("/public/plugins/", route.PluginId)
34+
log.Info("Plugin: Adding static route %s -> %s", pluginRoute, route.Directory)
35+
mapStatic(m, route.Directory, "", pluginRoute)
3636
}
3737

3838
mapStatic(m, setting.StaticRootPath, "", "public")

pkg/middleware/middleware.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,3 +253,7 @@ func (ctx *Context) JsonApiErr(status int, message string, err error) {
253253

254254
ctx.JSON(status, resp)
255255
}
256+
257+
func (ctx *Context) HasUserRole(role m.RoleType) bool {
258+
return ctx.OrgRole.Includes(role)
259+
}

0 commit comments

Comments
 (0)