mirror of https://github.com/grafana/grafana
InfluxDB now works in proxy mode, influxdb username and password is added in the backend and never exposed to frontend, #8
parent
27b11b1d79
commit
164d11c816
@ -0,0 +1,123 @@ |
|||||||
|
package api |
||||||
|
|
||||||
|
import ( |
||||||
|
"github.com/torkelo/grafana-pro/pkg/bus" |
||||||
|
"github.com/torkelo/grafana-pro/pkg/middleware" |
||||||
|
m "github.com/torkelo/grafana-pro/pkg/models" |
||||||
|
"github.com/torkelo/grafana-pro/pkg/utils" |
||||||
|
) |
||||||
|
|
||||||
|
func GetAccount(c *middleware.Context) { |
||||||
|
query := m.GetAccountInfoQuery{Id: c.UserAccount.Id} |
||||||
|
err := bus.Dispatch(&query) |
||||||
|
|
||||||
|
if err != nil { |
||||||
|
c.JsonApiErr(500, "Failed to fetch collaboratos", err) |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
c.JSON(200, query.Result) |
||||||
|
} |
||||||
|
|
||||||
|
func AddCollaborator(c *middleware.Context) { |
||||||
|
var cmd m.AddCollaboratorCommand |
||||||
|
|
||||||
|
if !c.JsonBody(&cmd) { |
||||||
|
c.JsonApiErr(400, "Invalid request", nil) |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
userQuery := m.GetAccountByLoginQuery{Login: cmd.Email} |
||||||
|
err := bus.Dispatch(&userQuery) |
||||||
|
if err != nil { |
||||||
|
c.JsonApiErr(404, "Collaborator not found", nil) |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
accountToAdd := userQuery.Result |
||||||
|
|
||||||
|
if accountToAdd.Id == c.UserAccount.Id { |
||||||
|
c.JsonApiErr(400, "Cannot add yourself as collaborator", nil) |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
cmd.AccountId = accountToAdd.Id |
||||||
|
cmd.ForAccountId = c.UserAccount.Id |
||||||
|
cmd.Role = m.ROLE_READ_WRITE |
||||||
|
|
||||||
|
err = bus.Dispatch(&cmd) |
||||||
|
if err != nil { |
||||||
|
c.JsonApiErr(500, "Could not add collaborator", err) |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
c.JsonOK("Collaborator added") |
||||||
|
} |
||||||
|
|
||||||
|
func GetOtherAccounts(c *middleware.Context) { |
||||||
|
query := m.GetOtherAccountsQuery{AccountId: c.UserAccount.Id} |
||||||
|
err := bus.Dispatch(&query) |
||||||
|
|
||||||
|
if err != nil { |
||||||
|
c.JSON(500, utils.DynMap{"message": err.Error()}) |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
result := append(query.Result, &m.OtherAccountDTO{ |
||||||
|
Id: c.UserAccount.Id, |
||||||
|
Role: "owner", |
||||||
|
Email: c.UserAccount.Email, |
||||||
|
}) |
||||||
|
|
||||||
|
for _, ac := range result { |
||||||
|
if ac.Id == c.UserAccount.UsingAccountId { |
||||||
|
ac.IsUsing = true |
||||||
|
break |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
c.JSON(200, result) |
||||||
|
} |
||||||
|
|
||||||
|
func validateUsingAccount(accountId int64, otherId int64) bool { |
||||||
|
if accountId == otherId { |
||||||
|
return true |
||||||
|
} |
||||||
|
|
||||||
|
query := m.GetOtherAccountsQuery{AccountId: accountId} |
||||||
|
err := bus.Dispatch(&query) |
||||||
|
if err != nil { |
||||||
|
return false |
||||||
|
} |
||||||
|
|
||||||
|
// validate that the account id in the list
|
||||||
|
valid := false |
||||||
|
for _, other := range query.Result { |
||||||
|
if other.Id == otherId { |
||||||
|
valid = true |
||||||
|
} |
||||||
|
} |
||||||
|
return valid |
||||||
|
} |
||||||
|
|
||||||
|
func SetUsingAccount(c *middleware.Context) { |
||||||
|
usingAccountId := c.ParamsInt64(":id") |
||||||
|
|
||||||
|
if !validateUsingAccount(c.UserAccount.Id, usingAccountId) { |
||||||
|
c.JsonApiErr(401, "Not a valid account", nil) |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
cmd := m.SetUsingAccountCommand{ |
||||||
|
AccountId: c.UserAccount.Id, |
||||||
|
UsingAccountId: usingAccountId, |
||||||
|
} |
||||||
|
|
||||||
|
err := bus.Dispatch(&cmd) |
||||||
|
if err != nil { |
||||||
|
c.JsonApiErr(500, "Failed to update account", err) |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
c.JsonOK("Active account changed") |
||||||
|
} |
||||||
@ -0,0 +1,73 @@ |
|||||||
|
package api |
||||||
|
|
||||||
|
import ( |
||||||
|
"github.com/torkelo/grafana-pro/pkg/bus" |
||||||
|
"github.com/torkelo/grafana-pro/pkg/middleware" |
||||||
|
m "github.com/torkelo/grafana-pro/pkg/models" |
||||||
|
"github.com/torkelo/grafana-pro/pkg/utils" |
||||||
|
) |
||||||
|
|
||||||
|
func GetDashboard(c *middleware.Context) { |
||||||
|
slug := c.Params(":slug") |
||||||
|
|
||||||
|
dash, err := m.GetDashboard(slug, c.GetAccountId()) |
||||||
|
if err != nil { |
||||||
|
c.JsonApiErr(404, "Dashboard not found", nil) |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
dash.Data["id"] = dash.Id |
||||||
|
|
||||||
|
c.JSON(200, dash.Data) |
||||||
|
} |
||||||
|
|
||||||
|
func DeleteDashboard(c *middleware.Context) { |
||||||
|
slug := c.Params(":slug") |
||||||
|
|
||||||
|
dash, err := m.GetDashboard(slug, c.GetAccountId()) |
||||||
|
if err != nil { |
||||||
|
c.JsonApiErr(404, "Dashboard not found", nil) |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
err = m.DeleteDashboard(slug, c.GetAccountId()) |
||||||
|
if err != nil { |
||||||
|
c.JsonApiErr(500, "Failed to delete dashboard", err) |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
var resp = map[string]interface{}{"title": dash.Title} |
||||||
|
|
||||||
|
c.JSON(200, resp) |
||||||
|
} |
||||||
|
|
||||||
|
func Search(c *middleware.Context) { |
||||||
|
query := c.Query("q") |
||||||
|
|
||||||
|
results, err := m.SearchQuery(query, c.GetAccountId()) |
||||||
|
if err != nil { |
||||||
|
c.JsonApiErr(500, "Search failed", err) |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
c.JSON(200, results) |
||||||
|
} |
||||||
|
|
||||||
|
func PostDashboard(c *middleware.Context) { |
||||||
|
var cmd m.SaveDashboardCommand |
||||||
|
|
||||||
|
if !c.JsonBody(&cmd) { |
||||||
|
c.JsonApiErr(400, "bad request", nil) |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
cmd.AccountId = c.GetAccountId() |
||||||
|
|
||||||
|
err := bus.Dispatch(&cmd) |
||||||
|
if err != nil { |
||||||
|
c.JsonApiErr(500, "Failed to save dashboard", err) |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
c.JSON(200, utils.DynMap{"status": "success", "slug": cmd.Result.Slug}) |
||||||
|
} |
||||||
@ -0,0 +1,53 @@ |
|||||||
|
package api |
||||||
|
|
||||||
|
import ( |
||||||
|
"net/http" |
||||||
|
"net/http/httputil" |
||||||
|
"net/url" |
||||||
|
|
||||||
|
"github.com/torkelo/grafana-pro/pkg/bus" |
||||||
|
"github.com/torkelo/grafana-pro/pkg/middleware" |
||||||
|
m "github.com/torkelo/grafana-pro/pkg/models" |
||||||
|
"github.com/torkelo/grafana-pro/pkg/utils" |
||||||
|
) |
||||||
|
|
||||||
|
func NewReverseProxy(ds *m.DataSource, proxyPath string) *httputil.ReverseProxy { |
||||||
|
target, _ := url.Parse(ds.Url) |
||||||
|
|
||||||
|
director := func(req *http.Request) { |
||||||
|
req.URL.Scheme = target.Scheme |
||||||
|
req.URL.Host = target.Host |
||||||
|
|
||||||
|
reqQueryVals := req.URL.Query() |
||||||
|
|
||||||
|
if ds.Type == m.DS_INFLUXDB { |
||||||
|
req.URL.Path = utils.JoinUrlFragments(target.Path, "db/"+ds.Database+"/"+proxyPath) |
||||||
|
reqQueryVals.Add("u", ds.User) |
||||||
|
reqQueryVals.Add("p", ds.Password) |
||||||
|
req.URL.RawQuery = reqQueryVals.Encode() |
||||||
|
} else { |
||||||
|
req.URL.Path = utils.JoinUrlFragments(target.Path, proxyPath) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return &httputil.ReverseProxy{Director: director} |
||||||
|
} |
||||||
|
|
||||||
|
// TODO: need to cache datasources
|
||||||
|
func ProxyDataSourceRequest(c *middleware.Context) { |
||||||
|
id := c.ParamsInt64(":id") |
||||||
|
|
||||||
|
query := m.GetDataSourceByIdQuery{ |
||||||
|
Id: id, |
||||||
|
AccountId: c.GetAccountId(), |
||||||
|
} |
||||||
|
|
||||||
|
err := bus.Dispatch(&query) |
||||||
|
if err != nil { |
||||||
|
c.JsonApiErr(500, "Unable to load datasource meta data", err) |
||||||
|
} |
||||||
|
|
||||||
|
proxyPath := c.Params("*") |
||||||
|
proxy := NewReverseProxy(&query.Result, proxyPath) |
||||||
|
proxy.ServeHTTP(c.RW(), c.Req.Request) |
||||||
|
} |
||||||
@ -0,0 +1,58 @@ |
|||||||
|
package api |
||||||
|
|
||||||
|
import ( |
||||||
|
"net/http" |
||||||
|
"net/url" |
||||||
|
"testing" |
||||||
|
|
||||||
|
. "github.com/smartystreets/goconvey/convey" |
||||||
|
|
||||||
|
m "github.com/torkelo/grafana-pro/pkg/models" |
||||||
|
) |
||||||
|
|
||||||
|
func TestAccountDataAccess(t *testing.T) { |
||||||
|
|
||||||
|
Convey("When getting graphite datasource proxy", t, func() { |
||||||
|
ds := m.DataSource{Url: "htttp://graphite:8080", Type: m.DS_GRAPHITE} |
||||||
|
proxy := NewReverseProxy(&ds, "/render") |
||||||
|
|
||||||
|
requestUrl, _ := url.Parse("http://grafana.com/sub") |
||||||
|
req := http.Request{URL: requestUrl} |
||||||
|
|
||||||
|
proxy.Director(&req) |
||||||
|
|
||||||
|
Convey("Can translate request url and path", func() { |
||||||
|
So(req.URL.Host, ShouldEqual, "graphite:8080") |
||||||
|
So(req.URL.Path, ShouldEqual, "/render") |
||||||
|
}) |
||||||
|
}) |
||||||
|
|
||||||
|
Convey("When getting influxdb datasource proxy", t, func() { |
||||||
|
ds := m.DataSource{ |
||||||
|
Type: m.DS_INFLUXDB, |
||||||
|
Url: "http://influxdb:8083", |
||||||
|
Database: "site", |
||||||
|
User: "user", |
||||||
|
Password: "password", |
||||||
|
} |
||||||
|
|
||||||
|
proxy := NewReverseProxy(&ds, "") |
||||||
|
|
||||||
|
requestUrl, _ := url.Parse("http://grafana.com/sub") |
||||||
|
req := http.Request{URL: requestUrl} |
||||||
|
|
||||||
|
proxy.Director(&req) |
||||||
|
|
||||||
|
Convey("Should add db to url", func() { |
||||||
|
So(req.URL.Path, ShouldEqual, "/db/site/") |
||||||
|
}) |
||||||
|
|
||||||
|
Convey("Should add username and password", func() { |
||||||
|
queryVals := req.URL.Query() |
||||||
|
So(queryVals["u"][0], ShouldEqual, "user") |
||||||
|
So(queryVals["p"][0], ShouldEqual, "password") |
||||||
|
}) |
||||||
|
|
||||||
|
}) |
||||||
|
|
||||||
|
} |
||||||
@ -0,0 +1,93 @@ |
|||||||
|
package api |
||||||
|
|
||||||
|
import ( |
||||||
|
"github.com/torkelo/grafana-pro/pkg/api/dtos" |
||||||
|
"github.com/torkelo/grafana-pro/pkg/bus" |
||||||
|
"github.com/torkelo/grafana-pro/pkg/middleware" |
||||||
|
m "github.com/torkelo/grafana-pro/pkg/models" |
||||||
|
) |
||||||
|
|
||||||
|
func GetDataSources(c *middleware.Context) { |
||||||
|
query := m.GetDataSourcesQuery{AccountId: c.Account.Id} |
||||||
|
err := bus.Dispatch(&query) |
||||||
|
|
||||||
|
if err != nil { |
||||||
|
c.JsonApiErr(500, "Failed to query datasources", err) |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
result := make([]*dtos.DataSource, len(query.Result)) |
||||||
|
for i, ds := range query.Result { |
||||||
|
result[i] = &dtos.DataSource{ |
||||||
|
Id: ds.Id, |
||||||
|
AccountId: ds.AccountId, |
||||||
|
Name: ds.Name, |
||||||
|
Url: ds.Url, |
||||||
|
Type: ds.Type, |
||||||
|
Access: ds.Access, |
||||||
|
Password: ds.Password, |
||||||
|
Database: ds.Database, |
||||||
|
User: ds.User, |
||||||
|
BasicAuth: ds.BasicAuth, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
c.JSON(200, result) |
||||||
|
} |
||||||
|
|
||||||
|
func DeleteDataSource(c *middleware.Context) { |
||||||
|
id := c.ParamsInt64(":id") |
||||||
|
|
||||||
|
if id <= 0 { |
||||||
|
c.JsonApiErr(400, "Missing valid datasource id", nil) |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
cmd := &m.DeleteDataSourceCommand{Id: id, AccountId: c.UserAccount.Id} |
||||||
|
|
||||||
|
err := bus.Dispatch(cmd) |
||||||
|
if err != nil { |
||||||
|
c.JsonApiErr(500, "Failed to delete datasource", err) |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
c.JsonOK("Data source deleted") |
||||||
|
} |
||||||
|
|
||||||
|
func AddDataSource(c *middleware.Context) { |
||||||
|
cmd := m.AddDataSourceCommand{} |
||||||
|
|
||||||
|
if !c.JsonBody(&cmd) { |
||||||
|
c.JsonApiErr(400, "Validation failed", nil) |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
cmd.AccountId = c.Account.Id |
||||||
|
|
||||||
|
err := bus.Dispatch(&cmd) |
||||||
|
if err != nil { |
||||||
|
c.JsonApiErr(500, "Failed to add datasource", err) |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
c.JsonOK("Datasource added") |
||||||
|
} |
||||||
|
|
||||||
|
func UpdateDataSource(c *middleware.Context) { |
||||||
|
cmd := m.UpdateDataSourceCommand{} |
||||||
|
|
||||||
|
if !c.JsonBody(&cmd) { |
||||||
|
c.JsonApiErr(400, "Validation failed", nil) |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
cmd.AccountId = c.Account.Id |
||||||
|
|
||||||
|
err := bus.Dispatch(&cmd) |
||||||
|
if err != nil { |
||||||
|
c.JsonApiErr(500, "Failed to update datasource", err) |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
c.JsonOK("Datasource updated") |
||||||
|
} |
||||||
@ -0,0 +1,68 @@ |
|||||||
|
package api |
||||||
|
|
||||||
|
import ( |
||||||
|
"strconv" |
||||||
|
|
||||||
|
"github.com/torkelo/grafana-pro/pkg/bus" |
||||||
|
"github.com/torkelo/grafana-pro/pkg/middleware" |
||||||
|
m "github.com/torkelo/grafana-pro/pkg/models" |
||||||
|
) |
||||||
|
|
||||||
|
func getFrontendSettings(c *middleware.Context) (map[string]interface{}, error) { |
||||||
|
accountDataSources := make([]*m.DataSource, 0) |
||||||
|
|
||||||
|
if c.Account != nil { |
||||||
|
query := m.GetDataSourcesQuery{AccountId: c.Account.Id} |
||||||
|
err := bus.Dispatch(&query) |
||||||
|
|
||||||
|
if err != nil { |
||||||
|
return nil, err |
||||||
|
} |
||||||
|
|
||||||
|
accountDataSources = query.Result |
||||||
|
} |
||||||
|
|
||||||
|
datasources := make(map[string]interface{}) |
||||||
|
|
||||||
|
for i, ds := range accountDataSources { |
||||||
|
url := ds.Url |
||||||
|
|
||||||
|
if ds.Access == m.DS_ACCESS_PROXY { |
||||||
|
url = "/api/datasources/proxy/" + strconv.FormatInt(ds.Id, 10) |
||||||
|
} |
||||||
|
|
||||||
|
var dsMap = map[string]interface{}{ |
||||||
|
"type": ds.Type, |
||||||
|
"url": url, |
||||||
|
} |
||||||
|
|
||||||
|
if ds.Type == m.DS_INFLUXDB { |
||||||
|
if ds.Access == m.DS_ACCESS_DIRECT { |
||||||
|
dsMap["username"] = ds.User |
||||||
|
dsMap["password"] = ds.Password |
||||||
|
dsMap["url"] = url + "/db/" + ds.Database |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// temp hack, first is always default
|
||||||
|
// TODO: implement default ds account setting
|
||||||
|
if i == 0 { |
||||||
|
dsMap["default"] = true |
||||||
|
} |
||||||
|
|
||||||
|
datasources[ds.Name] = dsMap |
||||||
|
} |
||||||
|
|
||||||
|
// add grafana backend data source
|
||||||
|
datasources["grafana"] = map[string]interface{}{ |
||||||
|
"type": "grafana", |
||||||
|
"url": "", |
||||||
|
"grafanaDB": true, |
||||||
|
} |
||||||
|
|
||||||
|
jsonObj := map[string]interface{}{ |
||||||
|
"datasources": datasources, |
||||||
|
} |
||||||
|
|
||||||
|
return jsonObj, nil |
||||||
|
} |
||||||
@ -0,0 +1,61 @@ |
|||||||
|
package api |
||||||
|
|
||||||
|
import ( |
||||||
|
"github.com/torkelo/grafana-pro/pkg/api/dtos" |
||||||
|
"github.com/torkelo/grafana-pro/pkg/bus" |
||||||
|
"github.com/torkelo/grafana-pro/pkg/log" |
||||||
|
"github.com/torkelo/grafana-pro/pkg/middleware" |
||||||
|
m "github.com/torkelo/grafana-pro/pkg/models" |
||||||
|
"github.com/torkelo/grafana-pro/pkg/utils" |
||||||
|
) |
||||||
|
|
||||||
|
type loginJsonModel struct { |
||||||
|
Email string `json:"email" binding:"required"` |
||||||
|
Password string `json:"password" binding:"required"` |
||||||
|
Remember bool `json:"remember"` |
||||||
|
} |
||||||
|
|
||||||
|
func LoginPost(c *middleware.Context) { |
||||||
|
var loginModel loginJsonModel |
||||||
|
|
||||||
|
if !c.JsonBody(&loginModel) { |
||||||
|
c.JSON(400, utils.DynMap{"status": "bad request"}) |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
userQuery := m.GetAccountByLoginQuery{Login: loginModel.Email} |
||||||
|
err := bus.Dispatch(&userQuery) |
||||||
|
|
||||||
|
if err != nil { |
||||||
|
c.JsonApiErr(401, "Invalid username or password", err) |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
account := userQuery.Result |
||||||
|
|
||||||
|
if loginModel.Password != account.Password { |
||||||
|
c.JsonApiErr(401, "Invalid username or password", err) |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
loginUserWithAccount(account, c) |
||||||
|
|
||||||
|
var resp = &dtos.LoginResult{} |
||||||
|
resp.Status = "Logged in" |
||||||
|
resp.User.Login = account.Login |
||||||
|
|
||||||
|
c.JSON(200, resp) |
||||||
|
} |
||||||
|
|
||||||
|
func loginUserWithAccount(account *m.Account, c *middleware.Context) { |
||||||
|
if account == nil { |
||||||
|
log.Error(3, "Account login with nil account") |
||||||
|
} |
||||||
|
|
||||||
|
c.Session.Set("accountId", account.Id) |
||||||
|
} |
||||||
|
|
||||||
|
func LogoutPost(c *middleware.Context) { |
||||||
|
c.Session.Delete("accountId") |
||||||
|
c.JSON(200, utils.DynMap{"status": "logged out"}) |
||||||
|
} |
||||||
@ -0,0 +1,78 @@ |
|||||||
|
package api |
||||||
|
|
||||||
|
import ( |
||||||
|
"errors" |
||||||
|
"fmt" |
||||||
|
|
||||||
|
"github.com/torkelo/grafana-pro/pkg/bus" |
||||||
|
"github.com/torkelo/grafana-pro/pkg/log" |
||||||
|
"github.com/torkelo/grafana-pro/pkg/middleware" |
||||||
|
m "github.com/torkelo/grafana-pro/pkg/models" |
||||||
|
"github.com/torkelo/grafana-pro/pkg/setting" |
||||||
|
"github.com/torkelo/grafana-pro/pkg/social" |
||||||
|
) |
||||||
|
|
||||||
|
func OAuthLogin(ctx *middleware.Context) { |
||||||
|
if setting.OAuthService == nil { |
||||||
|
ctx.Handle(404, "login.OAuthLogin(oauth service not enabled)", nil) |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
name := ctx.Params(":name") |
||||||
|
connect, ok := social.SocialMap[name] |
||||||
|
if !ok { |
||||||
|
ctx.Handle(404, "login.OAuthLogin(social login not enabled)", errors.New(name)) |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
code := ctx.Query("code") |
||||||
|
if code == "" { |
||||||
|
ctx.Redirect(connect.AuthCodeURL("", "online", "auto")) |
||||||
|
return |
||||||
|
} |
||||||
|
log.Info("code: %v", code) |
||||||
|
|
||||||
|
// handle call back
|
||||||
|
transport, err := connect.NewTransportFromCode(code) |
||||||
|
if err != nil { |
||||||
|
ctx.Handle(500, "login.OAuthLogin(NewTransportWithCode)", err) |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
log.Trace("login.OAuthLogin(Got token)") |
||||||
|
|
||||||
|
userInfo, err := connect.UserInfo(transport) |
||||||
|
if err != nil { |
||||||
|
ctx.Handle(500, fmt.Sprintf("login.OAuthLogin(get info from %s)", name), err) |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
log.Info("login.OAuthLogin(social login): %s", userInfo) |
||||||
|
|
||||||
|
userQuery := m.GetAccountByLoginQuery{Login: userInfo.Email} |
||||||
|
err = bus.Dispatch(&userQuery) |
||||||
|
|
||||||
|
// create account if missing
|
||||||
|
if err == m.ErrAccountNotFound { |
||||||
|
cmd := &m.CreateAccountCommand{ |
||||||
|
Login: userInfo.Email, |
||||||
|
Email: userInfo.Email, |
||||||
|
Name: userInfo.Name, |
||||||
|
Company: userInfo.Company, |
||||||
|
} |
||||||
|
|
||||||
|
if err = bus.Dispatch(&cmd); err != nil { |
||||||
|
ctx.Handle(500, "Failed to create account", err) |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
userQuery.Result = &cmd.Result |
||||||
|
} else if err != nil { |
||||||
|
ctx.Handle(500, "Unexpected error", err) |
||||||
|
} |
||||||
|
|
||||||
|
// login
|
||||||
|
loginUserWithAccount(userQuery.Result, ctx) |
||||||
|
|
||||||
|
ctx.Redirect("/") |
||||||
|
} |
||||||
@ -0,0 +1,26 @@ |
|||||||
|
package api |
||||||
|
|
||||||
|
import ( |
||||||
|
"github.com/torkelo/grafana-pro/pkg/bus" |
||||||
|
"github.com/torkelo/grafana-pro/pkg/middleware" |
||||||
|
m "github.com/torkelo/grafana-pro/pkg/models" |
||||||
|
) |
||||||
|
|
||||||
|
func CreateAccount(c *middleware.Context) { |
||||||
|
var cmd m.CreateAccountCommand |
||||||
|
|
||||||
|
if !c.JsonBody(&cmd) { |
||||||
|
c.JsonApiErr(400, "Validation error", nil) |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
cmd.Login = cmd.Email |
||||||
|
err := bus.Dispatch(&cmd) |
||||||
|
|
||||||
|
if err != nil { |
||||||
|
c.JsonApiErr(500, "failed to create account", err) |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
c.JsonOK("Account created") |
||||||
|
} |
||||||
@ -0,0 +1,32 @@ |
|||||||
|
package api |
||||||
|
|
||||||
|
import ( |
||||||
|
"net/http" |
||||||
|
"strconv" |
||||||
|
|
||||||
|
"github.com/torkelo/grafana-pro/pkg/components/renderer" |
||||||
|
"github.com/torkelo/grafana-pro/pkg/middleware" |
||||||
|
"github.com/torkelo/grafana-pro/pkg/utils" |
||||||
|
) |
||||||
|
|
||||||
|
func RenderToPng(c *middleware.Context) { |
||||||
|
accountId := c.GetAccountId() |
||||||
|
queryReader := utils.NewUrlQueryReader(c.Req.URL) |
||||||
|
queryParams := "?render&accountId=" + strconv.FormatInt(accountId, 10) + "&" + c.Req.URL.RawQuery |
||||||
|
|
||||||
|
renderOpts := &renderer.RenderOpts{ |
||||||
|
Url: c.Params("*") + queryParams, |
||||||
|
Width: queryReader.Get("width", "800"), |
||||||
|
Height: queryReader.Get("height", "400"), |
||||||
|
} |
||||||
|
|
||||||
|
renderOpts.Url = "http://localhost:3000/" + renderOpts.Url |
||||||
|
|
||||||
|
pngPath, err := renderer.RenderToPng(renderOpts) |
||||||
|
if err != nil { |
||||||
|
c.HTML(500, "error.html", nil) |
||||||
|
} |
||||||
|
|
||||||
|
c.Resp.Header().Set("Content-Type", "image/png") |
||||||
|
http.ServeFile(c.Resp, c.Req.Request, pngPath) |
||||||
|
} |
||||||
Loading…
Reference in new issue