diff --git a/pkg/api/api.go b/pkg/api/api.go index 14e693752b9..cfc1f50b98e 100644 --- a/pkg/api/api.go +++ b/pkg/api/api.go @@ -55,15 +55,21 @@ func Register(r *macaron.Macaron) { r.Group("/api", func() { // user r.Group("/user", func() { - r.Get("/", GetUser) + r.Get("/", wrap(GetSignedInUser)) r.Put("/", bind(m.UpdateUserCommand{}), UpdateUser) r.Post("/using/:id", UserSetUsingOrg) - r.Get("/orgs", GetUserOrgList) + r.Get("/orgs", wrap(GetSignedInUserOrgList)) r.Post("/stars/dashboard/:id", StarDashboard) r.Delete("/stars/dashboard/:id", UnstarDashboard) r.Put("/password", bind(m.ChangeUserPasswordCommand{}), ChangeUserPassword) }) + // users + r.Group("/users", func() { + r.Get("/:id/", wrap(GetUserById)) + r.Get("/:id/org", wrap(GetUserOrgList)) + }, reqGrafanaAdmin) + // account r.Group("/org", func() { r.Get("/", GetOrg) @@ -127,5 +133,5 @@ func Register(r *macaron.Macaron) { // rendering r.Get("/render/*", reqSignedIn, RenderToPng) - r.NotFound(NotFound) + r.NotFound(NotFoundHandler) } diff --git a/pkg/api/common.go b/pkg/api/common.go new file mode 100644 index 00000000000..8757318159e --- /dev/null +++ b/pkg/api/common.go @@ -0,0 +1,111 @@ +package api + +import ( + "encoding/json" + "net/http" + + "github.com/Unknwon/macaron" + "github.com/grafana/grafana/pkg/log" + "github.com/grafana/grafana/pkg/metrics" + "github.com/grafana/grafana/pkg/middleware" + "github.com/grafana/grafana/pkg/setting" +) + +var ( + NotFound = ApiError(404, "Not found", nil) + ServerError = ApiError(500, "Server error", nil) +) + +type Response interface { + WriteTo(out http.ResponseWriter) +} + +type NormalResponse struct { + status int + body []byte + header http.Header +} + +func wrap(action func(c *middleware.Context) Response) macaron.Handler { + return func(c *middleware.Context) { + res := action(c) + if res == nil { + res = ServerError + } + res.WriteTo(c.Resp) + } +} + +func (r *NormalResponse) WriteTo(out http.ResponseWriter) { + header := out.Header() + for k, v := range r.header { + header[k] = v + } + out.WriteHeader(r.status) + out.Write(r.body) +} + +func (r *NormalResponse) Cache(ttl string) *NormalResponse { + return r.Header("Cache-Control", "public,max-age="+ttl) +} + +func (r *NormalResponse) Header(key, value string) *NormalResponse { + r.header.Set(key, value) + return r +} + +// functions to create responses + +func Empty(status int) *NormalResponse { + return Respond(status, nil) +} + +func Json(status int, body interface{}) *NormalResponse { + return Respond(status, body).Header("Content-Type", "application/json") +} + +func ApiError(status int, message string, err error) *NormalResponse { + resp := make(map[string]interface{}) + + if err != nil { + log.Error(4, "%s: %v", message, err) + if setting.Env != setting.PROD { + resp["error"] = err.Error() + } + } + + switch status { + case 404: + resp["message"] = "Not Found" + metrics.M_Api_Status_500.Inc(1) + case 500: + metrics.M_Api_Status_404.Inc(1) + resp["message"] = "Internal Server Error" + } + + if message != "" { + resp["message"] = message + } + + return Json(status, resp) +} + +func Respond(status int, body interface{}) *NormalResponse { + var b []byte + var err error + switch t := body.(type) { + case []byte: + b = t + case string: + b = []byte(t) + default: + if b, err = json.Marshal(body); err != nil { + return ApiError(500, "body json marshal", err) + } + } + return &NormalResponse{ + body: b, + status: status, + header: make(http.Header), + } +} diff --git a/pkg/api/index.go b/pkg/api/index.go index 386bb3351df..8f486c4b785 100644 --- a/pkg/api/index.go +++ b/pkg/api/index.go @@ -59,7 +59,7 @@ func Index(c *middleware.Context) { c.HTML(200, "index") } -func NotFound(c *middleware.Context) { +func NotFoundHandler(c *middleware.Context) { if c.IsApiRequest() { c.JsonApiErr(404, "Not found", nil) return diff --git a/pkg/api/user.go b/pkg/api/user.go index 9d870a10a1b..e7cc8ff0366 100644 --- a/pkg/api/user.go +++ b/pkg/api/user.go @@ -7,15 +7,24 @@ import ( "github.com/grafana/grafana/pkg/util" ) -func GetUser(c *middleware.Context) { - query := m.GetUserProfileQuery{UserId: c.UserId} +// GET /api/user (current authenticated user) +func GetSignedInUser(c *middleware.Context) Response { + return getUserUserProfile(c.UserId) +} + +// GET /api/user/:id +func GetUserById(c *middleware.Context) Response { + return getUserUserProfile(c.ParamsInt64(":id")) +} + +func getUserUserProfile(userId int64) Response { + query := m.GetUserProfileQuery{UserId: userId} if err := bus.Dispatch(&query); err != nil { - c.JsonApiErr(500, "Failed to get user", err) - return + return ApiError(500, "Failed to get user", err) } - c.JSON(200, query.Result) + return Json(200, query.Result) } func UpdateUser(c *middleware.Context, cmd m.UpdateUserCommand) { @@ -29,22 +38,24 @@ func UpdateUser(c *middleware.Context, cmd m.UpdateUserCommand) { c.JsonOK("User updated") } -func GetUserOrgList(c *middleware.Context) { - query := m.GetUserOrgListQuery{UserId: c.UserId} +// GET /api/user/orgs +func GetSignedInUserOrgList(c *middleware.Context) Response { + return getUserOrgList(c.UserId) +} + +// GET /api/user/:id/orgs +func GetUserOrgList(c *middleware.Context) Response { + return getUserOrgList(c.ParamsInt64(":id")) +} + +func getUserOrgList(userId int64) Response { + query := m.GetUserOrgListQuery{UserId: userId} if err := bus.Dispatch(&query); err != nil { - c.JsonApiErr(500, "Failed to get user organizations", err) - return + return ApiError(500, "Faile to get user organziations", err) } - for _, ac := range query.Result { - if ac.OrgId == c.OrgId { - ac.IsUsing = true - break - } - } - - c.JSON(200, query.Result) + return Json(200, query.Result) } func validateUsingOrg(userId int64, orgId int64) bool { diff --git a/pkg/models/org.go b/pkg/models/org.go index ab6d97b9ae8..a8ee08ea69b 100644 --- a/pkg/models/org.go +++ b/pkg/models/org.go @@ -58,8 +58,7 @@ type OrgDTO struct { } type UserOrgDTO struct { - OrgId int64 `json:"orgId"` - Name string `json:"name"` - Role RoleType `json:"role"` - IsUsing bool `json:"isUsing"` + OrgId int64 `json:"orgId"` + Name string `json:"name"` + Role RoleType `json:"role"` } diff --git a/public/app/features/admin/partials/edit_user.html b/public/app/features/admin/partials/edit_user.html index 9b2a18fd010..c82d7705b8d 100644 --- a/public/app/features/admin/partials/edit_user.html +++ b/public/app/features/admin/partials/edit_user.html @@ -25,7 +25,7 @@
-
+
-
+
  • Username diff --git a/public/app/features/admin/partials/new_user.html b/public/app/features/admin/partials/new_user.html index 48f78fb76b6..73877f9bda4 100644 --- a/public/app/features/admin/partials/new_user.html +++ b/public/app/features/admin/partials/new_user.html @@ -24,7 +24,7 @@
-
+
  • Email @@ -35,7 +35,7 @@
-
+
  • Username @@ -46,7 +46,7 @@
-
+
  • Password diff --git a/public/app/features/profile/partials/profile.html b/public/app/features/profile/partials/profile.html index d8758ae9c09..5512245b275 100644 --- a/public/app/features/profile/partials/profile.html +++ b/public/app/features/profile/partials/profile.html @@ -71,10 +71,10 @@ Name: {{org.name}} Role: {{org.role}} - + Current - + Select