mirror of
https://github.com/grafana/grafana.git
synced 2025-07-29 22:32:24 +08:00
Lots of api refactoring for org routes, #2014
This commit is contained in:
@ -13,7 +13,7 @@ func Register(r *macaron.Macaron) {
|
|||||||
reqSignedIn := middleware.Auth(&middleware.AuthOptions{ReqSignedIn: true})
|
reqSignedIn := middleware.Auth(&middleware.AuthOptions{ReqSignedIn: true})
|
||||||
reqGrafanaAdmin := middleware.Auth(&middleware.AuthOptions{ReqSignedIn: true, ReqGrafanaAdmin: true})
|
reqGrafanaAdmin := middleware.Auth(&middleware.AuthOptions{ReqSignedIn: true, ReqGrafanaAdmin: true})
|
||||||
reqEditorRole := middleware.RoleAuth(m.ROLE_EDITOR, m.ROLE_ADMIN)
|
reqEditorRole := middleware.RoleAuth(m.ROLE_EDITOR, m.ROLE_ADMIN)
|
||||||
reqAccountAdmin := middleware.RoleAuth(m.ROLE_ADMIN)
|
regOrgAdmin := middleware.RoleAuth(m.ROLE_ADMIN)
|
||||||
bind := binding.Bind
|
bind := binding.Bind
|
||||||
|
|
||||||
// not logged in views
|
// not logged in views
|
||||||
@ -71,23 +71,34 @@ func Register(r *macaron.Macaron) {
|
|||||||
r.Put("/:id", bind(m.UpdateUserCommand{}), wrap(UpdateUser))
|
r.Put("/:id", bind(m.UpdateUserCommand{}), wrap(UpdateUser))
|
||||||
}, reqGrafanaAdmin)
|
}, reqGrafanaAdmin)
|
||||||
|
|
||||||
// account
|
// current org
|
||||||
r.Group("/org", func() {
|
r.Group("/org", func() {
|
||||||
r.Get("/", GetOrg)
|
r.Get("/", wrap(GetOrgCurrent))
|
||||||
r.Post("/", bind(m.CreateOrgCommand{}), CreateOrg)
|
r.Put("/", bind(m.UpdateOrgCommand{}), wrap(UpdateOrgCurrent))
|
||||||
r.Put("/", bind(m.UpdateOrgCommand{}), UpdateOrg)
|
r.Post("/users", bind(m.AddOrgUserCommand{}), wrap(AddOrgUserToCurrentOrg))
|
||||||
r.Post("/users", bind(m.AddOrgUserCommand{}), AddOrgUser)
|
r.Get("/users", wrap(GetOrgUsersForCurrentOrg))
|
||||||
r.Get("/users", GetOrgUsers)
|
r.Patch("/users/:userId", bind(m.UpdateOrgUserCommand{}), wrap(UpdateOrgUserForCurrentOrg))
|
||||||
r.Patch("/users/:id", bind(m.UpdateOrgUserCommand{}), UpdateOrgUser)
|
r.Delete("/users/:userId", wrap(RemoveOrgUserForCurrentOrg))
|
||||||
r.Delete("/users/:id", RemoveOrgUser)
|
}, regOrgAdmin)
|
||||||
}, reqAccountAdmin)
|
|
||||||
|
// 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
|
// auth api keys
|
||||||
r.Group("/auth/keys", func() {
|
r.Group("/auth/keys", func() {
|
||||||
r.Get("/", wrap(GetApiKeys))
|
r.Get("/", wrap(GetApiKeys))
|
||||||
r.Post("/", bind(m.AddApiKeyCommand{}), wrap(AddApiKey))
|
r.Post("/", bind(m.AddApiKeyCommand{}), wrap(AddApiKey))
|
||||||
r.Delete("/:id", wrap(DeleteApiKey))
|
r.Delete("/:id", wrap(DeleteApiKey))
|
||||||
}, reqAccountAdmin)
|
}, regOrgAdmin)
|
||||||
|
|
||||||
// Data sources
|
// Data sources
|
||||||
r.Group("/datasources", func() {
|
r.Group("/datasources", func() {
|
||||||
@ -98,7 +109,7 @@ func Register(r *macaron.Macaron) {
|
|||||||
r.Delete("/:id", DeleteDataSource)
|
r.Delete("/:id", DeleteDataSource)
|
||||||
r.Get("/:id", GetDataSourceById)
|
r.Get("/:id", GetDataSourceById)
|
||||||
r.Get("/plugins", GetDataSourcePlugins)
|
r.Get("/plugins", GetDataSourcePlugins)
|
||||||
}, reqAccountAdmin)
|
}, regOrgAdmin)
|
||||||
|
|
||||||
r.Get("/frontend/settings/", GetFrontendSettings)
|
r.Get("/frontend/settings/", GetFrontendSettings)
|
||||||
r.Any("/datasources/proxy/:id/*", reqSignedIn, ProxyDataSourceRequest)
|
r.Any("/datasources/proxy/:id/*", reqSignedIn, ProxyDataSourceRequest)
|
||||||
|
@ -8,17 +8,25 @@ import (
|
|||||||
"github.com/grafana/grafana/pkg/setting"
|
"github.com/grafana/grafana/pkg/setting"
|
||||||
)
|
)
|
||||||
|
|
||||||
func GetOrg(c *middleware.Context) {
|
// GET /api/org
|
||||||
query := m.GetOrgByIdQuery{Id: c.OrgId}
|
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 := bus.Dispatch(&query); err != nil {
|
||||||
if err == m.ErrOrgNotFound {
|
if err == m.ErrOrgNotFound {
|
||||||
c.JsonApiErr(404, "Organization not found", err)
|
return ApiError(404, "Organization not found", err)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
c.JsonApiErr(500, "Failed to get organization", err)
|
return ApiError(500, "Failed to get organization", err)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
org := m.OrgDTO{
|
org := m.OrgDTO{
|
||||||
@ -26,33 +34,41 @@ func GetOrg(c *middleware.Context) {
|
|||||||
Name: query.Result.Name,
|
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 {
|
if !setting.AllowUserOrgCreate && !c.IsGrafanaAdmin {
|
||||||
c.JsonApiErr(401, "Access denied", nil)
|
return ApiError(401, "Access denied", nil)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd.UserId = c.UserId
|
cmd.UserId = c.UserId
|
||||||
if err := bus.Dispatch(&cmd); err != nil {
|
if err := bus.Dispatch(&cmd); err != nil {
|
||||||
c.JsonApiErr(500, "Failed to create organization", err)
|
return ApiError(500, "Failed to create organization", err)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
metrics.M_Api_Org_Create.Inc(1)
|
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
|
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 {
|
if err := bus.Dispatch(&cmd); err != nil {
|
||||||
c.JsonApiErr(500, "Failed to update organization", err)
|
return ApiError(500, "Failed to update organization", err)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
c.JsonOK("Organization updated")
|
return ApiSuccess("Organization updated")
|
||||||
}
|
}
|
||||||
|
@ -6,77 +6,112 @@ import (
|
|||||||
m "github.com/grafana/grafana/pkg/models"
|
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() {
|
if !cmd.Role.IsValid() {
|
||||||
c.JsonApiErr(400, "Invalid role specified", nil)
|
return ApiError(400, "Invalid role specified", nil)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
userQuery := m.GetUserByLoginQuery{LoginOrEmail: cmd.LoginOrEmail}
|
userQuery := m.GetUserByLoginQuery{LoginOrEmail: cmd.LoginOrEmail}
|
||||||
err := bus.Dispatch(&userQuery)
|
err := bus.Dispatch(&userQuery)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.JsonApiErr(404, "User not found", nil)
|
return ApiError(404, "User not found", nil)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
userToAdd := userQuery.Result
|
userToAdd := userQuery.Result
|
||||||
|
|
||||||
if userToAdd.Id == c.UserId {
|
// if userToAdd.Id == c.UserId {
|
||||||
c.JsonApiErr(400, "Cannot add yourself as user", nil)
|
// return ApiError(400, "Cannot add yourself as user", nil)
|
||||||
return
|
// }
|
||||||
}
|
|
||||||
|
|
||||||
cmd.OrgId = c.OrgId
|
|
||||||
cmd.UserId = userToAdd.Id
|
cmd.UserId = userToAdd.Id
|
||||||
|
|
||||||
if err := bus.Dispatch(&cmd); err != nil {
|
if err := bus.Dispatch(&cmd); err != nil {
|
||||||
c.JsonApiErr(500, "Could not add user to organization", err)
|
return ApiError(500, "Could not add user to organization", err)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
c.JsonOK("User added to organization")
|
return ApiSuccess("User added to organization")
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetOrgUsers(c *middleware.Context) {
|
// GET /api/org/users
|
||||||
query := m.GetOrgUsersQuery{OrgId: c.OrgId}
|
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 {
|
if err := bus.Dispatch(&query); err != nil {
|
||||||
c.JsonApiErr(500, "Failed to get account user", err)
|
return ApiError(500, "Failed to get account user", err)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
c.JSON(200, query.Result)
|
return Json(200, query.Result)
|
||||||
}
|
}
|
||||||
|
|
||||||
func UpdateOrgUser(c *middleware.Context, cmd m.UpdateOrgUserCommand) {
|
// PATCH /api/org/users/:userId
|
||||||
if !cmd.Role.IsValid() {
|
func UpdateOrgUserForCurrentOrg(c *middleware.Context, cmd m.UpdateOrgUserCommand) Response {
|
||||||
c.JsonApiErr(400, "Invalid role specified", nil)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
cmd.UserId = c.ParamsInt64(":id")
|
|
||||||
cmd.OrgId = c.OrgId
|
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 {
|
if err := bus.Dispatch(&cmd); err != nil {
|
||||||
c.JsonApiErr(500, "Failed update org user", err)
|
return ApiError(500, "Failed update org user", err)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
c.JsonOK("Organization user updated")
|
return ApiSuccess("Organization user updated")
|
||||||
}
|
}
|
||||||
|
|
||||||
func RemoveOrgUser(c *middleware.Context) {
|
// DELETE /api/org/users/:userId
|
||||||
userId := c.ParamsInt64(":id")
|
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 := bus.Dispatch(&cmd); err != nil {
|
||||||
if err == m.ErrLastOrgAdmin {
|
if err == m.ErrLastOrgAdmin {
|
||||||
c.JsonApiErr(400, "Cannot remove last organization admin", nil)
|
return ApiError(400, "Cannot remove last organization admin", nil)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
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")
|
||||||
}
|
}
|
||||||
|
@ -133,6 +133,7 @@ type UserProfileDTO struct {
|
|||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Login string `json:"login"`
|
Login string `json:"login"`
|
||||||
Theme string `json:"theme"`
|
Theme string `json:"theme"`
|
||||||
|
OrgId int64 `json:"orgId"`
|
||||||
IsGrafanaAdmin bool `json:"isGrafanaAdmin"`
|
IsGrafanaAdmin bool `json:"isGrafanaAdmin"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -236,6 +236,7 @@ func GetUserProfile(query *m.GetUserProfileQuery) error {
|
|||||||
Login: user.Login,
|
Login: user.Login,
|
||||||
Theme: user.Theme,
|
Theme: user.Theme,
|
||||||
IsGrafanaAdmin: user.IsAdmin,
|
IsGrafanaAdmin: user.IsAdmin,
|
||||||
|
OrgId: user.OrgId,
|
||||||
}
|
}
|
||||||
|
|
||||||
return err
|
return err
|
||||||
|
@ -98,17 +98,26 @@
|
|||||||
Organizations
|
Organizations
|
||||||
</h2>
|
</h2>
|
||||||
|
|
||||||
<table class="grafana-options-table">
|
<table class="grafana-options-table form-inline">
|
||||||
|
<tr>
|
||||||
|
<th>Name</th>
|
||||||
|
<th>Role</th>
|
||||||
|
<th></th>
|
||||||
|
</tr>
|
||||||
<tr ng-repeat="org in orgs">
|
<tr ng-repeat="org in orgs">
|
||||||
<td style="width: 98%"><strong>Name: </strong> {{org.name}}</td>
|
<td>
|
||||||
<td><strong>Role: </strong> {{org.role}}</td>
|
{{org.name}} <span class="label label-info" ng-show="org.orgId === user.orgId">Current</span>
|
||||||
<td class="nobg max-width-btns">
|
</td>
|
||||||
<span class="label label-info" ng-show="org.orgId === user.orgId">
|
<td>
|
||||||
Current
|
<select type="text" ng-model="org.role" class="input-small" ng-options="f for f in ['Viewer', 'Editor', 'Admin']" ng-change="updateOrgRole(org)">
|
||||||
</span>
|
</select>
|
||||||
|
</td>
|
||||||
|
<td style="width: 1%">
|
||||||
|
<a ng-click="removeUser(user)" class="btn btn-danger btn-mini">
|
||||||
|
<i class="fa fa-remove"></i>
|
||||||
|
</a>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
<topnav icon="fa fa-fw fa-user" title="Global users" subnav="true">
|
<topnav icon="fa fa-fw fa-user" title="Global Users" subnav="true">
|
||||||
<ul class="nav">
|
<ul class="nav">
|
||||||
<li class="active"><a href="admin/users">Overview</a></li>
|
<li class="active"><a href="admin/users">Overview</a></li>
|
||||||
<li><a href="admin/users/create">Create user</a></li>
|
<li><a href="admin/users/create">Create user</a></li>
|
||||||
|
@ -11,7 +11,7 @@ function (angular) {
|
|||||||
$scope.newOrg = {name: ''};
|
$scope.newOrg = {name: ''};
|
||||||
|
|
||||||
$scope.createOrg = function() {
|
$scope.createOrg = function() {
|
||||||
backendSrv.post('/api/org/', $scope.newOrg).then($scope.getUserOrgs);
|
backendSrv.post('/api/orgs/', $scope.newOrg).then($scope.getUserOrgs);
|
||||||
};
|
};
|
||||||
|
|
||||||
});
|
});
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
<div class="page-container">
|
<div class="page-container">
|
||||||
<div class="page">
|
<div class="page">
|
||||||
|
|
||||||
<h2>Account users</h2>
|
<h2>Organization users</h2>
|
||||||
|
|
||||||
<form name="form">
|
<form name="form">
|
||||||
<div class="tight-form">
|
<div class="tight-form">
|
||||||
|
@ -57,8 +57,6 @@ function (_) {
|
|||||||
p._buildQuery = function() {
|
p._buildQuery = function() {
|
||||||
var target = this.target;
|
var target = this.target;
|
||||||
|
|
||||||
console.log('Build Query: target = ', target);
|
|
||||||
|
|
||||||
if (!target.measurement) {
|
if (!target.measurement) {
|
||||||
throw "Metric measurement is missing";
|
throw "Metric measurement is missing";
|
||||||
}
|
}
|
||||||
|
@ -48,15 +48,14 @@ define([
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('series with groupByTag', function() {
|
describe('series with groupByTag', function() {
|
||||||
var builder = new InfluxQueryBuilder({
|
|
||||||
measurement: 'cpu',
|
|
||||||
tags: [],
|
|
||||||
groupByTags: ["host"]
|
|
||||||
});
|
|
||||||
|
|
||||||
var query = builder.build();
|
|
||||||
|
|
||||||
it('should generate correct query', function() {
|
it('should generate correct query', function() {
|
||||||
|
var builder = new InfluxQueryBuilder({
|
||||||
|
measurement: 'cpu',
|
||||||
|
tags: [],
|
||||||
|
groupByTags: ["host"]
|
||||||
|
});
|
||||||
|
|
||||||
|
var query = builder.build();
|
||||||
expect(query).to.be('SELECT mean(value) FROM "cpu" WHERE $timeFilter ' +
|
expect(query).to.be('SELECT mean(value) FROM "cpu" WHERE $timeFilter ' +
|
||||||
'GROUP BY time($interval), host ORDER BY asc');
|
'GROUP BY time($interval), host ORDER BY asc');
|
||||||
});
|
});
|
||||||
|
Reference in New Issue
Block a user