diff --git a/grafana b/grafana index 4b5eadf7b59..79beefe57c6 160000 --- a/grafana +++ b/grafana @@ -1 +1 @@ -Subproject commit 4b5eadf7b59898e6622a75e0a57081103dd78b2a +Subproject commit 79beefe57c608b3cd933c5b1f772c8707731a64c diff --git a/pkg/api/api.go b/pkg/api/api.go deleted file mode 100644 index bdc44e0c94b..00000000000 --- a/pkg/api/api.go +++ /dev/null @@ -1,84 +0,0 @@ -package api - -import ( - "fmt" - "html/template" - - "github.com/gin-gonic/gin" - "github.com/gorilla/sessions" - - "github.com/torkelo/grafana-pro/pkg/components" - "github.com/torkelo/grafana-pro/pkg/configuration" - "github.com/torkelo/grafana-pro/pkg/log" - "github.com/torkelo/grafana-pro/pkg/models" - "github.com/torkelo/grafana-pro/pkg/setting" - "github.com/torkelo/grafana-pro/pkg/stores" -) - -type HttpServer struct { - port string - shutdown chan bool - store stores.Store - renderer *components.PhantomRenderer - router *gin.Engine - cfg *configuration.Cfg -} - -var sessionStore = sessions.NewCookieStore([]byte("something-very-secret")) - -func NewHttpServer(cfg *configuration.Cfg, store stores.Store) *HttpServer { - self := &HttpServer{} - self.cfg = cfg - self.port = cfg.Http.Port - self.store = store - self.renderer = &components.PhantomRenderer{ImagesDir: "data/png", PhantomDir: "_vendor/phantomjs"} - - return self -} - -func (self *HttpServer) ListenAndServe() { - defer func() { self.shutdown <- true }() - - gin.SetMode(gin.ReleaseMode) - self.router = gin.New() - self.router.Use(gin.Recovery(), apiLogger(), CacheHeadersMiddleware()) - - self.router.Static("/public", "./public") - self.router.Static("/app", "./public/app") - self.router.Static("/img", "./public/img") - - // register & parse templates - templates := template.New("templates") - templates.Delims("[[", "]]") - templates.ParseFiles("./views/index.html") - self.router.SetHTMLTemplate(templates) - - for _, fn := range routeHandlers { - fn(self) - } - - // register default route - self.router.GET("/", self.auth(), self.index) - self.router.GET("/dashboard/*_", self.auth(), self.index) - self.router.GET("/admin/*_", self.auth(), self.index) - self.router.GET("/account/*_", self.auth(), self.index) - - listenAddr := fmt.Sprintf("%s:%s", setting.HttpAddr, setting.HttpPort) - log.Info("Listen: %v://%s%s", setting.Protocol, listenAddr, setting.AppSubUrl) - self.router.Run(listenAddr) -} - -func (self *HttpServer) index(c *gin.Context) { - viewModel := &IndexDto{} - userAccount, _ := c.Get("userAccount") - account, _ := userAccount.(*models.Account) - initCurrentUserDto(&viewModel.User, account) - - c.HTML(200, "index.html", viewModel) -} - -func CacheHeadersMiddleware() gin.HandlerFunc { - return func(c *gin.Context) { - c.Writer.Header().Add("Cache-Control", "max-age=0, public, must-revalidate, proxy-revalidate") - } -} diff --git a/pkg/api/api_account.go b/pkg/api/api_account.go deleted file mode 100644 index 28c72c3bb50..00000000000 --- a/pkg/api/api_account.go +++ /dev/null @@ -1,147 +0,0 @@ -package api - -import ( - "strconv" - - "github.com/gin-gonic/gin" -) - -func init() { - addRoutes(func(self *HttpServer) { - self.addRoute("POST", "/api/account/collaborators/add", self.addCollaborator) - self.addRoute("POST", "/api/account/collaborators/remove", self.removeCollaborator) - self.addRoute("GET", "/api/account/", self.getAccount) - self.addRoute("GET", "/api/account/others", self.getOtherAccounts) - self.addRoute("POST", "/api/account/using/:id", self.setUsingAccount) - }) -} - -func (self *HttpServer) getAccount(c *gin.Context, auth *authContext) { - var account = auth.userAccount - - model := accountInfoDto{ - Name: account.Name, - Email: account.Email, - AccountName: account.AccountName, - } - - for _, collaborator := range account.Collaborators { - model.Collaborators = append(model.Collaborators, &collaboratorInfoDto{ - AccountId: collaborator.AccountId, - Role: collaborator.Role, - Email: collaborator.Email, - }) - } - - c.JSON(200, model) -} - -func (self *HttpServer) getOtherAccounts(c *gin.Context, auth *authContext) { - var account = auth.userAccount - - otherAccounts, err := self.store.GetOtherAccountsFor(account.Id) - if err != nil { - c.JSON(500, gin.H{"message": err.Error()}) - return - } - - var result []*otherAccountDto - result = append(result, &otherAccountDto{ - Id: account.Id, - Role: "owner", - IsUsing: account.Id == account.UsingAccountId, - Name: account.Email, - }) - - for _, other := range otherAccounts { - result = append(result, &otherAccountDto{ - Id: other.Id, - Role: other.Role, - Name: other.Name, - IsUsing: other.Id == account.UsingAccountId, - }) - } - - c.JSON(200, result) -} - -func (self *HttpServer) addCollaborator(c *gin.Context, auth *authContext) { - var model addCollaboratorDto - - if !c.EnsureBody(&model) { - c.JSON(400, gin.H{"message": "Invalid request"}) - return - } - - collaborator, err := self.store.GetAccountByLogin(model.Email) - if err != nil { - c.JSON(404, gin.H{"message": "Collaborator not found"}) - return - } - - userAccount := auth.userAccount - - if collaborator.Id == userAccount.Id { - c.JSON(400, gin.H{"message": "Cannot add yourself as collaborator"}) - return - } - - err = userAccount.AddCollaborator(collaborator) - if err != nil { - c.JSON(400, gin.H{"message": err.Error()}) - return - } - - err = self.store.UpdateAccount(userAccount) - if err != nil { - c.JSON(500, gin.H{"message": err.Error()}) - return - } - - c.Abort(204) -} - -func (self *HttpServer) removeCollaborator(c *gin.Context, auth *authContext) { - var model removeCollaboratorDto - if !c.EnsureBody(&model) { - c.JSON(400, gin.H{"message": "Invalid request"}) - return - } - - account := auth.userAccount - account.RemoveCollaborator(model.AccountId) - - err := self.store.UpdateAccount(account) - if err != nil { - c.JSON(500, gin.H{"message": err.Error()}) - return - } - - c.Abort(204) -} - -func (self *HttpServer) setUsingAccount(c *gin.Context, auth *authContext) { - 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) -} diff --git a/pkg/api/api_auth.go b/pkg/api/api_auth.go deleted file mode 100644 index 69ed3872748..00000000000 --- a/pkg/api/api_auth.go +++ /dev/null @@ -1,70 +0,0 @@ -package api - -import ( - "errors" - "strconv" - - "github.com/torkelo/grafana-pro/pkg/models" - - "github.com/gin-gonic/gin" - "github.com/gorilla/sessions" -) - -type authContext struct { - account *models.Account - userAccount *models.Account -} - -func (auth *authContext) getAccountId() int { - return auth.account.Id -} - -func (self *HttpServer) authDenied(c *gin.Context) { - c.Writer.Header().Set("Location", "/login") - c.Abort(302) -} - -func authGetRequestAccountId(c *gin.Context, session *sessions.Session) (int, error) { - accountId := session.Values["accountId"] - - urlQuery := c.Request.URL.Query() - if len(urlQuery["render"]) > 0 { - accId, _ := strconv.Atoi(urlQuery["accountId"][0]) - session.Values["accountId"] = accId - accountId = accId - } - - if accountId == nil { - return -1, errors.New("Auth: session account id not found") - } - - return accountId.(int), nil -} - -func (self *HttpServer) auth() gin.HandlerFunc { - return func(c *gin.Context) { - session, _ := sessionStore.Get(c.Request, "grafana-session") - accountId, err := authGetRequestAccountId(c, session) - - if err != nil && c.Request.URL.Path != "/login" { - self.authDenied(c) - return - } - - account, err := self.store.GetAccount(accountId) - if err != nil { - self.authDenied(c) - return - } - - usingAccount, err := self.store.GetAccount(account.UsingAccountId) - if err != nil { - self.authDenied(c) - return - } - - c.Set("userAccount", account) - c.Set("usingAccount", usingAccount) - session.Save(c.Request, c.Writer) - } -} diff --git a/pkg/api/api_dashboard.go b/pkg/api/api_dashboard.go deleted file mode 100644 index 36448aa7ecb..00000000000 --- a/pkg/api/api_dashboard.go +++ /dev/null @@ -1,87 +0,0 @@ -package api - -import ( - log "github.com/alecthomas/log4go" - "github.com/gin-gonic/gin" - "github.com/torkelo/grafana-pro/pkg/models" -) - -func init() { - addRoutes(func(self *HttpServer) { - self.addRoute("GET", "/api/dashboards/:slug", self.getDashboard) - self.addRoute("GET", "/api/search/", self.search) - self.addRoute("POST", "/api/dashboard/", self.postDashboard) - self.addRoute("DELETE", "/api/dashboard/:slug", self.deleteDashboard) - }) -} - -func (self *HttpServer) getDashboard(c *gin.Context, auth *authContext) { - slug := c.Params.ByName("slug") - - dash, err := self.store.GetDashboard(slug, auth.getAccountId()) - if err != nil { - c.JSON(404, newErrorResponse("Dashboard not found")) - return - } - - dash.Data["id"] = dash.Id - - c.JSON(200, dash.Data) -} - -func (self *HttpServer) deleteDashboard(c *gin.Context, auth *authContext) { - slug := c.Params.ByName("slug") - - dash, err := self.store.GetDashboard(slug, auth.getAccountId()) - if err != nil { - c.JSON(404, newErrorResponse("Dashboard not found")) - return - } - - err = self.store.DeleteDashboard(slug, auth.getAccountId()) - if err != nil { - c.JSON(500, newErrorResponse("Failed to delete dashboard: "+err.Error())) - return - } - - var resp = map[string]interface{}{"title": dash.Title} - - c.JSON(200, resp) -} - -func (self *HttpServer) search(c *gin.Context, auth *authContext) { - query := c.Params.ByName("q") - - results, err := self.store.Query(query, auth.getAccountId()) - if err != nil { - log.Error("Store query error: %v", err) - c.JSON(500, newErrorResponse("Failed")) - return - } - - c.JSON(200, results) -} - -func (self *HttpServer) postDashboard(c *gin.Context, auth *authContext) { - var command saveDashboardCommand - - if c.EnsureBody(&command) { - dashboard := models.NewDashboard("test") - dashboard.Data = command.Dashboard - dashboard.Title = dashboard.Data["title"].(string) - dashboard.AccountId = auth.getAccountId() - dashboard.UpdateSlug() - - if dashboard.Data["id"] != nil { - dashboard.Id = dashboard.Data["id"].(string) - } - - err := self.store.SaveDashboard(dashboard) - if err == nil { - c.JSON(200, gin.H{"status": "success", "slug": dashboard.Slug}) - return - } - } - - c.JSON(500, gin.H{"error": "bad request"}) -} diff --git a/pkg/api/api_dtos.go b/pkg/api/api_dtos.go deleted file mode 100644 index ff6cc6670a9..00000000000 --- a/pkg/api/api_dtos.go +++ /dev/null @@ -1,29 +0,0 @@ -package api - -type accountInfoDto struct { - Email string `json:"email"` - Name string `json:"name"` - AccountName string `json:"accountName"` - Collaborators []*collaboratorInfoDto `json:"collaborators"` -} - -type collaboratorInfoDto struct { - AccountId int `json:"accountId"` - Email string `json:"email"` - Role string `json:"role"` -} - -type addCollaboratorDto struct { - Email string `json:"email" binding:"required"` -} - -type removeCollaboratorDto struct { - AccountId int `json:"accountId" binding:"required"` -} - -type otherAccountDto struct { - Id int `json:"id"` - Name string `json:"name"` - Role string `json:"role"` - IsUsing bool `json:"isUsing"` -} diff --git a/pkg/api/api_logger.go b/pkg/api/api_logger.go deleted file mode 100644 index f332889f1fc..00000000000 --- a/pkg/api/api_logger.go +++ /dev/null @@ -1,63 +0,0 @@ -package api - -import ( - "strings" - "time" - - "github.com/gin-gonic/gin" - - "github.com/torkelo/grafana-pro/pkg/log" -) - -var ( - green = string([]byte{27, 91, 57, 55, 59, 52, 50, 109}) - white = string([]byte{27, 91, 57, 48, 59, 52, 55, 109}) - yellow = string([]byte{27, 91, 57, 55, 59, 52, 51, 109}) - red = string([]byte{27, 91, 57, 55, 59, 52, 49, 109}) - reset = string([]byte{27, 91, 48, 109}) -) - -func ignoreLoggingRequest(code int, contentType string) bool { - return code == 304 || - strings.HasPrefix(contentType, "application/javascript") || - strings.HasPrefix(contentType, "text/") || - strings.HasPrefix(contentType, "application/x-font-woff") -} - -func apiLogger() gin.HandlerFunc { - return func(c *gin.Context) { - // Start timer - start := time.Now() - - // Process request - c.Next() - - code := c.Writer.Status() - contentType := c.Writer.Header().Get("Content-Type") - - // ignore logging some requests - if ignoreLoggingRequest(code, contentType) { - return - } - - // save the IP of the requester - requester := c.Request.Header.Get("X-Real-IP") - // if the requester-header is empty, check the forwarded-header - if len(requester) == 0 { - requester = c.Request.Header.Get("X-Forwarded-For") - } - // if the requester is still empty, use the hard-coded address from the socket - if len(requester) == 0 { - requester = c.Request.RemoteAddr - } - - end := time.Now() - latency := end.Sub(start) - log.Info("[http] %s %s %3d %12v %s", - c.Request.Method, c.Request.URL.Path, - code, - latency, - c.Errors.String(), - ) - } -} diff --git a/pkg/api/api_login.go b/pkg/api/api_login.go deleted file mode 100644 index 01fcfa95369..00000000000 --- a/pkg/api/api_login.go +++ /dev/null @@ -1,70 +0,0 @@ -package api - -import ( - "github.com/gin-gonic/gin" - "github.com/torkelo/grafana-pro/pkg/models" - - log "github.com/alecthomas/log4go" -) - -func init() { - addRoutes(func(self *HttpServer) { - self.router.GET("/login", self.index) - self.router.POST("/login", self.loginPost) - self.router.POST("/logout", self.logoutPost) - }) -} - -type loginJsonModel struct { - Email string `json:"email" binding:"required"` - Password string `json:"password" binding:"required"` - Remember bool `json:"remember"` -} - -func (self *HttpServer) loginPost(c *gin.Context) { - var loginModel loginJsonModel - - if !c.EnsureBody(&loginModel) { - c.JSON(400, gin.H{"status": "bad request"}) - return - } - - account, err := self.store.GetAccountByLogin(loginModel.Email) - if err != nil { - c.JSON(400, gin.H{"status": err.Error()}) - return - } - - if loginModel.Password != account.Password { - c.JSON(401, gin.H{"status": "unauthorized"}) - return - } - - loginUserWithAccount(account, c) - - var resp = &LoginResultDto{} - resp.Status = "Logged in" - resp.User.Login = account.Login - - c.JSON(200, resp) -} - -func loginUserWithAccount(account *models.Account, c *gin.Context) { - if account == nil { - log.Error("Account login with nil account") - } - session, err := sessionStore.Get(c.Request, "grafana-session") - if err != nil { - log.Error("Failed to get session %v", err) - } - session.Values["accountId"] = account.Id - session.Save(c.Request, c.Writer) -} - -func (self *HttpServer) logoutPost(c *gin.Context) { - session, _ := sessionStore.Get(c.Request, "grafana-session") - session.Values = nil - session.Save(c.Request, c.Writer) - - c.JSON(200, gin.H{"status": "logged out"}) -} diff --git a/pkg/api/api_models.go b/pkg/api/api_models.go deleted file mode 100644 index de2b8762d13..00000000000 --- a/pkg/api/api_models.go +++ /dev/null @@ -1,52 +0,0 @@ -package api - -import ( - "crypto/md5" - "fmt" - "strings" - - "github.com/torkelo/grafana-pro/pkg/models" -) - -type saveDashboardCommand struct { - Id string `json:"id"` - Title string `json:"title"` - Dashboard map[string]interface{} -} - -type errorResponse struct { - Message string `json:"message"` -} - -type IndexDto struct { - User CurrentUserDto -} - -type CurrentUserDto struct { - Login string `json:"login"` - Email string `json:"email"` - GravatarUrl string `json:"gravatarUrl"` -} - -type LoginResultDto struct { - Status string `json:"status"` - User CurrentUserDto `json:"user"` -} - -func newErrorResponse(message string) *errorResponse { - return &errorResponse{Message: message} -} - -func initCurrentUserDto(userDto *CurrentUserDto, account *models.Account) { - if account != nil { - userDto.Login = account.Login - userDto.Email = account.Email - userDto.GravatarUrl = getGravatarUrl(account.Email) - } -} - -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)) -} diff --git a/pkg/api/api_oauth.go b/pkg/api/api_oauth.go deleted file mode 100644 index 778f64ec17c..00000000000 --- a/pkg/api/api_oauth.go +++ /dev/null @@ -1 +0,0 @@ -package api diff --git a/pkg/api/api_oauth_github.go b/pkg/api/api_oauth_github.go deleted file mode 100644 index 7e6a96babc8..00000000000 --- a/pkg/api/api_oauth_github.go +++ /dev/null @@ -1,112 +0,0 @@ -package api - -import ( - "encoding/json" - "net/http" - - log "github.com/alecthomas/log4go" - "github.com/gin-gonic/gin" - "github.com/golang/oauth2" - "github.com/torkelo/grafana-pro/pkg/models" - "github.com/torkelo/grafana-pro/pkg/stores" -) - -var ( - githubOAuthConfig *oauth2.Config - githubRedirectUrl string = "http://localhost:3000/oauth2/github/callback" - githubAuthUrl string = "https://github.com/login/oauth/authorize" - githubTokenUrl string = "https://github.com/login/oauth/access_token" -) - -func init() { - addRoutes(func(self *HttpServer) { - if !self.cfg.Http.GithubOAuth.Enabled { - return - } - - self.router.GET("/oauth2/github", self.oauthGithub) - self.router.GET("/oauth2/github/callback", self.oauthGithubCallback) - - options := &oauth2.Options{ - ClientID: self.cfg.Http.GithubOAuth.ClientId, - ClientSecret: self.cfg.Http.GithubOAuth.ClientSecret, - RedirectURL: githubRedirectUrl, - Scopes: []string{"user:email"}, - } - - cfg, err := oauth2.NewConfig(options, githubAuthUrl, githubTokenUrl) - - if err != nil { - log.Error("Failed to init github auth %v", err) - } - - githubOAuthConfig = cfg - }) -} - -func (self *HttpServer) oauthGithub(c *gin.Context) { - url := githubOAuthConfig.AuthCodeURL("", "online", "auto") - c.Redirect(302, url) -} - -type githubUserInfoDto struct { - Login string `json:"login"` - Name string `json:"name"` - Email string `json:"email"` - Company string `json:"company"` -} - -func (self *HttpServer) oauthGithubCallback(c *gin.Context) { - code := c.Request.URL.Query()["code"][0] - log.Info("OAuth code: %v", code) - - transport, err := githubOAuthConfig.NewTransportWithCode(code) - if err != nil { - c.String(500, "Failed to exchange oauth token: "+err.Error()) - return - } - - client := http.Client{Transport: transport} - resp, err := client.Get("https://api.github.com/user") - if err != nil { - c.String(500, err.Error()) - return - } - - var userInfo githubUserInfoDto - decoder := json.NewDecoder(resp.Body) - err = decoder.Decode(&userInfo) - if err != nil { - c.String(500, err.Error()) - return - } - - if len(userInfo.Email) < 5 { - c.String(500, "Invalid email") - return - } - - // try find existing account - account, err := self.store.GetAccountByLogin(userInfo.Email) - - // create account if missing - if err == stores.ErrAccountNotFound { - account = &models.Account{ - Login: userInfo.Login, - Email: userInfo.Email, - Name: userInfo.Name, - Company: userInfo.Company, - } - - if err = self.store.CreateAccount(account); err != nil { - log.Error("Failed to create account %v", err) - c.String(500, "Failed to create account") - return - } - } - - // login - loginUserWithAccount(account, c) - - c.Redirect(302, "/") -} diff --git a/pkg/api/api_oauth_google.go b/pkg/api/api_oauth_google.go deleted file mode 100644 index efa27e2d1f8..00000000000 --- a/pkg/api/api_oauth_google.go +++ /dev/null @@ -1,113 +0,0 @@ -package api - -import ( - "encoding/json" - "net/http" - - log "github.com/alecthomas/log4go" - "github.com/gin-gonic/gin" - "github.com/golang/oauth2" - "github.com/torkelo/grafana-pro/pkg/models" - "github.com/torkelo/grafana-pro/pkg/stores" -) - -var ( - googleOAuthConfig *oauth2.Config - googleRedirectUrl string = "http://localhost:3000/oauth2/google/callback" - googleAuthUrl string = "https://accounts.google.com/o/oauth2/auth" - googleTokenUrl string = "https://accounts.google.com/o/oauth2/token" - googleScopeProfile string = "https://www.googleapis.com/auth/userinfo.profile" - googleScopeEmail string = "https://www.googleapis.com/auth/userinfo.email" -) - -func init() { - addRoutes(func(self *HttpServer) { - if !self.cfg.Http.GoogleOAuth.Enabled { - return - } - - self.router.GET("/oauth2/google", self.oauthGoogle) - self.router.GET("/oauth2/google/callback", self.oauthGoogleCallback) - - options := &oauth2.Options{ - ClientID: self.cfg.Http.GoogleOAuth.ClientId, - ClientSecret: self.cfg.Http.GoogleOAuth.ClientSecret, - RedirectURL: googleRedirectUrl, - Scopes: []string{googleScopeEmail, googleScopeProfile}, - } - - cfg, err := oauth2.NewConfig(options, googleAuthUrl, googleTokenUrl) - - if err != nil { - log.Error("Failed to init google auth %v", err) - } - - googleOAuthConfig = cfg - }) -} - -func (self *HttpServer) oauthGoogle(c *gin.Context) { - url := googleOAuthConfig.AuthCodeURL("", "online", "auto") - c.Redirect(302, url) -} - -type googleUserInfoDto struct { - Email string `json:"email"` - GivenName string `json:"givenName"` - FamilyName string `json:"familyName"` - Name string `json:"name"` -} - -func (self *HttpServer) oauthGoogleCallback(c *gin.Context) { - code := c.Request.URL.Query()["code"][0] - log.Info("OAuth code: %v", code) - - transport, err := googleOAuthConfig.NewTransportWithCode(code) - if err != nil { - c.String(500, "Failed to exchange oauth token: "+err.Error()) - return - } - - client := http.Client{Transport: transport} - resp, err := client.Get("https://www.googleapis.com/oauth2/v1/userinfo?alt=json") - if err != nil { - c.String(500, err.Error()) - return - } - - var userInfo googleUserInfoDto - decoder := json.NewDecoder(resp.Body) - err = decoder.Decode(&userInfo) - if err != nil { - c.String(500, err.Error()) - return - } - - if len(userInfo.Email) < 5 { - c.String(500, "Invalid email") - return - } - - // try find existing account - account, err := self.store.GetAccountByLogin(userInfo.Email) - - // create account if missing - if err == stores.ErrAccountNotFound { - account = &models.Account{ - Login: userInfo.Email, - Email: userInfo.Email, - Name: userInfo.Name, - } - - if err = self.store.CreateAccount(account); err != nil { - log.Error("Failed to create account %v", err) - c.String(500, "Failed to create account") - return - } - } - - // login - loginUserWithAccount(account, c) - - c.Redirect(302, "/") -} diff --git a/pkg/api/api_register.go b/pkg/api/api_register.go deleted file mode 100644 index f735b14ecce..00000000000 --- a/pkg/api/api_register.go +++ /dev/null @@ -1,44 +0,0 @@ -package api - -import ( - log "github.com/alecthomas/log4go" - "github.com/gin-gonic/gin" - "github.com/torkelo/grafana-pro/pkg/models" -) - -func init() { - addRoutes(func(self *HttpServer) { - self.router.GET("/register/*_", self.index) - self.router.POST("/api/register/user", self.registerUserPost) - }) -} - -type registerAccountJsonModel struct { - Email string `json:"email" binding:"required"` - Password string `json:"password" binding:"required"` - Password2 bool `json:"remember2"` -} - -func (self *HttpServer) registerUserPost(c *gin.Context) { - var registerModel registerAccountJsonModel - - if !c.EnsureBody(®isterModel) { - c.JSON(400, gin.H{"status": "bad request"}) - return - } - - account := models.Account{ - Login: registerModel.Email, - Email: registerModel.Email, - Password: registerModel.Password, - } - - err := self.store.CreateAccount(&account) - if err != nil { - log.Error("Failed to create user account, email: %v, error: %v", registerModel.Email, err) - c.JSON(500, gin.H{"status": "failed to create account"}) - return - } - - c.JSON(200, gin.H{"status": "ok"}) -} diff --git a/pkg/api/api_render.go b/pkg/api/api_render.go deleted file mode 100644 index 21d38a2bf97..00000000000 --- a/pkg/api/api_render.go +++ /dev/null @@ -1,36 +0,0 @@ -package api - -import ( - "strconv" - - "github.com/gin-gonic/gin" - "github.com/torkelo/grafana-pro/pkg/components" - "github.com/torkelo/grafana-pro/pkg/utils" -) - -func init() { - addRoutes(func(self *HttpServer) { - self.addRoute("GET", "/render/*url", self.renderToPng) - }) -} - -func (self *HttpServer) renderToPng(c *gin.Context, auth *authContext) { - accountId := auth.getAccountId() - queryReader := utils.NewUrlQueryReader(c.Request.URL) - queryParams := "?render&accountId=" + strconv.Itoa(accountId) + "&" + c.Request.URL.RawQuery - - renderOpts := &components.RenderOpts{ - Url: c.Params.ByName("url") + queryParams, - Width: queryReader.Get("width", "800"), - Height: queryReader.Get("height", "400"), - } - - renderOpts.Url = "http://localhost:3000" + renderOpts.Url - - pngPath, err := self.renderer.RenderToPng(renderOpts) - if err != nil { - c.HTML(500, "error.html", nil) - } - - c.File(pngPath) -} diff --git a/pkg/api/api_routing.go b/pkg/api/api_routing.go deleted file mode 100644 index f15dffaff06..00000000000 --- a/pkg/api/api_routing.go +++ /dev/null @@ -1,36 +0,0 @@ -package api - -import ( - "github.com/gin-gonic/gin" - "github.com/torkelo/grafana-pro/pkg/models" -) - -type routeHandlerRegisterFn func(self *HttpServer) -type routeHandlerFn func(c *gin.Context, auth *authContext) - -var routeHandlers = make([]routeHandlerRegisterFn, 0) - -func getRouteHandlerWrapper(handler routeHandlerFn) gin.HandlerFunc { - return func(c *gin.Context) { - authContext := authContext{ - account: c.MustGet("usingAccount").(*models.Account), - userAccount: c.MustGet("userAccount").(*models.Account), - } - handler(c, &authContext) - } -} - -func (self *HttpServer) addRoute(method string, path string, handler routeHandlerFn) { - switch method { - case "GET": - self.router.GET(path, self.auth(), getRouteHandlerWrapper(handler)) - case "POST": - self.router.POST(path, self.auth(), getRouteHandlerWrapper(handler)) - case "DELETE": - self.router.DELETE(path, self.auth(), getRouteHandlerWrapper(handler)) - } -} - -func addRoutes(fn routeHandlerRegisterFn) { - routeHandlers = append(routeHandlers, fn) -} diff --git a/pkg/api/api_test.go b/pkg/api/api_test.go deleted file mode 100644 index 778f64ec17c..00000000000 --- a/pkg/api/api_test.go +++ /dev/null @@ -1 +0,0 @@ -package api diff --git a/pkg/routes/api/api_account.go b/pkg/routes/api/api_account.go index c46fa42042c..8579fc0a4ce 100644 --- a/pkg/routes/api/api_account.go +++ b/pkg/routes/api/api_account.go @@ -87,3 +87,29 @@ func GetOtherAccounts(c *middleware.Context) { 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) +// } diff --git a/pkg/stores/rethinkdb.go b/pkg/stores/rethinkdb.go deleted file mode 100644 index eb9a016c2a9..00000000000 --- a/pkg/stores/rethinkdb.go +++ /dev/null @@ -1,45 +0,0 @@ -package stores - -import ( - "time" - - r "github.com/dancannon/gorethink" - - "github.com/torkelo/grafana-pro/pkg/log" -) - -type rethinkStore struct { - session *r.Session -} - -type RethinkCfg struct { - DatabaseName string -} - -type Account struct { - Id int `gorethink:"id"` - NextDashboardId int -} - -func NewRethinkStore(config *RethinkCfg) *rethinkStore { - log.Info("Initializing rethink storage") - - session, err := r.Connect(r.ConnectOpts{ - Address: "localhost:28015", - Database: config.DatabaseName, - MaxIdle: 10, - IdleTimeout: time.Second * 10, - }) - - if err != nil { - log.Error(3, "Failed to connect to rethink database %v", err) - } - - createRethinkDBTablesAndIndices(config, session) - - return &rethinkStore{ - session: session, - } -} - -func (self *rethinkStore) Close() {} diff --git a/pkg/stores/rethinkdb_accounts.go b/pkg/stores/rethinkdb_accounts.go deleted file mode 100644 index ec5161475eb..00000000000 --- a/pkg/stores/rethinkdb_accounts.go +++ /dev/null @@ -1,136 +0,0 @@ -package stores - -import ( - "errors" - - r "github.com/dancannon/gorethink" - "github.com/torkelo/grafana-pro/pkg/models" -) - -func (self *rethinkStore) getNextAccountId() (int, error) { - resp, err := r.Table("master").Get("ids").Update(map[string]interface{}{ - "NextAccountId": r.Row.Field("NextAccountId").Add(1), - }, r.UpdateOpts{ReturnChanges: true}).RunWrite(self.session) - - if err != nil { - return 0, err - } - - change := resp.Changes[0] - - if change.NewValue == nil { - return 0, errors.New("Failed to get new value after incrementing account id") - } - - return int(change.NewValue.(map[string]interface{})["NextAccountId"].(float64)), nil -} - -func (self *rethinkStore) CreateAccount(account *models.Account) error { - accountId, err := self.getNextAccountId() - if err != nil { - return err - } - - account.Id = accountId - account.UsingAccountId = accountId - - resp, err := r.Table("accounts").Insert(account).RunWrite(self.session) - if err != nil { - return err - } - - if resp.Inserted == 0 { - return errors.New("Failed to insert acccount") - } - - return nil -} - -func (self *rethinkStore) GetAccountByLogin(emailOrName string) (*models.Account, error) { - resp, err := r.Table("accounts").GetAllByIndex("Login", emailOrName).Run(self.session) - - if err != nil { - return nil, err - } - - var account models.Account - err = resp.One(&account) - if err != nil { - return nil, ErrAccountNotFound - } - - return &account, nil -} - -func (self *rethinkStore) GetAccount(id int) (*models.Account, error) { - resp, err := r.Table("accounts").Get(id).Run(self.session) - - if err != nil { - return nil, err - } - - var account models.Account - err = resp.One(&account) - if err != nil { - return nil, errors.New("Not found") - } - - return &account, nil -} - -func (self *rethinkStore) UpdateAccount(account *models.Account) error { - resp, err := r.Table("accounts").Update(account).RunWrite(self.session) - if err != nil { - return err - } - - if resp.Replaced == 0 && resp.Unchanged == 0 { - return errors.New("Could not find account to update") - } - - return nil -} - -func (self *rethinkStore) getNextDashboardNumber(accountId int) (int, error) { - resp, err := r.Table("accounts").Get(accountId).Update(map[string]interface{}{ - "NextDashboardId": r.Row.Field("NextDashboardId").Add(1), - }, r.UpdateOpts{ReturnChanges: true}).RunWrite(self.session) - - if err != nil { - return 0, err - } - - change := resp.Changes[0] - - if change.NewValue == nil { - return 0, errors.New("Failed to get next dashboard id, no new value after update") - } - - return int(change.NewValue.(map[string]interface{})["NextDashboardId"].(float64)), nil -} - -func (self *rethinkStore) GetOtherAccountsFor(accountId int) ([]*models.OtherAccount, error) { - resp, err := r.Table("accounts"). - GetAllByIndex("CollaboratorAccountId", accountId). - Map(func(row r.Term) interface{} { - return map[string]interface{}{ - "id": row.Field("id"), - "Name": row.Field("Email"), - "Role": row.Field("Collaborators").Filter(map[string]interface{}{ - "AccountId": accountId, - }).Nth(0).Field("Role"), - } - }).Run(self.session) - - if err != nil { - return nil, err - } - - var list []*models.OtherAccount - err = resp.All(&list) - if err != nil { - return nil, errors.New("Failed to read available accounts") - } - - return list, nil -} diff --git a/pkg/stores/rethinkdb_dashboards.go b/pkg/stores/rethinkdb_dashboards.go deleted file mode 100644 index 838d5715403..00000000000 --- a/pkg/stores/rethinkdb_dashboards.go +++ /dev/null @@ -1,79 +0,0 @@ -package stores - -import ( - "errors" - - log "github.com/alecthomas/log4go" - r "github.com/dancannon/gorethink" - "github.com/torkelo/grafana-pro/pkg/models" -) - -func (self *rethinkStore) SaveDashboard(dash *models.Dashboard) error { - resp, err := r.Table("dashboards").Insert(dash, r.InsertOpts{Conflict: "update"}).RunWrite(self.session) - if err != nil { - return err - } - - log.Info("Inserted: %v, Errors: %v, Updated: %v", resp.Inserted, resp.Errors, resp.Updated) - log.Info("First error:", resp.FirstError) - if len(resp.GeneratedKeys) > 0 { - dash.Id = resp.GeneratedKeys[0] - } - - return nil -} - -func (self *rethinkStore) GetDashboard(slug string, accountId int) (*models.Dashboard, error) { - resp, err := r.Table("dashboards"). - GetAllByIndex("AccountIdSlug", []interface{}{accountId, slug}). - Run(self.session) - - if err != nil { - return nil, err - } - - var dashboard models.Dashboard - err = resp.One(&dashboard) - if err != nil { - return nil, err - } - - return &dashboard, nil -} - -func (self *rethinkStore) DeleteDashboard(slug string, accountId int) error { - resp, err := r.Table("dashboards"). - GetAllByIndex("AccountIdSlug", []interface{}{accountId, slug}). - Delete().RunWrite(self.session) - - if err != nil { - return err - } - - if resp.Deleted != 1 { - return errors.New("Did not find dashboard to delete") - } - - return nil -} - -func (self *rethinkStore) Query(query string, accountId int) ([]*models.SearchResult, error) { - docs, err := r.Table("dashboards"). - GetAllByIndex("AccountId", []interface{}{accountId}). - Filter(r.Row.Field("Title").Match(".*")).Run(self.session) - - if err != nil { - return nil, err - } - - results := make([]*models.SearchResult, 0, 50) - var dashboard models.Dashboard - for docs.Next(&dashboard) { - results = append(results, &models.SearchResult{ - Title: dashboard.Title, - Id: dashboard.Slug, - }) - } - - return results, nil -} diff --git a/pkg/stores/rethinkdb_setup.go b/pkg/stores/rethinkdb_setup.go deleted file mode 100644 index 0f16474eabb..00000000000 --- a/pkg/stores/rethinkdb_setup.go +++ /dev/null @@ -1,39 +0,0 @@ -package stores - -import ( - log "github.com/alecthomas/log4go" - r "github.com/dancannon/gorethink" -) - -func createRethinkDBTablesAndIndices(config *RethinkCfg, session *r.Session) { - - r.DbCreate(config.DatabaseName).Exec(session) - - // create tables - r.Db(config.DatabaseName).TableCreate("dashboards").Exec(session) - r.Db(config.DatabaseName).TableCreate("accounts").Exec(session) - r.Db(config.DatabaseName).TableCreate("master").Exec(session) - - // create dashboard accountId + slug index - r.Db(config.DatabaseName).Table("dashboards").IndexCreateFunc("AccountIdSlug", func(row r.Term) interface{} { - return []interface{}{row.Field("AccountId"), row.Field("Slug")} - }).Exec(session) - - r.Db(config.DatabaseName).Table("dashboards").IndexCreate("AccountId").Exec(session) - r.Db(config.DatabaseName).Table("accounts").IndexCreate("Login").Exec(session) - - // create account collaborator index - r.Db(config.DatabaseName).Table("accounts"). - IndexCreateFunc("CollaboratorAccountId", func(row r.Term) interface{} { - return row.Field("Collaborators").Map(func(row r.Term) interface{} { - return row.Field("AccountId") - }) - }, r.IndexCreateOpts{Multi: true}).Exec(session) - - // make sure master ids row exists - _, err := r.Table("master").Insert(map[string]interface{}{"id": "ids", "NextAccountId": 0}).RunWrite(session) - if err != nil { - log.Error("Failed to insert master ids row", err) - } - -} diff --git a/pkg/stores/rethinkdb_test.go b/pkg/stores/rethinkdb_test.go deleted file mode 100644 index 4de4dc48d8e..00000000000 --- a/pkg/stores/rethinkdb_test.go +++ /dev/null @@ -1,56 +0,0 @@ -package stores - -import ( - "testing" - - "github.com/dancannon/gorethink" - . "github.com/smartystreets/goconvey/convey" - "github.com/torkelo/grafana-pro/pkg/models" -) - -func TestRethinkStore(t *testing.T) { - store := NewRethinkStore(&RethinkCfg{DatabaseName: "tests"}) - defer gorethink.DbDrop("tests").Exec(store.session) - - Convey("Insert dashboard", t, func() { - dashboard := models.NewDashboard("test") - dashboard.AccountId = 1 - - err := store.SaveDashboard(dashboard) - So(err, ShouldBeNil) - So(dashboard.Id, ShouldNotBeEmpty) - - read, err := store.GetDashboard("test", 1) - So(err, ShouldBeNil) - So(read, ShouldNotBeNil) - }) - - Convey("can get next account id", t, func() { - id, err := store.getNextAccountId() - So(err, ShouldBeNil) - So(id, ShouldNotEqual, 0) - - id2, err := store.getNextAccountId() - So(id2, ShouldEqual, id+1) - }) - - Convey("can create account", t, func() { - account := &models.Account{UserName: "torkelo", Email: "mupp", Login: "test@test.com"} - err := store.CreateAccount(account) - So(err, ShouldBeNil) - So(account.Id, ShouldNotEqual, 0) - - read, err := store.GetUserAccountLogin("test@test.com") - So(err, ShouldBeNil) - So(read.Id, ShouldEqual, account.DatabaseId) - }) - - Convey("can get next dashboard id", t, func() { - account := &models.Account{UserName: "torkelo", Email: "mupp"} - err := store.CreateAccount(account) - dashId, err := store.getNextDashboardNumber(account.Id) - So(err, ShouldBeNil) - So(dashId, ShouldEqual, 1) - }) - -} diff --git a/pkg/stores/store.go b/pkg/stores/store.go deleted file mode 100644 index f8a3c08fd16..00000000000 --- a/pkg/stores/store.go +++ /dev/null @@ -1,20 +0,0 @@ -package stores - -import "github.com/torkelo/grafana-pro/pkg/models" - -type Store interface { - GetDashboard(slug string, accountId int) (*models.Dashboard, error) - SaveDashboard(dash *models.Dashboard) error - DeleteDashboard(slug string, accountId int) error - Query(query string, acccountId int) ([]*models.SearchResult, error) - CreateAccount(acccount *models.Account) error - UpdateAccount(acccount *models.Account) error - GetAccountByLogin(emailOrName string) (*models.Account, error) - GetAccount(accountId int) (*models.Account, error) - GetOtherAccountsFor(accountId int) ([]*models.OtherAccount, error) - Close() -} - -func New() Store { - return NewRethinkStore(&RethinkCfg{DatabaseName: "grafana"}) -}