moved all http route handling into single package named api
This commit is contained in:
@@ -0,0 +1,49 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"github.com/Unknwon/macaron"
|
||||
"github.com/torkelo/grafana-pro/pkg/api/dtos"
|
||||
"github.com/torkelo/grafana-pro/pkg/middleware"
|
||||
)
|
||||
|
||||
func Register(m *macaron.Macaron) {
|
||||
auth := middleware.Auth()
|
||||
|
||||
// index
|
||||
m.Get("/", auth, Index)
|
||||
m.Post("/logout", LogoutPost)
|
||||
m.Post("/login", LoginPost)
|
||||
|
||||
// login
|
||||
m.Get("/login", Index)
|
||||
m.Get("/login/:name", OAuthLogin)
|
||||
|
||||
// account
|
||||
m.Get("/account/", auth, Index)
|
||||
m.Get("/api/account/", auth, GetAccount)
|
||||
m.Post("/api/account/collaborators/add", auth, AddCollaborator)
|
||||
m.Get("/api/account/others", auth, GetOtherAccounts)
|
||||
|
||||
// user register
|
||||
m.Get("/register/*_", Index)
|
||||
m.Post("/api/account", CreateAccount)
|
||||
|
||||
// dashboards
|
||||
m.Get("/dashboard/*", auth, Index)
|
||||
m.Get("/api/dashboards/:slug", auth, GetDashboard)
|
||||
m.Get("/api/search/", auth, Search)
|
||||
m.Post("/api/dashboard/", auth, PostDashboard)
|
||||
m.Delete("/api/dashboard/:slug", auth, DeleteDashboard)
|
||||
|
||||
// rendering
|
||||
m.Get("/render/*", auth, RenderToPng)
|
||||
}
|
||||
|
||||
func Index(ctx *middleware.Context) {
|
||||
ctx.Data["User"] = dtos.NewCurrentUser(ctx.UserAccount)
|
||||
ctx.HTML(200, "index")
|
||||
}
|
||||
|
||||
func NotFound(ctx *middleware.Context) {
|
||||
ctx.Handle(404, "index", nil)
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"github.com/torkelo/grafana-pro/pkg/api/dtos"
|
||||
"github.com/torkelo/grafana-pro/pkg/middleware"
|
||||
"github.com/torkelo/grafana-pro/pkg/models"
|
||||
"github.com/torkelo/grafana-pro/pkg/utils"
|
||||
)
|
||||
|
||||
func GetAccount(c *middleware.Context) {
|
||||
model := dtos.AccountInfo{
|
||||
Name: c.UserAccount.Name,
|
||||
Email: c.UserAccount.Email,
|
||||
}
|
||||
|
||||
collaborators, err := models.GetCollaboratorsForAccount(c.UserAccount.Id)
|
||||
if err != nil {
|
||||
c.JsonApiErr(500, "Failed to fetch collaboratos", err)
|
||||
return
|
||||
}
|
||||
|
||||
for _, collaborator := range collaborators {
|
||||
model.Collaborators = append(model.Collaborators, &dtos.Collaborator{
|
||||
AccountId: collaborator.AccountId,
|
||||
Role: collaborator.Role,
|
||||
Email: collaborator.Email,
|
||||
})
|
||||
}
|
||||
|
||||
c.JSON(200, model)
|
||||
}
|
||||
|
||||
func AddCollaborator(c *middleware.Context) {
|
||||
var model dtos.AddCollaboratorCommand
|
||||
|
||||
if !c.JsonBody(&model) {
|
||||
c.JsonApiErr(400, "Invalid request", nil)
|
||||
return
|
||||
}
|
||||
|
||||
accountToAdd, err := models.GetAccountByLogin(model.Email)
|
||||
if err != nil {
|
||||
c.JsonApiErr(404, "Collaborator not found", nil)
|
||||
return
|
||||
}
|
||||
|
||||
if accountToAdd.Id == c.UserAccount.Id {
|
||||
c.JsonApiErr(400, "Cannot add yourself as collaborator", nil)
|
||||
return
|
||||
}
|
||||
|
||||
var collaborator = models.NewCollaborator(accountToAdd.Id, c.UserAccount.Id, models.ROLE_READ_WRITE)
|
||||
|
||||
err = models.AddCollaborator(collaborator)
|
||||
if err != nil {
|
||||
c.JsonApiErr(500, "Could not add collaborator", err)
|
||||
return
|
||||
}
|
||||
|
||||
c.Status(204)
|
||||
}
|
||||
|
||||
func GetOtherAccounts(c *middleware.Context) {
|
||||
|
||||
otherAccounts, err := models.GetOtherAccountsFor(c.UserAccount.Id)
|
||||
if err != nil {
|
||||
c.JSON(500, utils.DynMap{"message": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
var result []*dtos.OtherAccount
|
||||
result = append(result, &dtos.OtherAccount{
|
||||
Id: c.UserAccount.Id,
|
||||
Role: "owner",
|
||||
IsUsing: c.UserAccount.Id == c.UserAccount.UsingAccountId,
|
||||
Name: c.UserAccount.Email,
|
||||
})
|
||||
|
||||
for _, other := range otherAccounts {
|
||||
result = append(result, &dtos.OtherAccount{
|
||||
Id: other.Id,
|
||||
Role: other.Role,
|
||||
Name: other.Email,
|
||||
IsUsing: other.Id == c.UserAccount.UsingAccountId,
|
||||
})
|
||||
}
|
||||
|
||||
c.JSON(200, result)
|
||||
}
|
||||
|
||||
// func SetUsingAccount(c *middleware.Context) {
|
||||
// idString := c.Params.ByName("id")
|
||||
// id, _ := strconv.Atoi(idString)
|
||||
//
|
||||
// account := auth.userAccount
|
||||
// otherAccount, err := self.store.GetAccount(id)
|
||||
// if err != nil {
|
||||
// c.JSON(500, gin.H{"message": err.Error()})
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// if otherAccount.Id != account.Id && !otherAccount.HasCollaborator(account.Id) {
|
||||
// c.Abort(401)
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// account.UsingAccountId = otherAccount.Id
|
||||
// err = self.store.UpdateAccount(account)
|
||||
// if err != nil {
|
||||
// c.JSON(500, gin.H{"message": err.Error()})
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// c.Abort(204)
|
||||
// }
|
||||
@@ -0,0 +1,91 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"github.com/torkelo/grafana-pro/pkg/api/dtos"
|
||||
"github.com/torkelo/grafana-pro/pkg/middleware"
|
||||
"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 := models.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 := models.GetDashboard(slug, c.GetAccountId())
|
||||
if err != nil {
|
||||
c.JsonApiErr(404, "Dashboard not found", nil)
|
||||
return
|
||||
}
|
||||
|
||||
err = models.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 := models.SearchQuery(query, c.GetAccountId())
|
||||
if err != nil {
|
||||
c.JsonApiErr(500, "Search failed", err)
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(200, results)
|
||||
}
|
||||
|
||||
func convertToStringArray(arr []interface{}) []string {
|
||||
b := make([]string, len(arr))
|
||||
for i := range arr {
|
||||
b[i] = arr[i].(string)
|
||||
}
|
||||
|
||||
return b
|
||||
}
|
||||
|
||||
func PostDashboard(c *middleware.Context) {
|
||||
var command dtos.SaveDashboardCommand
|
||||
|
||||
if !c.JsonBody(&command) {
|
||||
c.JsonApiErr(400, "bad request", nil)
|
||||
return
|
||||
}
|
||||
|
||||
dashboard := models.NewDashboard("test")
|
||||
dashboard.Data = command.Dashboard
|
||||
dashboard.Title = dashboard.Data["title"].(string)
|
||||
dashboard.AccountId = c.GetAccountId()
|
||||
dashboard.Tags = convertToStringArray(dashboard.Data["tags"].([]interface{}))
|
||||
dashboard.UpdateSlug()
|
||||
|
||||
if dashboard.Data["id"] != nil {
|
||||
dashboard.Id = int64(dashboard.Data["id"].(float64))
|
||||
}
|
||||
|
||||
err := models.SaveDashboard(dashboard)
|
||||
if err != nil {
|
||||
c.JsonApiErr(500, "Failed to save dashboard", err)
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(200, utils.DynMap{"status": "success", "slug": dashboard.Slug})
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"github.com/torkelo/grafana-pro/pkg/api/dtos"
|
||||
"github.com/torkelo/grafana-pro/pkg/log"
|
||||
"github.com/torkelo/grafana-pro/pkg/middleware"
|
||||
"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
|
||||
}
|
||||
|
||||
account, err := models.GetAccountByLogin(loginModel.Email)
|
||||
if err != nil {
|
||||
c.JSON(401, utils.DynMap{"status": "unauthorized"})
|
||||
return
|
||||
}
|
||||
|
||||
if loginModel.Password != account.Password {
|
||||
c.JSON(401, utils.DynMap{"status": "unauthorized"})
|
||||
return
|
||||
}
|
||||
|
||||
loginUserWithAccount(account, c)
|
||||
|
||||
var resp = &dtos.LoginResult{}
|
||||
resp.Status = "Logged in"
|
||||
resp.User.Login = account.Login
|
||||
|
||||
c.JSON(200, resp)
|
||||
}
|
||||
|
||||
func loginUserWithAccount(account *models.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,74 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/torkelo/grafana-pro/pkg/log"
|
||||
"github.com/torkelo/grafana-pro/pkg/middleware"
|
||||
"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)
|
||||
|
||||
account, err := models.GetAccountByLogin(userInfo.Email)
|
||||
|
||||
// create account if missing
|
||||
if err == models.ErrAccountNotFound {
|
||||
account = &models.Account{
|
||||
Login: userInfo.Email,
|
||||
Email: userInfo.Email,
|
||||
Name: userInfo.Name,
|
||||
Company: userInfo.Company,
|
||||
}
|
||||
|
||||
if err = models.CreateAccount(account); err != nil {
|
||||
ctx.Handle(500, "Failed to create account", err)
|
||||
return
|
||||
}
|
||||
} else if err != nil {
|
||||
ctx.Handle(500, "Unexpected error", err)
|
||||
}
|
||||
|
||||
// login
|
||||
loginUserWithAccount(account, ctx)
|
||||
|
||||
ctx.Redirect("/")
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"github.com/torkelo/grafana-pro/pkg/log"
|
||||
"github.com/torkelo/grafana-pro/pkg/middleware"
|
||||
"github.com/torkelo/grafana-pro/pkg/models"
|
||||
"github.com/torkelo/grafana-pro/pkg/utils"
|
||||
)
|
||||
|
||||
type registerAccountJsonModel struct {
|
||||
Email string `json:"email" binding:"required"`
|
||||
Password string `json:"password" binding:"required"`
|
||||
Password2 bool `json:"remember2"`
|
||||
}
|
||||
|
||||
func CreateAccount(c *middleware.Context) {
|
||||
var registerModel registerAccountJsonModel
|
||||
|
||||
if !c.JsonBody(®isterModel) {
|
||||
c.JSON(400, utils.DynMap{"status": "bad request"})
|
||||
return
|
||||
}
|
||||
|
||||
account := models.Account{
|
||||
Login: registerModel.Email,
|
||||
Email: registerModel.Email,
|
||||
Password: registerModel.Password,
|
||||
}
|
||||
|
||||
err := models.CreateAccount(&account)
|
||||
if err != nil {
|
||||
log.Error(2, "Failed to create user account, email: %v, error: %v", registerModel.Email, err)
|
||||
c.JSON(500, utils.DynMap{"status": "failed to create account"})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(200, utils.DynMap{"status": "ok"})
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package dtos
|
||||
|
||||
type AddCollaboratorCommand struct {
|
||||
Email string `json:"email" binding:"required"`
|
||||
}
|
||||
|
||||
type SaveDashboardCommand struct {
|
||||
Id string `json:"id"`
|
||||
Title string `json:"title"`
|
||||
Dashboard map[string]interface{} `json:"dashboard"`
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package dtos
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/torkelo/grafana-pro/pkg/models"
|
||||
)
|
||||
|
||||
type LoginResult struct {
|
||||
Status string `json:"status"`
|
||||
User CurrentUser `json:"user"`
|
||||
}
|
||||
|
||||
type CurrentUser struct {
|
||||
Login string `json:"login"`
|
||||
Email string `json:"email"`
|
||||
GravatarUrl string `json:"gravatarUrl"`
|
||||
}
|
||||
|
||||
type AccountInfo struct {
|
||||
Email string `json:"email"`
|
||||
Name string `json:"name"`
|
||||
Collaborators []*Collaborator `json:"collaborators"`
|
||||
}
|
||||
|
||||
type OtherAccount struct {
|
||||
Id int64 `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Role string `json:"role"`
|
||||
IsUsing bool `json:"isUsing"`
|
||||
}
|
||||
|
||||
type Collaborator struct {
|
||||
AccountId int64 `json:"accountId"`
|
||||
Email string `json:"email"`
|
||||
Role string `json:"role"`
|
||||
}
|
||||
|
||||
func NewCurrentUser(account *models.Account) *CurrentUser {
|
||||
model := &CurrentUser{}
|
||||
if account != nil {
|
||||
model.Login = account.Login
|
||||
model.Email = account.Email
|
||||
model.GravatarUrl = getGravatarUrl(account.Email)
|
||||
}
|
||||
return model
|
||||
}
|
||||
|
||||
func getGravatarUrl(text string) string {
|
||||
hasher := md5.New()
|
||||
hasher.Write([]byte(strings.ToLower(text)))
|
||||
return fmt.Sprintf("https://secure.gravatar.com/avatar/%x?s=90&default=mm", hasher.Sum(nil))
|
||||
}
|
||||
Reference in New Issue
Block a user