diff --git a/pkg/api/api.go b/pkg/api/api.go index f45da26d9c2..1c63ad3a541 100644 --- a/pkg/api/api.go +++ b/pkg/api/api.go @@ -13,7 +13,7 @@ func Register(r *macaron.Macaron) { reqSignedIn := middleware.Auth(&middleware.AuthOptions{ReqSignedIn: true}) reqGrafanaAdmin := middleware.Auth(&middleware.AuthOptions{ReqSignedIn: true, ReqGrafanaAdmin: true}) reqEditorRole := middleware.RoleAuth(m.ROLE_EDITOR, m.ROLE_ADMIN) - reqAccountAdmin := middleware.RoleAuth(m.ROLE_ADMIN) + regOrgAdmin := middleware.RoleAuth(m.ROLE_ADMIN) bind := binding.Bind // not logged in views @@ -71,23 +71,34 @@ func Register(r *macaron.Macaron) { r.Put("/:id", bind(m.UpdateUserCommand{}), wrap(UpdateUser)) }, reqGrafanaAdmin) - // account + // current org r.Group("/org", func() { - r.Get("/", GetOrg) - r.Post("/", bind(m.CreateOrgCommand{}), CreateOrg) - r.Put("/", bind(m.UpdateOrgCommand{}), UpdateOrg) - r.Post("/users", bind(m.AddOrgUserCommand{}), AddOrgUser) - r.Get("/users", GetOrgUsers) - r.Patch("/users/:id", bind(m.UpdateOrgUserCommand{}), UpdateOrgUser) - r.Delete("/users/:id", RemoveOrgUser) - }, reqAccountAdmin) + r.Get("/", wrap(GetOrgCurrent)) + r.Put("/", bind(m.UpdateOrgCommand{}), wrap(UpdateOrgCurrent)) + r.Post("/users", bind(m.AddOrgUserCommand{}), wrap(AddOrgUserToCurrentOrg)) + r.Get("/users", wrap(GetOrgUsersForCurrentOrg)) + r.Patch("/users/:userId", bind(m.UpdateOrgUserCommand{}), wrap(UpdateOrgUserForCurrentOrg)) + r.Delete("/users/:userId", wrap(RemoveOrgUserForCurrentOrg)) + }, regOrgAdmin) + + // create new org + r.Post("/orgs", bind(m.CreateOrgCommand{}), wrap(CreateOrg)) + + // orgs (admin routes) + r.Group("/orgs/:orgId", func() { + r.Put("/", bind(m.UpdateOrgCommand{}), wrap(UpdateOrg)) + r.Get("/users", wrap(GetOrgUsers)) + r.Post("/users", bind(m.AddOrgUserCommand{}), wrap(AddOrgUser)) + r.Patch("/users/:userId", bind(m.UpdateOrgUserCommand{}), wrap(UpdateOrgUser)) + r.Delete("/users/:userId", wrap(RemoveOrgUser)) + }, reqGrafanaAdmin) // auth api keys r.Group("/auth/keys", func() { r.Get("/", wrap(GetApiKeys)) r.Post("/", bind(m.AddApiKeyCommand{}), wrap(AddApiKey)) r.Delete("/:id", wrap(DeleteApiKey)) - }, reqAccountAdmin) + }, regOrgAdmin) // Data sources r.Group("/datasources", func() { @@ -98,7 +109,7 @@ func Register(r *macaron.Macaron) { r.Delete("/:id", DeleteDataSource) r.Get("/:id", GetDataSourceById) r.Get("/plugins", GetDataSourcePlugins) - }, reqAccountAdmin) + }, regOrgAdmin) r.Get("/frontend/settings/", GetFrontendSettings) r.Any("/datasources/proxy/:id/*", reqSignedIn, ProxyDataSourceRequest) diff --git a/pkg/api/org.go b/pkg/api/org.go index ac8727c9e49..5b9e1a9aef8 100644 --- a/pkg/api/org.go +++ b/pkg/api/org.go @@ -8,17 +8,25 @@ import ( "github.com/grafana/grafana/pkg/setting" ) -func GetOrg(c *middleware.Context) { - query := m.GetOrgByIdQuery{Id: c.OrgId} +// GET /api/org +func GetOrgCurrent(c *middleware.Context) Response { + return getOrgHelper(c.OrgId) +} + +// GET /api/orgs/:orgId +func GetOrgById(c *middleware.Context) Response { + return getOrgHelper(c.ParamsInt64(":orgId")) +} + +func getOrgHelper(orgId int64) Response { + query := m.GetOrgByIdQuery{Id: orgId} if err := bus.Dispatch(&query); err != nil { if err == m.ErrOrgNotFound { - c.JsonApiErr(404, "Organization not found", err) - return + return ApiError(404, "Organization not found", err) } - c.JsonApiErr(500, "Failed to get organization", err) - return + return ApiError(500, "Failed to get organization", err) } org := m.OrgDTO{ @@ -26,33 +34,41 @@ func GetOrg(c *middleware.Context) { Name: query.Result.Name, } - c.JSON(200, &org) + return Json(200, &org) } -func CreateOrg(c *middleware.Context, cmd m.CreateOrgCommand) { +// POST /api/orgs +func CreateOrg(c *middleware.Context, cmd m.CreateOrgCommand) Response { if !setting.AllowUserOrgCreate && !c.IsGrafanaAdmin { - c.JsonApiErr(401, "Access denied", nil) - return + return ApiError(401, "Access denied", nil) } cmd.UserId = c.UserId if err := bus.Dispatch(&cmd); err != nil { - c.JsonApiErr(500, "Failed to create organization", err) - return + return ApiError(500, "Failed to create organization", err) } metrics.M_Api_Org_Create.Inc(1) - c.JsonOK("Organization created") + return ApiSuccess("Organization created") } -func UpdateOrg(c *middleware.Context, cmd m.UpdateOrgCommand) { +// PUT /api/org +func UpdateOrgCurrent(c *middleware.Context, cmd m.UpdateOrgCommand) Response { cmd.OrgId = c.OrgId + return updateOrgHelper(cmd) +} +// PUT /api/orgs/:orgId +func UpdateOrg(c *middleware.Context, cmd m.UpdateOrgCommand) Response { + cmd.OrgId = c.ParamsInt64(":orgId") + return updateOrgHelper(cmd) +} + +func updateOrgHelper(cmd m.UpdateOrgCommand) Response { if err := bus.Dispatch(&cmd); err != nil { - c.JsonApiErr(500, "Failed to update organization", err) - return + return ApiError(500, "Failed to update organization", err) } - c.JsonOK("Organization updated") + return ApiSuccess("Organization updated") } diff --git a/pkg/api/org_users.go b/pkg/api/org_users.go index 8a372c791b9..c88df600450 100644 --- a/pkg/api/org_users.go +++ b/pkg/api/org_users.go @@ -6,77 +6,112 @@ import ( m "github.com/grafana/grafana/pkg/models" ) -func AddOrgUser(c *middleware.Context, cmd m.AddOrgUserCommand) { +// POST /api/org/users +func AddOrgUserToCurrentOrg(c *middleware.Context, cmd m.AddOrgUserCommand) Response { + cmd.OrgId = c.OrgId + return addOrgUserHelper(cmd) +} + +// POST /api/orgs/:orgId/users +func AddOrgUser(c *middleware.Context, cmd m.AddOrgUserCommand) Response { + cmd.OrgId = c.ParamsInt64(":orgId") + return addOrgUserHelper(cmd) +} + +func addOrgUserHelper(cmd m.AddOrgUserCommand) Response { if !cmd.Role.IsValid() { - c.JsonApiErr(400, "Invalid role specified", nil) - return + return ApiError(400, "Invalid role specified", nil) } userQuery := m.GetUserByLoginQuery{LoginOrEmail: cmd.LoginOrEmail} err := bus.Dispatch(&userQuery) if err != nil { - c.JsonApiErr(404, "User not found", nil) - return + return ApiError(404, "User not found", nil) } userToAdd := userQuery.Result - if userToAdd.Id == c.UserId { - c.JsonApiErr(400, "Cannot add yourself as user", nil) - return - } + // if userToAdd.Id == c.UserId { + // return ApiError(400, "Cannot add yourself as user", nil) + // } - cmd.OrgId = c.OrgId cmd.UserId = userToAdd.Id if err := bus.Dispatch(&cmd); err != nil { - c.JsonApiErr(500, "Could not add user to organization", err) - return + return ApiError(500, "Could not add user to organization", err) } - c.JsonOK("User added to organization") + return ApiSuccess("User added to organization") } -func GetOrgUsers(c *middleware.Context) { - query := m.GetOrgUsersQuery{OrgId: c.OrgId} +// GET /api/org/users +func GetOrgUsersForCurrentOrg(c *middleware.Context) Response { + return getOrgUsersHelper(c.OrgId) +} + +// GET /api/orgs/:orgId/users +func GetOrgUsers(c *middleware.Context) Response { + return getOrgUsersHelper(c.ParamsInt64(":orgId")) +} + +func getOrgUsersHelper(orgId int64) Response { + query := m.GetOrgUsersQuery{OrgId: orgId} if err := bus.Dispatch(&query); err != nil { - c.JsonApiErr(500, "Failed to get account user", err) - return + return ApiError(500, "Failed to get account user", err) } - c.JSON(200, query.Result) + return Json(200, query.Result) } -func UpdateOrgUser(c *middleware.Context, cmd m.UpdateOrgUserCommand) { - if !cmd.Role.IsValid() { - c.JsonApiErr(400, "Invalid role specified", nil) - return - } - - cmd.UserId = c.ParamsInt64(":id") +// PATCH /api/org/users/:userId +func UpdateOrgUserForCurrentOrg(c *middleware.Context, cmd m.UpdateOrgUserCommand) Response { cmd.OrgId = c.OrgId + cmd.UserId = c.ParamsInt64(":userId") + return updateOrgUserHelper(cmd) +} + +// PATCH /api/orgs/:orgId/users/:userId +func UpdateOrgUser(c *middleware.Context, cmd m.UpdateOrgUserCommand) Response { + cmd.OrgId = c.ParamsInt64(":orgId") + cmd.UserId = c.ParamsInt64(":userId") + return updateOrgUserHelper(cmd) +} + +func updateOrgUserHelper(cmd m.UpdateOrgUserCommand) Response { + if !cmd.Role.IsValid() { + return ApiError(400, "Invalid role specified", nil) + } if err := bus.Dispatch(&cmd); err != nil { - c.JsonApiErr(500, "Failed update org user", err) - return + return ApiError(500, "Failed update org user", err) } - c.JsonOK("Organization user updated") + return ApiSuccess("Organization user updated") } -func RemoveOrgUser(c *middleware.Context) { - userId := c.ParamsInt64(":id") +// DELETE /api/org/users/:userId +func RemoveOrgUserForCurrentOrg(c *middleware.Context) Response { + userId := c.ParamsInt64(":userId") + return removeOrgUserHelper(c.OrgId, userId) +} - cmd := m.RemoveOrgUserCommand{OrgId: c.OrgId, UserId: userId} +// DELETE /api/orgs/:orgId/users/:userId +func RemoveOrgUser(c *middleware.Context) Response { + userId := c.ParamsInt64(":userId") + orgId := c.ParamsInt64(":orgId") + return removeOrgUserHelper(orgId, userId) +} + +func removeOrgUserHelper(orgId int64, userId int64) Response { + cmd := m.RemoveOrgUserCommand{OrgId: orgId, UserId: userId} if err := bus.Dispatch(&cmd); err != nil { if err == m.ErrLastOrgAdmin { - c.JsonApiErr(400, "Cannot remove last organization admin", nil) - return + return ApiError(400, "Cannot remove last organization admin", nil) } - c.JsonApiErr(500, "Failed to remove user from organization", err) + return ApiError(500, "Failed to remove user from organization", err) } - c.JsonOK("User removed from organization") + return ApiSuccess("User removed from organization") } diff --git a/pkg/models/user.go b/pkg/models/user.go index 68e0001b99c..5efecc8deef 100644 --- a/pkg/models/user.go +++ b/pkg/models/user.go @@ -133,6 +133,7 @@ type UserProfileDTO struct { Name string `json:"name"` Login string `json:"login"` Theme string `json:"theme"` + OrgId int64 `json:"orgId"` IsGrafanaAdmin bool `json:"isGrafanaAdmin"` } diff --git a/pkg/services/sqlstore/user.go b/pkg/services/sqlstore/user.go index 9f79081783b..f5df6f9ff1f 100644 --- a/pkg/services/sqlstore/user.go +++ b/pkg/services/sqlstore/user.go @@ -236,6 +236,7 @@ func GetUserProfile(query *m.GetUserProfileQuery) error { Login: user.Login, Theme: user.Theme, IsGrafanaAdmin: user.IsAdmin, + OrgId: user.OrgId, } return err diff --git a/public/app/features/admin/partials/edit_user.html b/public/app/features/admin/partials/edit_user.html index 712aee26d5d..e72bd5b57c9 100644 --- a/public/app/features/admin/partials/edit_user.html +++ b/public/app/features/admin/partials/edit_user.html @@ -98,17 +98,26 @@ Organizations - +
+ + + + + - - - + +
NameRole
Name: {{org.name}}Role: {{org.role}} - - Current - + + {{org.name}} Current + + + + + +
- diff --git a/public/app/features/admin/partials/users.html b/public/app/features/admin/partials/users.html index 14bcd922b5e..6d4f7a8671c 100644 --- a/public/app/features/admin/partials/users.html +++ b/public/app/features/admin/partials/users.html @@ -1,4 +1,4 @@ - +