moved all http route handling into single package named api

This commit is contained in:
Torkel Ödegaard
2014-12-15 21:25:02 +01:00
parent 1663cbbb34
commit 973b9cad36
11 changed files with 56 additions and 58 deletions
+49
View File
@@ -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)
}
+115
View File
@@ -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)
// }
+91
View File
@@ -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})
}
+56
View File
@@ -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"})
}
+74
View File
@@ -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("/")
}
+38
View File
@@ -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(&registerModel) {
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"})
}
+32
View File
@@ -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)
}
+11
View File
@@ -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"`
}
+55
View File
@@ -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))
}