Commit 05cc1f85 by Torkel Ödegaard

Merge branch 'refactor-user-group-to-team' of…

Merge branch 'refactor-user-group-to-team' of https://github.com/alexanderzobnin/grafana into user-group-to-team
parents 10fbfcb1 26281dd9
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
### WIP (in develop branch currently as its unstable or unfinished) ### WIP (in develop branch currently as its unstable or unfinished)
- Dashboard folders - Dashboard folders
- User groups - Teams
- Dashboard permissions (on folder & dashboard level), permissions can be assigned to groups or individual users - Dashboard permissions (on folder & dashboard level), permissions can be assigned to groups or individual users
- UX changes to nav & side menu - UX changes to nav & side menu
- New dashboard grid layout system - New dashboard grid layout system
......
...@@ -6,7 +6,7 @@ But it will give you an idea of our current vision and plan. ...@@ -6,7 +6,7 @@ But it will give you an idea of our current vision and plan.
### Short term (1-4 months) ### Short term (1-4 months)
- Release Grafana v5 - Release Grafana v5
- User groups - Teams
- Dashboard folders - Dashboard folders
- Dashboard & folder permissions (assigned to users or groups) - Dashboard & folder permissions (assigned to users or groups)
- New Dashboard layout engine - New Dashboard layout engine
......
...@@ -135,16 +135,16 @@ func (hs *HttpServer) registerRoutes() { ...@@ -135,16 +135,16 @@ func (hs *HttpServer) registerRoutes() {
usersRoute.Post("/:id/using/:orgId", wrap(UpdateUserActiveOrg)) usersRoute.Post("/:id/using/:orgId", wrap(UpdateUserActiveOrg))
}, reqGrafanaAdmin) }, reqGrafanaAdmin)
// user group (admin permission required) // team (admin permission required)
apiRoute.Group("/user-groups", func(userGroupsRoute RouteRegister) { apiRoute.Group("/teams", func(teamsRoute RouteRegister) {
userGroupsRoute.Get("/:userGroupId", wrap(GetUserGroupById)) teamsRoute.Get("/:teamId", wrap(GetTeamById))
userGroupsRoute.Get("/search", wrap(SearchUserGroups)) teamsRoute.Get("/search", wrap(SearchTeams))
userGroupsRoute.Post("/", quota("user-groups"), bind(m.CreateUserGroupCommand{}), wrap(CreateUserGroup)) teamsRoute.Post("/", quota("teams"), bind(m.CreateTeamCommand{}), wrap(CreateTeam))
userGroupsRoute.Put("/:userGroupId", bind(m.UpdateUserGroupCommand{}), wrap(UpdateUserGroup)) teamsRoute.Put("/:teamId", bind(m.UpdateTeamCommand{}), wrap(UpdateTeam))
userGroupsRoute.Delete("/:userGroupId", wrap(DeleteUserGroupById)) teamsRoute.Delete("/:teamId", wrap(DeleteTeamById))
userGroupsRoute.Get("/:userGroupId/members", wrap(GetUserGroupMembers)) teamsRoute.Get("/:teamId/members", wrap(GetTeamMembers))
userGroupsRoute.Post("/:userGroupId/members", quota("user-groups"), bind(m.AddUserGroupMemberCommand{}), wrap(AddUserGroupMember)) teamsRoute.Post("/:teamId/members", quota("teams"), bind(m.AddTeamMemberCommand{}), wrap(AddTeamMember))
userGroupsRoute.Delete("/:userGroupId/members/:userId", wrap(RemoveUserGroupMember)) teamsRoute.Delete("/:teamId/members/:userId", wrap(RemoveTeamMember))
}, reqOrgAdmin) }, reqOrgAdmin)
// org information available to all users. // org information available to all users.
......
...@@ -43,7 +43,7 @@ func UpdateDashboardAcl(c *middleware.Context, apiCmd dtos.UpdateDashboardAclCom ...@@ -43,7 +43,7 @@ func UpdateDashboardAcl(c *middleware.Context, apiCmd dtos.UpdateDashboardAclCom
OrgId: c.OrgId, OrgId: c.OrgId,
DashboardId: dashId, DashboardId: dashId,
UserId: item.UserId, UserId: item.UserId,
UserGroupId: item.UserGroupId, TeamId: item.TeamId,
Role: item.Role, Role: item.Role,
Permission: item.Permission, Permission: item.Permission,
Created: time.Now(), Created: time.Now(),
......
...@@ -16,8 +16,8 @@ func TestDashboardAclApiEndpoint(t *testing.T) { ...@@ -16,8 +16,8 @@ func TestDashboardAclApiEndpoint(t *testing.T) {
{Id: 1, OrgId: 1, DashboardId: 1, UserId: 2, Permission: m.PERMISSION_VIEW}, {Id: 1, OrgId: 1, DashboardId: 1, UserId: 2, Permission: m.PERMISSION_VIEW},
{Id: 2, OrgId: 1, DashboardId: 1, UserId: 3, Permission: m.PERMISSION_EDIT}, {Id: 2, OrgId: 1, DashboardId: 1, UserId: 3, Permission: m.PERMISSION_EDIT},
{Id: 3, OrgId: 1, DashboardId: 1, UserId: 4, Permission: m.PERMISSION_ADMIN}, {Id: 3, OrgId: 1, DashboardId: 1, UserId: 4, Permission: m.PERMISSION_ADMIN},
{Id: 4, OrgId: 1, DashboardId: 1, UserGroupId: 1, Permission: m.PERMISSION_VIEW}, {Id: 4, OrgId: 1, DashboardId: 1, TeamId: 1, Permission: m.PERMISSION_VIEW},
{Id: 5, OrgId: 1, DashboardId: 1, UserGroupId: 2, Permission: m.PERMISSION_ADMIN}, {Id: 5, OrgId: 1, DashboardId: 1, TeamId: 2, Permission: m.PERMISSION_ADMIN},
} }
dtoRes := transformDashboardAclsToDTOs(mockResult) dtoRes := transformDashboardAclsToDTOs(mockResult)
...@@ -31,9 +31,9 @@ func TestDashboardAclApiEndpoint(t *testing.T) { ...@@ -31,9 +31,9 @@ func TestDashboardAclApiEndpoint(t *testing.T) {
return nil return nil
}) })
userGroupResp := []*m.UserGroup{} teamResp := []*m.Team{}
bus.AddHandler("test", func(query *m.GetUserGroupsByUserQuery) error { bus.AddHandler("test", func(query *m.GetTeamsByUserQuery) error {
query.Result = userGroupResp query.Result = teamResp
return nil return nil
}) })
...@@ -81,9 +81,9 @@ func TestDashboardAclApiEndpoint(t *testing.T) { ...@@ -81,9 +81,9 @@ func TestDashboardAclApiEndpoint(t *testing.T) {
}) })
}) })
Convey("When user is a member of a user group in the ACL with admin permission", func() { Convey("When user is a member of a team in the ACL with admin permission", func() {
loggedInUserScenarioWithRole("When calling DELETE on", "DELETE", "/api/dashboards/id/1/acl/1", "/api/dashboards/id/:dashboardsId/acl/:aclId", m.ROLE_EDITOR, func(sc *scenarioContext) { loggedInUserScenarioWithRole("When calling DELETE on", "DELETE", "/api/dashboards/id/1/acl/1", "/api/dashboards/id/:dashboardsId/acl/:aclId", m.ROLE_EDITOR, func(sc *scenarioContext) {
userGroupResp = append(userGroupResp, &m.UserGroup{Id: 2, OrgId: 1, Name: "UG2"}) teamResp = append(teamResp, &m.Team{Id: 2, OrgId: 1, Name: "UG2"})
bus.AddHandler("test3", func(cmd *m.RemoveDashboardAclCommand) error { bus.AddHandler("test3", func(cmd *m.RemoveDashboardAclCommand) error {
return nil return nil
...@@ -165,7 +165,7 @@ func transformDashboardAclsToDTOs(acls []*m.DashboardAclInfoDTO) []*m.DashboardA ...@@ -165,7 +165,7 @@ func transformDashboardAclsToDTOs(acls []*m.DashboardAclInfoDTO) []*m.DashboardA
DashboardId: acl.DashboardId, DashboardId: acl.DashboardId,
Permission: acl.Permission, Permission: acl.Permission,
UserId: acl.UserId, UserId: acl.UserId,
UserGroupId: acl.UserGroupId, TeamId: acl.TeamId,
} }
dtos = append(dtos, dto) dtos = append(dtos, dto)
} }
......
...@@ -56,8 +56,8 @@ func TestDashboardApiEndpoint(t *testing.T) { ...@@ -56,8 +56,8 @@ func TestDashboardApiEndpoint(t *testing.T) {
return nil return nil
}) })
bus.AddHandler("test", func(query *m.GetUserGroupsByUserQuery) error { bus.AddHandler("test", func(query *m.GetTeamsByUserQuery) error {
query.Result = []*m.UserGroup{} query.Result = []*m.Team{}
return nil return nil
}) })
...@@ -217,8 +217,8 @@ func TestDashboardApiEndpoint(t *testing.T) { ...@@ -217,8 +217,8 @@ func TestDashboardApiEndpoint(t *testing.T) {
return nil return nil
}) })
bus.AddHandler("test", func(query *m.GetUserGroupsByUserQuery) error { bus.AddHandler("test", func(query *m.GetTeamsByUserQuery) error {
query.Result = []*m.UserGroup{} query.Result = []*m.Team{}
return nil return nil
}) })
......
...@@ -10,7 +10,7 @@ type UpdateDashboardAclCommand struct { ...@@ -10,7 +10,7 @@ type UpdateDashboardAclCommand struct {
type DashboardAclUpdateItem struct { type DashboardAclUpdateItem struct {
UserId int64 `json:"userId"` UserId int64 `json:"userId"`
UserGroupId int64 `json:"userGroupId"` TeamId int64 `json:"teamId"`
Role *m.RoleType `json:"role,omitempty"` Role *m.RoleType `json:"role,omitempty"`
Permission m.PermissionType `json:"permission"` Permission m.PermissionType `json:"permission"`
} }
...@@ -231,8 +231,8 @@ func setIndexViewData(c *middleware.Context) (*dtos.IndexViewData, error) { ...@@ -231,8 +231,8 @@ func setIndexViewData(c *middleware.Context) (*dtos.IndexViewData, error) {
Text: "Teams", Text: "Teams",
Id: "teams", Id: "teams",
Description: "Manage org groups", Description: "Manage org groups",
Icon: "gicon gicon-user-group", Icon: "gicon gicon-team",
Url: setting.AppSubUrl + "/org/user-groups", Url: setting.AppSubUrl + "/org/teams",
}, },
{ {
Text: "Plugins", Text: "Plugins",
......
...@@ -7,48 +7,48 @@ import ( ...@@ -7,48 +7,48 @@ import (
"github.com/grafana/grafana/pkg/util" "github.com/grafana/grafana/pkg/util"
) )
// POST /api/user-groups // POST /api/teams
func CreateUserGroup(c *middleware.Context, cmd m.CreateUserGroupCommand) Response { func CreateTeam(c *middleware.Context, cmd m.CreateTeamCommand) Response {
cmd.OrgId = c.OrgId cmd.OrgId = c.OrgId
if err := bus.Dispatch(&cmd); err != nil { if err := bus.Dispatch(&cmd); err != nil {
if err == m.ErrUserGroupNameTaken { if err == m.ErrTeamNameTaken {
return ApiError(409, "User Group name taken", err) return ApiError(409, "Team name taken", err)
} }
return ApiError(500, "Failed to create User Group", err) return ApiError(500, "Failed to create Team", err)
} }
return Json(200, &util.DynMap{ return Json(200, &util.DynMap{
"userGroupId": cmd.Result.Id, "teamId": cmd.Result.Id,
"message": "User Group created", "message": "Team created",
}) })
} }
// PUT /api/user-groups/:userGroupId // PUT /api/teams/:teamId
func UpdateUserGroup(c *middleware.Context, cmd m.UpdateUserGroupCommand) Response { func UpdateTeam(c *middleware.Context, cmd m.UpdateTeamCommand) Response {
cmd.Id = c.ParamsInt64(":userGroupId") cmd.Id = c.ParamsInt64(":teamId")
if err := bus.Dispatch(&cmd); err != nil { if err := bus.Dispatch(&cmd); err != nil {
if err == m.ErrUserGroupNameTaken { if err == m.ErrTeamNameTaken {
return ApiError(400, "User Group name taken", err) return ApiError(400, "Team name taken", err)
} }
return ApiError(500, "Failed to update User Group", err) return ApiError(500, "Failed to update Team", err)
} }
return ApiSuccess("User Group updated") return ApiSuccess("Team updated")
} }
// DELETE /api/user-groups/:userGroupId // DELETE /api/teams/:teamId
func DeleteUserGroupById(c *middleware.Context) Response { func DeleteTeamById(c *middleware.Context) Response {
if err := bus.Dispatch(&m.DeleteUserGroupCommand{Id: c.ParamsInt64(":userGroupId")}); err != nil { if err := bus.Dispatch(&m.DeleteTeamCommand{Id: c.ParamsInt64(":teamId")}); err != nil {
if err == m.ErrUserGroupNotFound { if err == m.ErrTeamNotFound {
return ApiError(404, "Failed to delete User Group. ID not found", nil) return ApiError(404, "Failed to delete Team. ID not found", nil)
} }
return ApiError(500, "Failed to update User Group", err) return ApiError(500, "Failed to update Team", err)
} }
return ApiSuccess("User Group deleted") return ApiSuccess("Team deleted")
} }
// GET /api/user-groups/search // GET /api/teams/search
func SearchUserGroups(c *middleware.Context) Response { func SearchTeams(c *middleware.Context) Response {
perPage := c.QueryInt("perpage") perPage := c.QueryInt("perpage")
if perPage <= 0 { if perPage <= 0 {
perPage = 1000 perPage = 1000
...@@ -58,7 +58,7 @@ func SearchUserGroups(c *middleware.Context) Response { ...@@ -58,7 +58,7 @@ func SearchUserGroups(c *middleware.Context) Response {
page = 1 page = 1
} }
query := m.SearchUserGroupsQuery{ query := m.SearchTeamsQuery{
Query: c.Query("query"), Query: c.Query("query"),
Name: c.Query("name"), Name: c.Query("name"),
Page: page, Page: page,
...@@ -67,7 +67,7 @@ func SearchUserGroups(c *middleware.Context) Response { ...@@ -67,7 +67,7 @@ func SearchUserGroups(c *middleware.Context) Response {
} }
if err := bus.Dispatch(&query); err != nil { if err := bus.Dispatch(&query); err != nil {
return ApiError(500, "Failed to search User Groups", err) return ApiError(500, "Failed to search Teams", err)
} }
query.Result.Page = page query.Result.Page = page
...@@ -76,16 +76,16 @@ func SearchUserGroups(c *middleware.Context) Response { ...@@ -76,16 +76,16 @@ func SearchUserGroups(c *middleware.Context) Response {
return Json(200, query.Result) return Json(200, query.Result)
} }
// GET /api/user-groups/:userGroupId // GET /api/teams/:teamId
func GetUserGroupById(c *middleware.Context) Response { func GetTeamById(c *middleware.Context) Response {
query := m.GetUserGroupByIdQuery{Id: c.ParamsInt64(":userGroupId")} query := m.GetTeamByIdQuery{Id: c.ParamsInt64(":teamId")}
if err := bus.Dispatch(&query); err != nil { if err := bus.Dispatch(&query); err != nil {
if err == m.ErrUserGroupNotFound { if err == m.ErrTeamNotFound {
return ApiError(404, "User Group not found", err) return ApiError(404, "Team not found", err)
} }
return ApiError(500, "Failed to get User Group", err) return ApiError(500, "Failed to get Team", err)
} }
return Json(200, &query.Result) return Json(200, &query.Result)
......
...@@ -7,38 +7,38 @@ import ( ...@@ -7,38 +7,38 @@ import (
"github.com/grafana/grafana/pkg/util" "github.com/grafana/grafana/pkg/util"
) )
// GET /api/user-groups/:userGroupId/members // GET /api/teams/:teamId/members
func GetUserGroupMembers(c *middleware.Context) Response { func GetTeamMembers(c *middleware.Context) Response {
query := m.GetUserGroupMembersQuery{UserGroupId: c.ParamsInt64(":userGroupId")} query := m.GetTeamMembersQuery{TeamId: c.ParamsInt64(":teamId")}
if err := bus.Dispatch(&query); err != nil { if err := bus.Dispatch(&query); err != nil {
return ApiError(500, "Failed to get User Group Members", err) return ApiError(500, "Failed to get Team Members", err)
} }
return Json(200, query.Result) return Json(200, query.Result)
} }
// POST /api/user-groups/:userGroupId/members // POST /api/teams/:teamId/members
func AddUserGroupMember(c *middleware.Context, cmd m.AddUserGroupMemberCommand) Response { func AddTeamMember(c *middleware.Context, cmd m.AddTeamMemberCommand) Response {
cmd.UserGroupId = c.ParamsInt64(":userGroupId") cmd.TeamId = c.ParamsInt64(":teamId")
cmd.OrgId = c.OrgId cmd.OrgId = c.OrgId
if err := bus.Dispatch(&cmd); err != nil { if err := bus.Dispatch(&cmd); err != nil {
if err == m.ErrUserGroupMemberAlreadyAdded { if err == m.ErrTeamMemberAlreadyAdded {
return ApiError(400, "User is already added to this user group", err) return ApiError(400, "User is already added to this team", err)
} }
return ApiError(500, "Failed to add Member to User Group", err) return ApiError(500, "Failed to add Member to Team", err)
} }
return Json(200, &util.DynMap{ return Json(200, &util.DynMap{
"message": "Member added to User Group", "message": "Member added to Team",
}) })
} }
// DELETE /api/user-groups/:userGroupId/members/:userId // DELETE /api/teams/:teamId/members/:userId
func RemoveUserGroupMember(c *middleware.Context) Response { func RemoveTeamMember(c *middleware.Context) Response {
if err := bus.Dispatch(&m.RemoveUserGroupMemberCommand{UserGroupId: c.ParamsInt64(":userGroupId"), UserId: c.ParamsInt64(":userId")}); err != nil { if err := bus.Dispatch(&m.RemoveTeamMemberCommand{TeamId: c.ParamsInt64(":teamId"), UserId: c.ParamsInt64(":userId")}); err != nil {
return ApiError(500, "Failed to remove Member from User Group", err) return ApiError(500, "Failed to remove Member from Team", err)
} }
return ApiSuccess("User Group Member removed") return ApiSuccess("Team Member removed")
} }
...@@ -10,21 +10,21 @@ import ( ...@@ -10,21 +10,21 @@ import (
. "github.com/smartystreets/goconvey/convey" . "github.com/smartystreets/goconvey/convey"
) )
func TestUserGroupApiEndpoint(t *testing.T) { func TestTeamApiEndpoint(t *testing.T) {
Convey("Given two user groups", t, func() { Convey("Given two teams", t, func() {
mockResult := models.SearchUserGroupQueryResult{ mockResult := models.SearchTeamQueryResult{
UserGroups: []*models.UserGroup{ Teams: []*models.Team{
{Name: "userGroup1"}, {Name: "team1"},
{Name: "userGroup2"}, {Name: "team2"},
}, },
TotalCount: 2, TotalCount: 2,
} }
Convey("When searching with no parameters", func() { Convey("When searching with no parameters", func() {
loggedInUserScenario("When calling GET on", "/api/user-groups/search", func(sc *scenarioContext) { loggedInUserScenario("When calling GET on", "/api/teams/search", func(sc *scenarioContext) {
var sentLimit int var sentLimit int
var sendPage int var sendPage int
bus.AddHandler("test", func(query *models.SearchUserGroupsQuery) error { bus.AddHandler("test", func(query *models.SearchTeamsQuery) error {
query.Result = mockResult query.Result = mockResult
sentLimit = query.Limit sentLimit = query.Limit
...@@ -33,7 +33,7 @@ func TestUserGroupApiEndpoint(t *testing.T) { ...@@ -33,7 +33,7 @@ func TestUserGroupApiEndpoint(t *testing.T) {
return nil return nil
}) })
sc.handlerFunc = SearchUserGroups sc.handlerFunc = SearchTeams
sc.fakeReqWithParams("GET", sc.url, map[string]string{}).exec() sc.fakeReqWithParams("GET", sc.url, map[string]string{}).exec()
So(sentLimit, ShouldEqual, 1000) So(sentLimit, ShouldEqual, 1000)
...@@ -43,15 +43,15 @@ func TestUserGroupApiEndpoint(t *testing.T) { ...@@ -43,15 +43,15 @@ func TestUserGroupApiEndpoint(t *testing.T) {
So(err, ShouldBeNil) So(err, ShouldBeNil)
So(respJSON.Get("totalCount").MustInt(), ShouldEqual, 2) So(respJSON.Get("totalCount").MustInt(), ShouldEqual, 2)
So(len(respJSON.Get("userGroups").MustArray()), ShouldEqual, 2) So(len(respJSON.Get("teams").MustArray()), ShouldEqual, 2)
}) })
}) })
Convey("When searching with page and perpage parameters", func() { Convey("When searching with page and perpage parameters", func() {
loggedInUserScenario("When calling GET on", "/api/user-groups/search", func(sc *scenarioContext) { loggedInUserScenario("When calling GET on", "/api/teams/search", func(sc *scenarioContext) {
var sentLimit int var sentLimit int
var sendPage int var sendPage int
bus.AddHandler("test", func(query *models.SearchUserGroupsQuery) error { bus.AddHandler("test", func(query *models.SearchTeamsQuery) error {
query.Result = mockResult query.Result = mockResult
sentLimit = query.Limit sentLimit = query.Limit
...@@ -60,7 +60,7 @@ func TestUserGroupApiEndpoint(t *testing.T) { ...@@ -60,7 +60,7 @@ func TestUserGroupApiEndpoint(t *testing.T) {
return nil return nil
}) })
sc.handlerFunc = SearchUserGroups sc.handlerFunc = SearchTeams
sc.fakeReqWithParams("GET", sc.url, map[string]string{"perpage": "10", "page": "2"}).exec() sc.fakeReqWithParams("GET", sc.url, map[string]string{"perpage": "10", "page": "2"}).exec()
So(sentLimit, ShouldEqual, 10) So(sentLimit, ShouldEqual, 10)
......
...@@ -24,7 +24,7 @@ func (p PermissionType) String() string { ...@@ -24,7 +24,7 @@ func (p PermissionType) String() string {
// Typed errors // Typed errors
var ( var (
ErrDashboardAclInfoMissing = errors.New("User id and user group id cannot both be empty for a dashboard permission.") ErrDashboardAclInfoMissing = errors.New("User id and team id cannot both be empty for a dashboard permission.")
ErrDashboardPermissionDashboardEmpty = errors.New("Dashboard Id must be greater than zero for a dashboard permission.") ErrDashboardPermissionDashboardEmpty = errors.New("Dashboard Id must be greater than zero for a dashboard permission.")
) )
...@@ -35,7 +35,7 @@ type DashboardAcl struct { ...@@ -35,7 +35,7 @@ type DashboardAcl struct {
DashboardId int64 DashboardId int64
UserId int64 UserId int64
UserGroupId int64 TeamId int64
Role *RoleType // pointer to be nullable Role *RoleType // pointer to be nullable
Permission PermissionType Permission PermissionType
...@@ -54,8 +54,8 @@ type DashboardAclInfoDTO struct { ...@@ -54,8 +54,8 @@ type DashboardAclInfoDTO struct {
UserId int64 `json:"userId"` UserId int64 `json:"userId"`
UserLogin string `json:"userLogin"` UserLogin string `json:"userLogin"`
UserEmail string `json:"userEmail"` UserEmail string `json:"userEmail"`
UserGroupId int64 `json:"userGroupId"` TeamId int64 `json:"teamId"`
UserGroup string `json:"userGroup"` Team string `json:"team"`
Role *RoleType `json:"role,omitempty"` Role *RoleType `json:"role,omitempty"`
Permission PermissionType `json:"permission"` Permission PermissionType `json:"permission"`
PermissionName string `json:"permissionName"` PermissionName string `json:"permissionName"`
...@@ -74,7 +74,7 @@ type SetDashboardAclCommand struct { ...@@ -74,7 +74,7 @@ type SetDashboardAclCommand struct {
DashboardId int64 DashboardId int64
OrgId int64 OrgId int64
UserId int64 UserId int64
UserGroupId int64 TeamId int64
Permission PermissionType Permission PermissionType
Result DashboardAcl Result DashboardAcl
......
...@@ -7,12 +7,12 @@ import ( ...@@ -7,12 +7,12 @@ import (
// Typed errors // Typed errors
var ( var (
ErrUserGroupNotFound = errors.New("User Group not found") ErrTeamNotFound = errors.New("Team not found")
ErrUserGroupNameTaken = errors.New("User Group name is taken") ErrTeamNameTaken = errors.New("Team name is taken")
) )
// UserGroup model // Team model
type UserGroup struct { type Team struct {
Id int64 `json:"id"` Id int64 `json:"id"`
OrgId int64 `json:"orgId"` OrgId int64 `json:"orgId"`
Name string `json:"name"` Name string `json:"name"`
...@@ -24,45 +24,45 @@ type UserGroup struct { ...@@ -24,45 +24,45 @@ type UserGroup struct {
// --------------------- // ---------------------
// COMMANDS // COMMANDS
type CreateUserGroupCommand struct { type CreateTeamCommand struct {
Name string `json:"name" binding:"Required"` Name string `json:"name" binding:"Required"`
OrgId int64 `json:"-"` OrgId int64 `json:"-"`
Result UserGroup `json:"-"` Result Team `json:"-"`
} }
type UpdateUserGroupCommand struct { type UpdateTeamCommand struct {
Id int64 Id int64
Name string Name string
} }
type DeleteUserGroupCommand struct { type DeleteTeamCommand struct {
Id int64 Id int64
} }
type GetUserGroupByIdQuery struct { type GetTeamByIdQuery struct {
Id int64 Id int64
Result *UserGroup Result *Team
} }
type GetUserGroupsByUserQuery struct { type GetTeamsByUserQuery struct {
UserId int64 `json:"userId"` UserId int64 `json:"userId"`
Result []*UserGroup `json:"userGroups"` Result []*Team `json:"teams"`
} }
type SearchUserGroupsQuery struct { type SearchTeamsQuery struct {
Query string Query string
Name string Name string
Limit int Limit int
Page int Page int
OrgId int64 OrgId int64
Result SearchUserGroupQueryResult Result SearchTeamQueryResult
} }
type SearchUserGroupQueryResult struct { type SearchTeamQueryResult struct {
TotalCount int64 `json:"totalCount"` TotalCount int64 `json:"totalCount"`
UserGroups []*UserGroup `json:"userGroups"` Teams []*Team `json:"teams"`
Page int `json:"page"` Page int `json:"page"`
PerPage int `json:"perPage"` PerPage int `json:"perPage"`
} }
package models
import (
"errors"
"time"
)
// Typed errors
var (
ErrTeamMemberAlreadyAdded = errors.New("User is already added to this team")
)
// TeamMember model
type TeamMember struct {
Id int64
OrgId int64
TeamId int64
UserId int64
Created time.Time
Updated time.Time
}
// ---------------------
// COMMANDS
type AddTeamMemberCommand struct {
UserId int64 `json:"userId" binding:"Required"`
OrgId int64 `json:"-"`
TeamId int64 `json:"-"`
}
type RemoveTeamMemberCommand struct {
UserId int64
TeamId int64
}
// ----------------------
// QUERIES
type GetTeamMembersQuery struct {
TeamId int64
Result []*TeamMemberDTO
}
// ----------------------
// Projections and DTOs
type TeamMemberDTO struct {
OrgId int64 `json:"orgId"`
TeamId int64 `json:"teamId"`
UserId int64 `json:"userId"`
Email string `json:"email"`
Login string `json:"login"`
}
package models
import (
"errors"
"time"
)
// Typed errors
var (
ErrUserGroupMemberAlreadyAdded = errors.New("User is already added to this user group")
)
// UserGroupMember model
type UserGroupMember struct {
Id int64
OrgId int64
UserGroupId int64
UserId int64
Created time.Time
Updated time.Time
}
// ---------------------
// COMMANDS
type AddUserGroupMemberCommand struct {
UserId int64 `json:"userId" binding:"Required"`
OrgId int64 `json:"-"`
UserGroupId int64 `json:"-"`
}
type RemoveUserGroupMemberCommand struct {
UserId int64
UserGroupId int64
}
// ----------------------
// QUERIES
type GetUserGroupMembersQuery struct {
UserGroupId int64
Result []*UserGroupMemberDTO
}
// ----------------------
// Projections and DTOs
type UserGroupMemberDTO struct {
OrgId int64 `json:"orgId"`
UserGroupId int64 `json:"userGroupId"`
UserId int64 `json:"userId"`
Email string `json:"email"`
Login string `json:"login"`
}
...@@ -11,7 +11,7 @@ type DashboardGuardian struct { ...@@ -11,7 +11,7 @@ type DashboardGuardian struct {
dashId int64 dashId int64
orgId int64 orgId int64
acl []*m.DashboardAclInfoDTO acl []*m.DashboardAclInfoDTO
groups []*m.UserGroup groups []*m.Team
log log.Logger log log.Logger
} }
...@@ -55,7 +55,7 @@ func (g *DashboardGuardian) HasPermission(permission m.PermissionType) (bool, er ...@@ -55,7 +55,7 @@ func (g *DashboardGuardian) HasPermission(permission m.PermissionType) (bool, er
orgRole = m.ROLE_VIEWER orgRole = m.ROLE_VIEWER
} }
userGroupAclItems := []*m.DashboardAclInfoDTO{} teamAclItems := []*m.DashboardAclInfoDTO{}
for _, p := range acl { for _, p := range acl {
// user match // user match
...@@ -71,26 +71,26 @@ func (g *DashboardGuardian) HasPermission(permission m.PermissionType) (bool, er ...@@ -71,26 +71,26 @@ func (g *DashboardGuardian) HasPermission(permission m.PermissionType) (bool, er
} }
// remember this rule for later // remember this rule for later
if p.UserGroupId > 0 { if p.TeamId > 0 {
userGroupAclItems = append(userGroupAclItems, p) teamAclItems = append(teamAclItems, p)
} }
} }
// do we have group rules? // do we have group rules?
if len(userGroupAclItems) == 0 { if len(teamAclItems) == 0 {
return false, nil return false, nil
} }
// load groups // load groups
userGroups, err := g.getUserGroups() teams, err := g.getTeams()
if err != nil { if err != nil {
return false, err return false, err
} }
// evalute group rules // evalute group rules
for _, p := range acl { for _, p := range acl {
for _, ug := range userGroups { for _, ug := range teams {
if ug.Id == p.UserGroupId && p.Permission >= permission { if ug.Id == p.TeamId && p.Permission >= permission {
return true, nil return true, nil
} }
} }
...@@ -114,12 +114,12 @@ func (g *DashboardGuardian) GetAcl() ([]*m.DashboardAclInfoDTO, error) { ...@@ -114,12 +114,12 @@ func (g *DashboardGuardian) GetAcl() ([]*m.DashboardAclInfoDTO, error) {
return g.acl, nil return g.acl, nil
} }
func (g *DashboardGuardian) getUserGroups() ([]*m.UserGroup, error) { func (g *DashboardGuardian) getTeams() ([]*m.Team, error) {
if g.groups != nil { if g.groups != nil {
return g.groups, nil return g.groups, nil
} }
query := m.GetUserGroupsByUserQuery{UserId: g.user.UserId} query := m.GetTeamsByUserQuery{UserId: g.user.UserId}
err := bus.Dispatch(&query) err := bus.Dispatch(&query)
g.groups = query.Result g.groups = query.Result
......
...@@ -24,7 +24,7 @@ func UpdateDashboardAcl(cmd *m.UpdateDashboardAclCommand) error { ...@@ -24,7 +24,7 @@ func UpdateDashboardAcl(cmd *m.UpdateDashboardAclCommand) error {
} }
for _, item := range cmd.Items { for _, item := range cmd.Items {
if item.UserId == 0 && item.UserGroupId == 0 && !item.Role.IsValid() { if item.UserId == 0 && item.TeamId == 0 && !item.Role.IsValid() {
return m.ErrDashboardAclInfoMissing return m.ErrDashboardAclInfoMissing
} }
...@@ -32,7 +32,7 @@ func UpdateDashboardAcl(cmd *m.UpdateDashboardAclCommand) error { ...@@ -32,7 +32,7 @@ func UpdateDashboardAcl(cmd *m.UpdateDashboardAclCommand) error {
return m.ErrDashboardPermissionDashboardEmpty return m.ErrDashboardPermissionDashboardEmpty
} }
sess.Nullable("user_id", "user_group_id") sess.Nullable("user_id", "team_id")
if _, err := sess.Insert(item); err != nil { if _, err := sess.Insert(item); err != nil {
return err return err
} }
...@@ -49,7 +49,7 @@ func UpdateDashboardAcl(cmd *m.UpdateDashboardAclCommand) error { ...@@ -49,7 +49,7 @@ func UpdateDashboardAcl(cmd *m.UpdateDashboardAclCommand) error {
func SetDashboardAcl(cmd *m.SetDashboardAclCommand) error { func SetDashboardAcl(cmd *m.SetDashboardAclCommand) error {
return inTransaction(func(sess *DBSession) error { return inTransaction(func(sess *DBSession) error {
if cmd.UserId == 0 && cmd.UserGroupId == 0 { if cmd.UserId == 0 && cmd.TeamId == 0 {
return m.ErrDashboardAclInfoMissing return m.ErrDashboardAclInfoMissing
} }
...@@ -57,7 +57,7 @@ func SetDashboardAcl(cmd *m.SetDashboardAclCommand) error { ...@@ -57,7 +57,7 @@ func SetDashboardAcl(cmd *m.SetDashboardAclCommand) error {
return m.ErrDashboardPermissionDashboardEmpty return m.ErrDashboardPermissionDashboardEmpty
} }
if res, err := sess.Query("SELECT 1 from "+dialect.Quote("dashboard_acl")+" WHERE dashboard_id =? and (user_group_id=? or user_id=?)", cmd.DashboardId, cmd.UserGroupId, cmd.UserId); err != nil { if res, err := sess.Query("SELECT 1 from "+dialect.Quote("dashboard_acl")+" WHERE dashboard_id =? and (team_id=? or user_id=?)", cmd.DashboardId, cmd.TeamId, cmd.UserId); err != nil {
return err return err
} else if len(res) == 1 { } else if len(res) == 1 {
...@@ -66,7 +66,7 @@ func SetDashboardAcl(cmd *m.SetDashboardAclCommand) error { ...@@ -66,7 +66,7 @@ func SetDashboardAcl(cmd *m.SetDashboardAclCommand) error {
Updated: time.Now(), Updated: time.Now(),
} }
if _, err := sess.Cols("updated", "permission").Where("dashboard_id =? and (user_group_id=? or user_id=?)", cmd.DashboardId, cmd.UserGroupId, cmd.UserId).Update(&entity); err != nil { if _, err := sess.Cols("updated", "permission").Where("dashboard_id =? and (team_id=? or user_id=?)", cmd.DashboardId, cmd.TeamId, cmd.UserId).Update(&entity); err != nil {
return err return err
} }
...@@ -75,7 +75,7 @@ func SetDashboardAcl(cmd *m.SetDashboardAclCommand) error { ...@@ -75,7 +75,7 @@ func SetDashboardAcl(cmd *m.SetDashboardAclCommand) error {
entity := m.DashboardAcl{ entity := m.DashboardAcl{
OrgId: cmd.OrgId, OrgId: cmd.OrgId,
UserGroupId: cmd.UserGroupId, TeamId: cmd.TeamId,
UserId: cmd.UserId, UserId: cmd.UserId,
Created: time.Now(), Created: time.Now(),
Updated: time.Now(), Updated: time.Now(),
...@@ -89,8 +89,8 @@ func SetDashboardAcl(cmd *m.SetDashboardAclCommand) error { ...@@ -89,8 +89,8 @@ func SetDashboardAcl(cmd *m.SetDashboardAclCommand) error {
cols = append(cols, "user_id") cols = append(cols, "user_id")
} }
if cmd.UserGroupId != 0 { if cmd.TeamId != 0 {
cols = append(cols, "user_group_id") cols = append(cols, "team_id")
} }
_, err := sess.Cols(cols...).Insert(&entity) _, err := sess.Cols(cols...).Insert(&entity)
...@@ -138,17 +138,17 @@ func GetDashboardAclInfoList(query *m.GetDashboardAclInfoListQuery) error { ...@@ -138,17 +138,17 @@ func GetDashboardAclInfoList(query *m.GetDashboardAclInfoListQuery) error {
da.org_id, da.org_id,
da.dashboard_id, da.dashboard_id,
da.user_id, da.user_id,
da.user_group_id, da.team_id,
da.permission, da.permission,
da.role, da.role,
da.created, da.created,
da.updated, da.updated,
u.login AS user_login, u.login AS user_login,
u.email AS user_email, u.email AS user_email,
ug.name AS user_group ug.name AS team
FROM` + dialect.Quote("dashboard_acl") + ` as da FROM` + dialect.Quote("dashboard_acl") + ` as da
LEFT OUTER JOIN ` + dialect.Quote("user") + ` AS u ON u.id = da.user_id LEFT OUTER JOIN ` + dialect.Quote("user") + ` AS u ON u.id = da.user_id
LEFT OUTER JOIN user_group ug on ug.id = da.user_group_id LEFT OUTER JOIN team ug on ug.id = da.team_id
WHERE dashboard_id ` + dashboardFilter + ` AND da.org_id = ? WHERE dashboard_id ` + dashboardFilter + ` AND da.org_id = ?
-- Also include default permission if has_acl = 0 -- Also include default permission if has_acl = 0
...@@ -159,14 +159,14 @@ func GetDashboardAclInfoList(query *m.GetDashboardAclInfoListQuery) error { ...@@ -159,14 +159,14 @@ func GetDashboardAclInfoList(query *m.GetDashboardAclInfoListQuery) error {
da.org_id, da.org_id,
da.dashboard_id, da.dashboard_id,
da.user_id, da.user_id,
da.user_group_id, da.team_id,
da.permission, da.permission,
da.role, da.role,
da.created, da.created,
da.updated, da.updated,
'' as user_login, '' as user_login,
'' as user_email, '' as user_email,
'' as user_group '' as team
FROM dashboard_acl as da, FROM dashboard_acl as da,
dashboard as dash dashboard as dash
LEFT JOIN dashboard folder on dash.folder_id = folder.id LEFT JOIN dashboard folder on dash.folder_id = folder.id
......
...@@ -16,7 +16,7 @@ func TestDashboardAclDataAccess(t *testing.T) { ...@@ -16,7 +16,7 @@ func TestDashboardAclDataAccess(t *testing.T) {
savedFolder := insertTestDashboard("1 test dash folder", 1, 0, true, "prod", "webapp") savedFolder := insertTestDashboard("1 test dash folder", 1, 0, true, "prod", "webapp")
childDash := insertTestDashboard("2 test dash", 1, savedFolder.Id, false, "prod", "webapp") childDash := insertTestDashboard("2 test dash", 1, savedFolder.Id, false, "prod", "webapp")
Convey("When adding dashboard permission with userId and userGroupId set to 0", func() { Convey("When adding dashboard permission with userId and teamId set to 0", func() {
err := SetDashboardAcl(&m.SetDashboardAclCommand{ err := SetDashboardAcl(&m.SetDashboardAclCommand{
OrgId: 1, OrgId: 1,
DashboardId: savedFolder.Id, DashboardId: savedFolder.Id,
...@@ -175,15 +175,15 @@ func TestDashboardAclDataAccess(t *testing.T) { ...@@ -175,15 +175,15 @@ func TestDashboardAclDataAccess(t *testing.T) {
}) })
}) })
Convey("Given a user group", func() { Convey("Given a team", func() {
group1 := m.CreateUserGroupCommand{Name: "group1 name", OrgId: 1} group1 := m.CreateTeamCommand{Name: "group1 name", OrgId: 1}
err := CreateUserGroup(&group1) err := CreateTeam(&group1)
So(err, ShouldBeNil) So(err, ShouldBeNil)
Convey("Should be able to add a user permission for a user group", func() { Convey("Should be able to add a user permission for a team", func() {
setDashAclCmd := m.SetDashboardAclCommand{ setDashAclCmd := m.SetDashboardAclCommand{
OrgId: 1, OrgId: 1,
UserGroupId: group1.Result.Id, TeamId: group1.Result.Id,
DashboardId: savedFolder.Id, DashboardId: savedFolder.Id,
Permission: m.PERMISSION_EDIT, Permission: m.PERMISSION_EDIT,
} }
...@@ -196,9 +196,9 @@ func TestDashboardAclDataAccess(t *testing.T) { ...@@ -196,9 +196,9 @@ func TestDashboardAclDataAccess(t *testing.T) {
So(err, ShouldBeNil) So(err, ShouldBeNil)
So(q1.Result[0].DashboardId, ShouldEqual, savedFolder.Id) So(q1.Result[0].DashboardId, ShouldEqual, savedFolder.Id)
So(q1.Result[0].Permission, ShouldEqual, m.PERMISSION_EDIT) So(q1.Result[0].Permission, ShouldEqual, m.PERMISSION_EDIT)
So(q1.Result[0].UserGroupId, ShouldEqual, group1.Result.Id) So(q1.Result[0].TeamId, ShouldEqual, group1.Result.Id)
Convey("Should be able to delete an existing permission for a user group", func() { Convey("Should be able to delete an existing permission for a team", func() {
err := RemoveDashboardAcl(&m.RemoveDashboardAclCommand{ err := RemoveDashboardAcl(&m.RemoveDashboardAclCommand{
OrgId: 1, OrgId: 1,
AclId: setDashAclCmd.Result.Id, AclId: setDashAclCmd.Result.Id,
...@@ -212,10 +212,10 @@ func TestDashboardAclDataAccess(t *testing.T) { ...@@ -212,10 +212,10 @@ func TestDashboardAclDataAccess(t *testing.T) {
}) })
}) })
Convey("Should be able to update an existing permission for a user group", func() { Convey("Should be able to update an existing permission for a team", func() {
err := SetDashboardAcl(&m.SetDashboardAclCommand{ err := SetDashboardAcl(&m.SetDashboardAclCommand{
OrgId: 1, OrgId: 1,
UserGroupId: group1.Result.Id, TeamId: group1.Result.Id,
DashboardId: savedFolder.Id, DashboardId: savedFolder.Id,
Permission: m.PERMISSION_ADMIN, Permission: m.PERMISSION_ADMIN,
}) })
...@@ -227,7 +227,7 @@ func TestDashboardAclDataAccess(t *testing.T) { ...@@ -227,7 +227,7 @@ func TestDashboardAclDataAccess(t *testing.T) {
So(len(q3.Result), ShouldEqual, 1) So(len(q3.Result), ShouldEqual, 1)
So(q3.Result[0].DashboardId, ShouldEqual, savedFolder.Id) So(q3.Result[0].DashboardId, ShouldEqual, savedFolder.Id)
So(q3.Result[0].Permission, ShouldEqual, m.PERMISSION_ADMIN) So(q3.Result[0].Permission, ShouldEqual, m.PERMISSION_ADMIN)
So(q3.Result[0].UserGroupId, ShouldEqual, group1.Result.Id) So(q3.Result[0].TeamId, ShouldEqual, group1.Result.Id)
}) })
}) })
......
...@@ -10,7 +10,7 @@ func addDashboardAclMigrations(mg *Migrator) { ...@@ -10,7 +10,7 @@ func addDashboardAclMigrations(mg *Migrator) {
{Name: "org_id", Type: DB_BigInt}, {Name: "org_id", Type: DB_BigInt},
{Name: "dashboard_id", Type: DB_BigInt}, {Name: "dashboard_id", Type: DB_BigInt},
{Name: "user_id", Type: DB_BigInt, Nullable: true}, {Name: "user_id", Type: DB_BigInt, Nullable: true},
{Name: "user_group_id", Type: DB_BigInt, Nullable: true}, {Name: "team_id", Type: DB_BigInt, Nullable: true},
{Name: "permission", Type: DB_SmallInt, Default: "4"}, {Name: "permission", Type: DB_SmallInt, Default: "4"},
{Name: "role", Type: DB_Varchar, Length: 20, Nullable: true}, {Name: "role", Type: DB_Varchar, Length: 20, Nullable: true},
{Name: "created", Type: DB_DateTime, Nullable: false}, {Name: "created", Type: DB_DateTime, Nullable: false},
...@@ -19,7 +19,7 @@ func addDashboardAclMigrations(mg *Migrator) { ...@@ -19,7 +19,7 @@ func addDashboardAclMigrations(mg *Migrator) {
Indices: []*Index{ Indices: []*Index{
{Cols: []string{"dashboard_id"}}, {Cols: []string{"dashboard_id"}},
{Cols: []string{"dashboard_id", "user_id"}, Type: UniqueIndex}, {Cols: []string{"dashboard_id", "user_id"}, Type: UniqueIndex},
{Cols: []string{"dashboard_id", "user_group_id"}, Type: UniqueIndex}, {Cols: []string{"dashboard_id", "team_id"}, Type: UniqueIndex},
}, },
} }
......
...@@ -26,7 +26,7 @@ func AddMigrations(mg *Migrator) { ...@@ -26,7 +26,7 @@ func AddMigrations(mg *Migrator) {
addAnnotationMig(mg) addAnnotationMig(mg)
addTestDataMigrations(mg) addTestDataMigrations(mg)
addDashboardVersionMigration(mg) addDashboardVersionMigration(mg)
addUserGroupMigrations(mg) addTeamMigrations(mg)
addDashboardAclMigrations(mg) addDashboardAclMigrations(mg)
addTagMigration(mg) addTagMigration(mg)
} }
......
...@@ -2,9 +2,9 @@ package migrations ...@@ -2,9 +2,9 @@ package migrations
import . "github.com/grafana/grafana/pkg/services/sqlstore/migrator" import . "github.com/grafana/grafana/pkg/services/sqlstore/migrator"
func addUserGroupMigrations(mg *Migrator) { func addTeamMigrations(mg *Migrator) {
userGroupV1 := Table{ teamV1 := Table{
Name: "user_group", Name: "team",
Columns: []*Column{ Columns: []*Column{
{Name: "id", Type: DB_BigInt, IsPrimaryKey: true, IsAutoIncrement: true}, {Name: "id", Type: DB_BigInt, IsPrimaryKey: true, IsAutoIncrement: true},
{Name: "name", Type: DB_NVarchar, Length: 255, Nullable: false}, {Name: "name", Type: DB_NVarchar, Length: 255, Nullable: false},
...@@ -18,31 +18,31 @@ func addUserGroupMigrations(mg *Migrator) { ...@@ -18,31 +18,31 @@ func addUserGroupMigrations(mg *Migrator) {
}, },
} }
mg.AddMigration("create user group table", NewAddTableMigration(userGroupV1)) mg.AddMigration("create team table", NewAddTableMigration(teamV1))
//------- indexes ------------------ //------- indexes ------------------
mg.AddMigration("add index user_group.org_id", NewAddIndexMigration(userGroupV1, userGroupV1.Indices[0])) mg.AddMigration("add index team.org_id", NewAddIndexMigration(teamV1, teamV1.Indices[0]))
mg.AddMigration("add unique index user_group_org_id_name", NewAddIndexMigration(userGroupV1, userGroupV1.Indices[1])) mg.AddMigration("add unique index team_org_id_name", NewAddIndexMigration(teamV1, teamV1.Indices[1]))
userGroupMemberV1 := Table{ teamMemberV1 := Table{
Name: "user_group_member", Name: "team_member",
Columns: []*Column{ Columns: []*Column{
{Name: "id", Type: DB_BigInt, IsPrimaryKey: true, IsAutoIncrement: true}, {Name: "id", Type: DB_BigInt, IsPrimaryKey: true, IsAutoIncrement: true},
{Name: "org_id", Type: DB_BigInt}, {Name: "org_id", Type: DB_BigInt},
{Name: "user_group_id", Type: DB_BigInt}, {Name: "team_id", Type: DB_BigInt},
{Name: "user_id", Type: DB_BigInt}, {Name: "user_id", Type: DB_BigInt},
{Name: "created", Type: DB_DateTime, Nullable: false}, {Name: "created", Type: DB_DateTime, Nullable: false},
{Name: "updated", Type: DB_DateTime, Nullable: false}, {Name: "updated", Type: DB_DateTime, Nullable: false},
}, },
Indices: []*Index{ Indices: []*Index{
{Cols: []string{"org_id"}}, {Cols: []string{"org_id"}},
{Cols: []string{"org_id", "user_group_id", "user_id"}, Type: UniqueIndex}, {Cols: []string{"org_id", "team_id", "user_id"}, Type: UniqueIndex},
}, },
} }
mg.AddMigration("create user group member table", NewAddTableMigration(userGroupMemberV1)) mg.AddMigration("create team member table", NewAddTableMigration(teamMemberV1))
//------- indexes ------------------ //------- indexes ------------------
mg.AddMigration("add index user_group_member.org_id", NewAddIndexMigration(userGroupMemberV1, userGroupMemberV1.Indices[0])) mg.AddMigration("add index team_member.org_id", NewAddIndexMigration(teamMemberV1, teamMemberV1.Indices[0]))
mg.AddMigration("add unique index user_group_member_org_id_user_group_id_user_id", NewAddIndexMigration(userGroupMemberV1, userGroupMemberV1.Indices[1])) mg.AddMigration("add unique index team_member_org_id_team_id_user_id", NewAddIndexMigration(teamMemberV1, teamMemberV1.Indices[1]))
} }
...@@ -91,7 +91,7 @@ func RemoveOrgUser(cmd *m.RemoveOrgUserCommand) error { ...@@ -91,7 +91,7 @@ func RemoveOrgUser(cmd *m.RemoveOrgUserCommand) error {
deletes := []string{ deletes := []string{
"DELETE FROM org_user WHERE org_id=? and user_id=?", "DELETE FROM org_user WHERE org_id=? and user_id=?",
"DELETE FROM dashboard_acl WHERE org_id=? and user_id = ?", "DELETE FROM dashboard_acl WHERE org_id=? and user_id = ?",
"DELETE FROM user_group_member WHERE org_id=? and user_id = ?", "DELETE FROM team_member WHERE org_id=? and user_id = ?",
} }
for _, sql := range deletes { for _, sql := range deletes {
......
...@@ -179,7 +179,7 @@ func (sb *SearchBuilder) buildSearchWhereClause() { ...@@ -179,7 +179,7 @@ func (sb *SearchBuilder) buildSearchWhereClause() {
SELECT distinct d.id AS DashboardId SELECT distinct d.id AS DashboardId
FROM dashboard AS d FROM dashboard AS d
LEFT JOIN dashboard_acl as da on d.folder_id = da.dashboard_id or d.id = da.dashboard_id LEFT JOIN dashboard_acl as da on d.folder_id = da.dashboard_id or d.id = da.dashboard_id
LEFT JOIN user_group_member as ugm on ugm.user_group_id = da.user_group_id LEFT JOIN team_member as ugm on ugm.team_id = da.team_id
LEFT JOIN org_user ou on ou.role = da.role LEFT JOIN org_user ou on ou.role = da.role
WHERE WHERE
d.has_acl = 1 and d.has_acl = 1 and
......
...@@ -9,82 +9,82 @@ import ( ...@@ -9,82 +9,82 @@ import (
) )
func init() { func init() {
bus.AddHandler("sql", CreateUserGroup) bus.AddHandler("sql", CreateTeam)
bus.AddHandler("sql", UpdateUserGroup) bus.AddHandler("sql", UpdateTeam)
bus.AddHandler("sql", DeleteUserGroup) bus.AddHandler("sql", DeleteTeam)
bus.AddHandler("sql", SearchUserGroups) bus.AddHandler("sql", SearchTeams)
bus.AddHandler("sql", GetUserGroupById) bus.AddHandler("sql", GetTeamById)
bus.AddHandler("sql", GetUserGroupsByUser) bus.AddHandler("sql", GetTeamsByUser)
bus.AddHandler("sql", AddUserGroupMember) bus.AddHandler("sql", AddTeamMember)
bus.AddHandler("sql", RemoveUserGroupMember) bus.AddHandler("sql", RemoveTeamMember)
bus.AddHandler("sql", GetUserGroupMembers) bus.AddHandler("sql", GetTeamMembers)
} }
func CreateUserGroup(cmd *m.CreateUserGroupCommand) error { func CreateTeam(cmd *m.CreateTeamCommand) error {
return inTransaction(func(sess *DBSession) error { return inTransaction(func(sess *DBSession) error {
if isNameTaken, err := isUserGroupNameTaken(cmd.Name, 0, sess); err != nil { if isNameTaken, err := isTeamNameTaken(cmd.Name, 0, sess); err != nil {
return err return err
} else if isNameTaken { } else if isNameTaken {
return m.ErrUserGroupNameTaken return m.ErrTeamNameTaken
} }
userGroup := m.UserGroup{ team := m.Team{
Name: cmd.Name, Name: cmd.Name,
OrgId: cmd.OrgId, OrgId: cmd.OrgId,
Created: time.Now(), Created: time.Now(),
Updated: time.Now(), Updated: time.Now(),
} }
_, err := sess.Insert(&userGroup) _, err := sess.Insert(&team)
cmd.Result = userGroup cmd.Result = team
return err return err
}) })
} }
func UpdateUserGroup(cmd *m.UpdateUserGroupCommand) error { func UpdateTeam(cmd *m.UpdateTeamCommand) error {
return inTransaction(func(sess *DBSession) error { return inTransaction(func(sess *DBSession) error {
if isNameTaken, err := isUserGroupNameTaken(cmd.Name, cmd.Id, sess); err != nil { if isNameTaken, err := isTeamNameTaken(cmd.Name, cmd.Id, sess); err != nil {
return err return err
} else if isNameTaken { } else if isNameTaken {
return m.ErrUserGroupNameTaken return m.ErrTeamNameTaken
} }
userGroup := m.UserGroup{ team := m.Team{
Name: cmd.Name, Name: cmd.Name,
Updated: time.Now(), Updated: time.Now(),
} }
affectedRows, err := sess.Id(cmd.Id).Update(&userGroup) affectedRows, err := sess.Id(cmd.Id).Update(&team)
if err != nil { if err != nil {
return err return err
} }
if affectedRows == 0 { if affectedRows == 0 {
return m.ErrUserGroupNotFound return m.ErrTeamNotFound
} }
return nil return nil
}) })
} }
func DeleteUserGroup(cmd *m.DeleteUserGroupCommand) error { func DeleteTeam(cmd *m.DeleteTeamCommand) error {
return inTransaction(func(sess *DBSession) error { return inTransaction(func(sess *DBSession) error {
if res, err := sess.Query("SELECT 1 from user_group WHERE id=?", cmd.Id); err != nil { if res, err := sess.Query("SELECT 1 from team WHERE id=?", cmd.Id); err != nil {
return err return err
} else if len(res) != 1 { } else if len(res) != 1 {
return m.ErrUserGroupNotFound return m.ErrTeamNotFound
} }
deletes := []string{ deletes := []string{
"DELETE FROM user_group_member WHERE user_group_id = ?", "DELETE FROM team_member WHERE team_id = ?",
"DELETE FROM user_group WHERE id = ?", "DELETE FROM team WHERE id = ?",
"DELETE FROM dashboard_acl WHERE user_group_id = ?", "DELETE FROM dashboard_acl WHERE team_id = ?",
} }
for _, sql := range deletes { for _, sql := range deletes {
...@@ -97,28 +97,28 @@ func DeleteUserGroup(cmd *m.DeleteUserGroupCommand) error { ...@@ -97,28 +97,28 @@ func DeleteUserGroup(cmd *m.DeleteUserGroupCommand) error {
}) })
} }
func isUserGroupNameTaken(name string, existingId int64, sess *DBSession) (bool, error) { func isTeamNameTaken(name string, existingId int64, sess *DBSession) (bool, error) {
var userGroup m.UserGroup var team m.Team
exists, err := sess.Where("name=?", name).Get(&userGroup) exists, err := sess.Where("name=?", name).Get(&team)
if err != nil { if err != nil {
return false, nil return false, nil
} }
if exists && existingId != userGroup.Id { if exists && existingId != team.Id {
return true, nil return true, nil
} }
return false, nil return false, nil
} }
func SearchUserGroups(query *m.SearchUserGroupsQuery) error { func SearchTeams(query *m.SearchTeamsQuery) error {
query.Result = m.SearchUserGroupQueryResult{ query.Result = m.SearchTeamQueryResult{
UserGroups: make([]*m.UserGroup, 0), Teams: make([]*m.Team, 0),
} }
queryWithWildcards := "%" + query.Query + "%" queryWithWildcards := "%" + query.Query + "%"
sess := x.Table("user_group") sess := x.Table("team")
sess.Where("org_id=?", query.OrgId) sess.Where("org_id=?", query.OrgId)
if query.Query != "" { if query.Query != "" {
...@@ -132,46 +132,46 @@ func SearchUserGroups(query *m.SearchUserGroupsQuery) error { ...@@ -132,46 +132,46 @@ func SearchUserGroups(query *m.SearchUserGroupsQuery) error {
offset := query.Limit * (query.Page - 1) offset := query.Limit * (query.Page - 1)
sess.Limit(query.Limit, offset) sess.Limit(query.Limit, offset)
sess.Cols("id", "name") sess.Cols("id", "name")
if err := sess.Find(&query.Result.UserGroups); err != nil { if err := sess.Find(&query.Result.Teams); err != nil {
return err return err
} }
userGroup := m.UserGroup{} team := m.Team{}
countSess := x.Table("user_group") countSess := x.Table("team")
if query.Query != "" { if query.Query != "" {
countSess.Where("name LIKE ?", queryWithWildcards) countSess.Where("name LIKE ?", queryWithWildcards)
} }
if query.Name != "" { if query.Name != "" {
countSess.Where("name=?", query.Name) countSess.Where("name=?", query.Name)
} }
count, err := countSess.Count(&userGroup) count, err := countSess.Count(&team)
query.Result.TotalCount = count query.Result.TotalCount = count
return err return err
} }
func GetUserGroupById(query *m.GetUserGroupByIdQuery) error { func GetTeamById(query *m.GetTeamByIdQuery) error {
var userGroup m.UserGroup var team m.Team
exists, err := x.Id(query.Id).Get(&userGroup) exists, err := x.Id(query.Id).Get(&team)
if err != nil { if err != nil {
return err return err
} }
if !exists { if !exists {
return m.ErrUserGroupNotFound return m.ErrTeamNotFound
} }
query.Result = &userGroup query.Result = &team
return nil return nil
} }
func GetUserGroupsByUser(query *m.GetUserGroupsByUserQuery) error { func GetTeamsByUser(query *m.GetTeamsByUserQuery) error {
query.Result = make([]*m.UserGroup, 0) query.Result = make([]*m.Team, 0)
sess := x.Table("user_group") sess := x.Table("team")
sess.Join("INNER", "user_group_member", "user_group.id=user_group_member.user_group_id") sess.Join("INNER", "team_member", "team.id=team_member.team_id")
sess.Where("user_group_member.user_id=?", query.UserId) sess.Where("team_member.user_id=?", query.UserId)
err := sess.Find(&query.Result) err := sess.Find(&query.Result)
if err != nil { if err != nil {
...@@ -181,23 +181,23 @@ func GetUserGroupsByUser(query *m.GetUserGroupsByUserQuery) error { ...@@ -181,23 +181,23 @@ func GetUserGroupsByUser(query *m.GetUserGroupsByUserQuery) error {
return nil return nil
} }
func AddUserGroupMember(cmd *m.AddUserGroupMemberCommand) error { func AddTeamMember(cmd *m.AddTeamMemberCommand) error {
return inTransaction(func(sess *DBSession) error { return inTransaction(func(sess *DBSession) error {
if res, err := sess.Query("SELECT 1 from user_group_member WHERE user_group_id=? and user_id=?", cmd.UserGroupId, cmd.UserId); err != nil { if res, err := sess.Query("SELECT 1 from team_member WHERE team_id=? and user_id=?", cmd.TeamId, cmd.UserId); err != nil {
return err return err
} else if len(res) == 1 { } else if len(res) == 1 {
return m.ErrUserGroupMemberAlreadyAdded return m.ErrTeamMemberAlreadyAdded
} }
if res, err := sess.Query("SELECT 1 from user_group WHERE id=?", cmd.UserGroupId); err != nil { if res, err := sess.Query("SELECT 1 from team WHERE id=?", cmd.TeamId); err != nil {
return err return err
} else if len(res) != 1 { } else if len(res) != 1 {
return m.ErrUserGroupNotFound return m.ErrTeamNotFound
} }
entity := m.UserGroupMember{ entity := m.TeamMember{
OrgId: cmd.OrgId, OrgId: cmd.OrgId,
UserGroupId: cmd.UserGroupId, TeamId: cmd.TeamId,
UserId: cmd.UserId, UserId: cmd.UserId,
Created: time.Now(), Created: time.Now(),
Updated: time.Now(), Updated: time.Now(),
...@@ -208,10 +208,10 @@ func AddUserGroupMember(cmd *m.AddUserGroupMemberCommand) error { ...@@ -208,10 +208,10 @@ func AddUserGroupMember(cmd *m.AddUserGroupMemberCommand) error {
}) })
} }
func RemoveUserGroupMember(cmd *m.RemoveUserGroupMemberCommand) error { func RemoveTeamMember(cmd *m.RemoveTeamMemberCommand) error {
return inTransaction(func(sess *DBSession) error { return inTransaction(func(sess *DBSession) error {
var rawSql = "DELETE FROM user_group_member WHERE user_group_id=? and user_id=?" var rawSql = "DELETE FROM team_member WHERE team_id=? and user_id=?"
_, err := sess.Exec(rawSql, cmd.UserGroupId, cmd.UserId) _, err := sess.Exec(rawSql, cmd.TeamId, cmd.UserId)
if err != nil { if err != nil {
return err return err
} }
...@@ -220,12 +220,12 @@ func RemoveUserGroupMember(cmd *m.RemoveUserGroupMemberCommand) error { ...@@ -220,12 +220,12 @@ func RemoveUserGroupMember(cmd *m.RemoveUserGroupMemberCommand) error {
}) })
} }
func GetUserGroupMembers(query *m.GetUserGroupMembersQuery) error { func GetTeamMembers(query *m.GetTeamMembersQuery) error {
query.Result = make([]*m.UserGroupMemberDTO, 0) query.Result = make([]*m.TeamMemberDTO, 0)
sess := x.Table("user_group_member") sess := x.Table("team_member")
sess.Join("INNER", "user", fmt.Sprintf("user_group_member.user_id=%s.id", x.Dialect().Quote("user"))) sess.Join("INNER", "user", fmt.Sprintf("team_member.user_id=%s.id", x.Dialect().Quote("user")))
sess.Where("user_group_member.user_group_id=?", query.UserGroupId) sess.Where("team_member.team_id=?", query.TeamId)
sess.Cols("user.org_id", "user_group_member.user_group_id", "user_group_member.user_id", "user.email", "user.login") sess.Cols("user.org_id", "team_member.team_id", "team_member.user_id", "user.email", "user.login")
sess.Asc("user.login", "user.email") sess.Asc("user.login", "user.email")
err := sess.Find(&query.Result) err := sess.Find(&query.Result)
......
...@@ -9,12 +9,12 @@ import ( ...@@ -9,12 +9,12 @@ import (
m "github.com/grafana/grafana/pkg/models" m "github.com/grafana/grafana/pkg/models"
) )
func TestUserGroupCommandsAndQueries(t *testing.T) { func TestTeamCommandsAndQueries(t *testing.T) {
Convey("Testing User Group commands & queries", t, func() { Convey("Testing Team commands & queries", t, func() {
InitTestDB(t) InitTestDB(t)
Convey("Given saved users and two user groups", func() { Convey("Given saved users and two teams", func() {
var userIds []int64 var userIds []int64
for i := 0; i < 5; i++ { for i := 0; i < 5; i++ {
userCmd := &m.CreateUserCommand{ userCmd := &m.CreateUserCommand{
...@@ -27,81 +27,81 @@ func TestUserGroupCommandsAndQueries(t *testing.T) { ...@@ -27,81 +27,81 @@ func TestUserGroupCommandsAndQueries(t *testing.T) {
userIds = append(userIds, userCmd.Result.Id) userIds = append(userIds, userCmd.Result.Id)
} }
group1 := m.CreateUserGroupCommand{Name: "group1 name"} group1 := m.CreateTeamCommand{Name: "group1 name"}
group2 := m.CreateUserGroupCommand{Name: "group2 name"} group2 := m.CreateTeamCommand{Name: "group2 name"}
err := CreateUserGroup(&group1) err := CreateTeam(&group1)
So(err, ShouldBeNil) So(err, ShouldBeNil)
err = CreateUserGroup(&group2) err = CreateTeam(&group2)
So(err, ShouldBeNil) So(err, ShouldBeNil)
Convey("Should be able to create user groups and add users", func() { Convey("Should be able to create teams and add users", func() {
query := &m.SearchUserGroupsQuery{Name: "group1 name", Page: 1, Limit: 10} query := &m.SearchTeamsQuery{Name: "group1 name", Page: 1, Limit: 10}
err = SearchUserGroups(query) err = SearchTeams(query)
So(err, ShouldBeNil) So(err, ShouldBeNil)
So(query.Page, ShouldEqual, 1) So(query.Page, ShouldEqual, 1)
userGroup1 := query.Result.UserGroups[0] team1 := query.Result.Teams[0]
So(userGroup1.Name, ShouldEqual, "group1 name") So(team1.Name, ShouldEqual, "group1 name")
err = AddUserGroupMember(&m.AddUserGroupMemberCommand{OrgId: 1, UserGroupId: userGroup1.Id, UserId: userIds[0]}) err = AddTeamMember(&m.AddTeamMemberCommand{OrgId: 1, TeamId: team1.Id, UserId: userIds[0]})
So(err, ShouldBeNil) So(err, ShouldBeNil)
q1 := &m.GetUserGroupMembersQuery{UserGroupId: userGroup1.Id} q1 := &m.GetTeamMembersQuery{TeamId: team1.Id}
err = GetUserGroupMembers(q1) err = GetTeamMembers(q1)
So(err, ShouldBeNil) So(err, ShouldBeNil)
So(q1.Result[0].UserGroupId, ShouldEqual, userGroup1.Id) So(q1.Result[0].TeamId, ShouldEqual, team1.Id)
So(q1.Result[0].Login, ShouldEqual, "loginuser0") So(q1.Result[0].Login, ShouldEqual, "loginuser0")
}) })
Convey("Should be able to search for user groups", func() { Convey("Should be able to search for teams", func() {
query := &m.SearchUserGroupsQuery{Query: "group", Page: 1} query := &m.SearchTeamsQuery{Query: "group", Page: 1}
err = SearchUserGroups(query) err = SearchTeams(query)
So(err, ShouldBeNil) So(err, ShouldBeNil)
So(len(query.Result.UserGroups), ShouldEqual, 2) So(len(query.Result.Teams), ShouldEqual, 2)
So(query.Result.TotalCount, ShouldEqual, 2) So(query.Result.TotalCount, ShouldEqual, 2)
query2 := &m.SearchUserGroupsQuery{Query: ""} query2 := &m.SearchTeamsQuery{Query: ""}
err = SearchUserGroups(query2) err = SearchTeams(query2)
So(err, ShouldBeNil) So(err, ShouldBeNil)
So(len(query2.Result.UserGroups), ShouldEqual, 2) So(len(query2.Result.Teams), ShouldEqual, 2)
}) })
Convey("Should be able to return all user groups a user is member of", func() { Convey("Should be able to return all teams a user is member of", func() {
groupId := group2.Result.Id groupId := group2.Result.Id
err := AddUserGroupMember(&m.AddUserGroupMemberCommand{OrgId: 1, UserGroupId: groupId, UserId: userIds[0]}) err := AddTeamMember(&m.AddTeamMemberCommand{OrgId: 1, TeamId: groupId, UserId: userIds[0]})
query := &m.GetUserGroupsByUserQuery{UserId: userIds[0]} query := &m.GetTeamsByUserQuery{UserId: userIds[0]}
err = GetUserGroupsByUser(query) err = GetTeamsByUser(query)
So(err, ShouldBeNil) So(err, ShouldBeNil)
So(len(query.Result), ShouldEqual, 1) So(len(query.Result), ShouldEqual, 1)
So(query.Result[0].Name, ShouldEqual, "group2 name") So(query.Result[0].Name, ShouldEqual, "group2 name")
}) })
Convey("Should be able to remove users from a group", func() { Convey("Should be able to remove users from a group", func() {
err = RemoveUserGroupMember(&m.RemoveUserGroupMemberCommand{UserGroupId: group1.Result.Id, UserId: userIds[0]}) err = RemoveTeamMember(&m.RemoveTeamMemberCommand{TeamId: group1.Result.Id, UserId: userIds[0]})
So(err, ShouldBeNil) So(err, ShouldBeNil)
q1 := &m.GetUserGroupMembersQuery{UserGroupId: group1.Result.Id} q1 := &m.GetTeamMembersQuery{TeamId: group1.Result.Id}
err = GetUserGroupMembers(q1) err = GetTeamMembers(q1)
So(err, ShouldBeNil) So(err, ShouldBeNil)
So(len(q1.Result), ShouldEqual, 0) So(len(q1.Result), ShouldEqual, 0)
}) })
Convey("Should be able to remove a group with users and permissions", func() { Convey("Should be able to remove a group with users and permissions", func() {
groupId := group2.Result.Id groupId := group2.Result.Id
err := AddUserGroupMember(&m.AddUserGroupMemberCommand{OrgId: 1, UserGroupId: groupId, UserId: userIds[1]}) err := AddTeamMember(&m.AddTeamMemberCommand{OrgId: 1, TeamId: groupId, UserId: userIds[1]})
So(err, ShouldBeNil) So(err, ShouldBeNil)
err = AddUserGroupMember(&m.AddUserGroupMemberCommand{OrgId: 1, UserGroupId: groupId, UserId: userIds[2]}) err = AddTeamMember(&m.AddTeamMemberCommand{OrgId: 1, TeamId: groupId, UserId: userIds[2]})
So(err, ShouldBeNil) So(err, ShouldBeNil)
err = SetDashboardAcl(&m.SetDashboardAclCommand{DashboardId: 1, OrgId: 1, Permission: m.PERMISSION_EDIT, UserGroupId: groupId}) err = SetDashboardAcl(&m.SetDashboardAclCommand{DashboardId: 1, OrgId: 1, Permission: m.PERMISSION_EDIT, TeamId: groupId})
err = DeleteUserGroup(&m.DeleteUserGroupCommand{Id: groupId}) err = DeleteTeam(&m.DeleteTeamCommand{Id: groupId})
So(err, ShouldBeNil) So(err, ShouldBeNil)
query := &m.GetUserGroupByIdQuery{Id: groupId} query := &m.GetTeamByIdQuery{Id: groupId}
err = GetUserGroupById(query) err = GetTeamById(query)
So(err, ShouldEqual, m.ErrUserGroupNotFound) So(err, ShouldEqual, m.ErrTeamNotFound)
permQuery := &m.GetDashboardAclInfoListQuery{DashboardId: 1, OrgId: 1} permQuery := &m.GetDashboardAclInfoListQuery{DashboardId: 1, OrgId: 1}
err = GetDashboardAclInfoList(permQuery) err = GetDashboardAclInfoList(permQuery)
......
...@@ -442,7 +442,7 @@ func DeleteUser(cmd *m.DeleteUserCommand) error { ...@@ -442,7 +442,7 @@ func DeleteUser(cmd *m.DeleteUserCommand) error {
"DELETE FROM org_user WHERE user_id = ?", "DELETE FROM org_user WHERE user_id = ?",
"DELETE FROM dashboard_acl WHERE user_id = ?", "DELETE FROM dashboard_acl WHERE user_id = ?",
"DELETE FROM preferences WHERE user_id = ?", "DELETE FROM preferences WHERE user_id = ?",
"DELETE FROM user_group_member WHERE user_id = ?", "DELETE FROM team_member WHERE user_id = ?",
} }
for _, sql := range deletes { for _, sql := range deletes {
......
...@@ -10,9 +10,9 @@ const template = ` ...@@ -10,9 +10,9 @@ const template = `
</gf-form-dropdown> </gf-form-dropdown>
</div> </div>
`; `;
export class UserGroupPickerCtrl { export class TeamPickerCtrl {
group: any; group: any;
userGroupPicked: any; teamPicked: any;
debouncedSearchGroups: any; debouncedSearchGroups: any;
/** @ngInject */ /** @ngInject */
...@@ -26,34 +26,34 @@ export class UserGroupPickerCtrl { ...@@ -26,34 +26,34 @@ export class UserGroupPickerCtrl {
} }
searchGroups(query: string) { searchGroups(query: string) {
return Promise.resolve(this.backendSrv.get('/api/user-groups/search?perpage=10&page=1&query=' + query).then(result => { return Promise.resolve(this.backendSrv.get('/api/teams/search?perpage=10&page=1&query=' + query).then(result => {
return _.map(result.userGroups, ug => { return _.map(result.teams, ug => {
return {text: ug.name, value: ug}; return {text: ug.name, value: ug};
}); });
})); }));
} }
onChange(option) { onChange(option) {
this.userGroupPicked({$group: option.value}); this.teamPicked({$group: option.value});
} }
} }
export function userGroupPicker() { export function teamPicker() {
return { return {
restrict: 'E', restrict: 'E',
template: template, template: template,
controller: UserGroupPickerCtrl, controller: TeamPickerCtrl,
bindToController: true, bindToController: true,
controllerAs: 'ctrl', controllerAs: 'ctrl',
scope: { scope: {
userGroupPicked: '&', teamPicked: '&',
}, },
link: function(scope, elem, attrs, ctrl) { link: function(scope, elem, attrs, ctrl) {
scope.$on("user-group-picker-reset", () => { scope.$on("team-picker-reset", () => {
ctrl.reset(); ctrl.reset();
}); });
} }
}; };
} }
coreModule.directive('userGroupPicker', userGroupPicker); coreModule.directive('teamPicker', teamPicker);
...@@ -47,7 +47,7 @@ import {helpModal} from './components/help/help'; ...@@ -47,7 +47,7 @@ import {helpModal} from './components/help/help';
import {JsonExplorer} from './components/json_explorer/json_explorer'; import {JsonExplorer} from './components/json_explorer/json_explorer';
import {NavModelSrv, NavModel} from './nav_model_srv'; import {NavModelSrv, NavModel} from './nav_model_srv';
import {userPicker} from './components/user_picker'; import {userPicker} from './components/user_picker';
import {userGroupPicker} from './components/user_group_picker'; import {teamPicker} from './components/team_picker';
import {geminiScrollbar} from './components/scroll/scroll'; import {geminiScrollbar} from './components/scroll/scroll';
import {gfPageDirective} from './components/gf_page'; import {gfPageDirective} from './components/gf_page';
import {orgSwitcher} from './components/org_switcher'; import {orgSwitcher} from './components/org_switcher';
...@@ -85,7 +85,7 @@ export { ...@@ -85,7 +85,7 @@ export {
NavModelSrv, NavModelSrv,
NavModel, NavModel,
userPicker, userPicker,
userGroupPicker, teamPicker,
geminiScrollbar, geminiScrollbar,
gfPageDirective, gfPageDirective,
orgSwitcher, orgSwitcher,
......
...@@ -109,15 +109,15 @@ function setupAngularRoutes($routeProvider, $locationProvider) { ...@@ -109,15 +109,15 @@ function setupAngularRoutes($routeProvider, $locationProvider) {
controller : 'OrgApiKeysCtrl', controller : 'OrgApiKeysCtrl',
resolve: loadOrgBundle, resolve: loadOrgBundle,
}) })
.when('/org/user-groups', { .when('/org/teams', {
templateUrl: 'public/app/features/org/partials/user_groups.html', templateUrl: 'public/app/features/org/partials/teams.html',
controller : 'UserGroupsCtrl', controller : 'TeamsCtrl',
controllerAs: 'ctrl', controllerAs: 'ctrl',
resolve: loadOrgBundle, resolve: loadOrgBundle,
}) })
.when('/org/user-groups/edit/:id', { .when('/org/teams/edit/:id', {
templateUrl: 'public/app/features/org/partials/user_group_details.html', templateUrl: 'public/app/features/org/partials/team_details.html',
controller : 'UserGroupDetailsCtrl', controller : 'TeamDetailsCtrl',
controllerAs: 'ctrl', controllerAs: 'ctrl',
resolve: loadOrgBundle, resolve: loadOrgBundle,
}) })
......
...@@ -52,7 +52,7 @@ ...@@ -52,7 +52,7 @@
<user-picker user-picked="ctrl.userPicked($user)"></user-picker> <user-picker user-picked="ctrl.userPicked($user)"></user-picker>
</div> </div>
<div class="gf-form" ng-show="ctrl.newType === 'Group'"> <div class="gf-form" ng-show="ctrl.newType === 'Group'">
<user-group-picker user-group-picked="ctrl.groupPicked($group)"></user-group-picker> <team-picker team-picked="ctrl.groupPicked($group)"></team-picker>
</div> </div>
</div> </div>
</form> </form>
...@@ -101,9 +101,9 @@ ...@@ -101,9 +101,9 @@
<!-- </a> --> <!-- </a> -->
<!-- </td> --> <!-- </td> -->
<!-- </tr> --> <!-- </tr> -->
<!-- <tr ng&#45;repeat="permission in ctrl.userGroupPermissions" class="permissionlist__item"> --> <!-- <tr ng&#45;repeat="permission in ctrl.teamPermissions" class="permissionlist__item"> -->
<!-- <td><i class="fa fa&#45;fw fa&#45;users"></i></td> --> <!-- <td><i class="fa fa&#45;fw fa&#45;users"></i></td> -->
<!-- <td>{{permission.userGroup}}</td> --> <!-- <td>{{permission.team}}</td> -->
<!-- <td><select class="gf&#45;form&#45;input gf&#45;size&#45;auto" ng&#45;model="permission.permissions" ng&#45;options="p.value as p.text for p in ctrl.permissionTypeOptions" ng&#45;change="ctrl.updatePermission(permission)"></select></td> --> <!-- <td><select class="gf&#45;form&#45;input gf&#45;size&#45;auto" ng&#45;model="permission.permissions" ng&#45;options="p.value as p.text for p in ctrl.permissionTypeOptions" ng&#45;change="ctrl.updatePermission(permission)"></select></td> -->
<!-- <td class="text&#45;right"> --> <!-- <td class="text&#45;right"> -->
<!-- <a ng&#45;click="ctrl.removePermission(permission)" class="btn btn&#45;danger btn&#45;small"> --> <!-- <a ng&#45;click="ctrl.removePermission(permission)" class="btn btn&#45;danger btn&#45;small"> -->
......
...@@ -12,7 +12,7 @@ export class AclCtrl { ...@@ -12,7 +12,7 @@ export class AclCtrl {
{value: 4, text: 'Admin'} {value: 4, text: 'Admin'}
]; ];
aclTypes = [ aclTypes = [
{value: 'Group', text: 'User Group'}, {value: 'Group', text: 'Team'},
{value: 'User', text: 'User'}, {value: 'User', text: 'User'},
{value: 'Viewer', text: 'Everyone With Viewer Role'}, {value: 'Viewer', text: 'Everyone With Viewer Role'},
{value: 'Editor', text: 'Everyone With Editor Role'} {value: 'Editor', text: 'Everyone With Editor Role'}
...@@ -58,10 +58,10 @@ export class AclCtrl { ...@@ -58,10 +58,10 @@ export class AclCtrl {
item.nameHtml = this.$sce.trustAsHtml(item.userLogin); item.nameHtml = this.$sce.trustAsHtml(item.userLogin);
item.sortName = item.userLogin; item.sortName = item.userLogin;
item.sortRank = 10; item.sortRank = 10;
} else if (item.userGroupId > 0) { } else if (item.teamId > 0) {
item.icon = "fa fa-fw fa-users"; item.icon = "fa fa-fw fa-users";
item.nameHtml = this.$sce.trustAsHtml(item.userGroup); item.nameHtml = this.$sce.trustAsHtml(item.team);
item.sortName = item.userGroup; item.sortName = item.team;
item.sortRank = 20; item.sortRank = 20;
} else if (item.role) { } else if (item.role) {
item.icon = "fa fa-fw fa-street-view"; item.icon = "fa fa-fw fa-street-view";
...@@ -89,7 +89,7 @@ export class AclCtrl { ...@@ -89,7 +89,7 @@ export class AclCtrl {
updated.push({ updated.push({
id: item.id, id: item.id,
userId: item.userId, userId: item.userId,
userGroupId: item.userGroupId, teamId: item.teamId,
role: item.role, role: item.role,
permission: item.permission, permission: item.permission,
}); });
...@@ -144,7 +144,7 @@ export class AclCtrl { ...@@ -144,7 +144,7 @@ export class AclCtrl {
return (origItem.role && newItem.role && origItem.role === newItem.role) || return (origItem.role && newItem.role && origItem.role === newItem.role) ||
(origItem.userId && newItem.userId && origItem.userId === newItem.userId) || (origItem.userId && newItem.userId && origItem.userId === newItem.userId) ||
(origItem.userGroupId && newItem.userGroupId && origItem.userGroupId === newItem.userGroupId); (origItem.teamId && newItem.teamId && origItem.teamId === newItem.teamId);
} }
userPicked(user) { userPicked(user) {
...@@ -153,8 +153,8 @@ export class AclCtrl { ...@@ -153,8 +153,8 @@ export class AclCtrl {
} }
groupPicked(group) { groupPicked(group) {
this.addNewItem({userGroupId: group.id, userGroup: group.name, permission: 1}); this.addNewItem({teamId: group.id, team: group.name, permission: 1});
this.$scope.$broadcast('user-group-picker-reset'); this.$scope.$broadcast('team-picker-reset');
} }
removeItem(index) { removeItem(index) {
...@@ -179,7 +179,7 @@ export function dashAclModal() { ...@@ -179,7 +179,7 @@ export function dashAclModal() {
export interface FormModel { export interface FormModel {
dashboardId: number; dashboardId: number;
userId?: number; userId?: number;
userGroupId?: number; teamId?: number;
PermissionType: number; PermissionType: number;
} }
...@@ -189,8 +189,8 @@ export interface DashboardAcl { ...@@ -189,8 +189,8 @@ export interface DashboardAcl {
userId?: number; userId?: number;
userLogin?: string; userLogin?: string;
userEmail?: string; userEmail?: string;
userGroupId?: number; teamId?: number;
userGroup?: string; team?: string;
permission?: number; permission?: number;
permissionName?: string; permissionName?: string;
role?: string; role?: string;
......
...@@ -40,12 +40,12 @@ describe('AclCtrl', () => { ...@@ -40,12 +40,12 @@ describe('AclCtrl', () => {
ctx.ctrl.userPicked(userItem); ctx.ctrl.userPicked(userItem);
const userGroupItem = { const teamItem = {
id: 2, id: 2,
name: 'ug1', name: 'ug1',
}; };
ctx.ctrl.groupPicked(userGroupItem); ctx.ctrl.groupPicked(teamItem);
ctx.ctrl.newType = 'Editor'; ctx.ctrl.newType = 'Editor';
ctx.ctrl.typeChanged(); ctx.ctrl.typeChanged();
...@@ -54,10 +54,10 @@ describe('AclCtrl', () => { ...@@ -54,10 +54,10 @@ describe('AclCtrl', () => {
ctx.ctrl.typeChanged(); ctx.ctrl.typeChanged();
}); });
it('should sort the result by role, user group and user', () => { it('should sort the result by role, team and user', () => {
expect(ctx.ctrl.items[0].role).to.eql('Viewer'); expect(ctx.ctrl.items[0].role).to.eql('Viewer');
expect(ctx.ctrl.items[1].role).to.eql('Editor'); expect(ctx.ctrl.items[1].role).to.eql('Editor');
expect(ctx.ctrl.items[2].userGroupId).to.eql(2); expect(ctx.ctrl.items[2].teamId).to.eql(2);
expect(ctx.ctrl.items[3].userId).to.eql(2); expect(ctx.ctrl.items[3].userId).to.eql(2);
}); });
...@@ -71,7 +71,7 @@ describe('AclCtrl', () => { ...@@ -71,7 +71,7 @@ describe('AclCtrl', () => {
expect(backendSrv.post.getCall(0).args[1].items[0].permission).to.eql(1); expect(backendSrv.post.getCall(0).args[1].items[0].permission).to.eql(1);
expect(backendSrv.post.getCall(0).args[1].items[1].role).to.eql('Editor'); expect(backendSrv.post.getCall(0).args[1].items[1].role).to.eql('Editor');
expect(backendSrv.post.getCall(0).args[1].items[1].permission).to.eql(1); expect(backendSrv.post.getCall(0).args[1].items[1].permission).to.eql(1);
expect(backendSrv.post.getCall(0).args[1].items[2].userGroupId).to.eql(2); expect(backendSrv.post.getCall(0).args[1].items[2].teamId).to.eql(2);
expect(backendSrv.post.getCall(0).args[1].items[2].permission).to.eql(1); expect(backendSrv.post.getCall(0).args[1].items[2].permission).to.eql(1);
expect(backendSrv.post.getCall(0).args[1].items[3].userId).to.eql(2); expect(backendSrv.post.getCall(0).args[1].items[3].userId).to.eql(2);
expect(backendSrv.post.getCall(0).args[1].items[3].permission).to.eql(1); expect(backendSrv.post.getCall(0).args[1].items[3].permission).to.eql(1);
...@@ -124,19 +124,19 @@ describe('AclCtrl', () => { ...@@ -124,19 +124,19 @@ describe('AclCtrl', () => {
}); });
}); });
describe('when duplicate user group permissions are added', () => { describe('when duplicate team permissions are added', () => {
beforeEach(() => { beforeEach(() => {
backendSrv.get.reset(); backendSrv.get.reset();
backendSrv.post.reset(); backendSrv.post.reset();
ctx.ctrl.items = []; ctx.ctrl.items = [];
const userGroupItem = { const teamItem = {
id: 2, id: 2,
name: 'ug1', name: 'ug1',
}; };
ctx.ctrl.groupPicked(userGroupItem); ctx.ctrl.groupPicked(teamItem);
ctx.ctrl.groupPicked(userGroupItem); ctx.ctrl.groupPicked(teamItem);
}); });
it('should throw a validation error', () => { it('should throw a validation error', () => {
...@@ -148,25 +148,25 @@ describe('AclCtrl', () => { ...@@ -148,25 +148,25 @@ describe('AclCtrl', () => {
}); });
}); });
describe('when one inherited and one not inherited user group permission are added', () => { describe('when one inherited and one not inherited team permission are added', () => {
beforeEach(() => { beforeEach(() => {
backendSrv.get.reset(); backendSrv.get.reset();
backendSrv.post.reset(); backendSrv.post.reset();
ctx.ctrl.items = []; ctx.ctrl.items = [];
const inheritedUserGroupItem = { const inheritedTeamItem = {
id: 2, id: 2,
name: 'ug1', name: 'ug1',
dashboardId: -1 dashboardId: -1
}; };
ctx.ctrl.items.push(inheritedUserGroupItem); ctx.ctrl.items.push(inheritedTeamItem);
const userGroupItem = { const teamItem = {
id: 2, id: 2,
name: 'ug1', name: 'ug1',
}; };
ctx.ctrl.groupPicked(userGroupItem); ctx.ctrl.groupPicked(teamItem);
}); });
it('should not throw a validation error', () => { it('should not throw a validation error', () => {
......
...@@ -5,7 +5,9 @@ import './select_org_ctrl'; ...@@ -5,7 +5,9 @@ import './select_org_ctrl';
import './change_password_ctrl'; import './change_password_ctrl';
import './new_org_ctrl'; import './new_org_ctrl';
import './user_invite_ctrl'; import './user_invite_ctrl';
import './user_groups_ctrl'; import './teams_ctrl';
import './team_details_ctrl';
import './create_team_modal';
import './org_api_keys_ctrl'; import './org_api_keys_ctrl';
import './org_details_ctrl'; import './org_details_ctrl';
import './prefs_control'; import './prefs_control';
...@@ -3,17 +3,17 @@ ...@@ -3,17 +3,17 @@
import coreModule from 'app/core/core_module'; import coreModule from 'app/core/core_module';
import appEvents from 'app/core/app_events'; import appEvents from 'app/core/app_events';
export class CreateUserGroupCtrl { export class CreateTeamCtrl {
userGroupName = ''; teamName = '';
/** @ngInject */ /** @ngInject */
constructor(private backendSrv, private $location) { constructor(private backendSrv, private $location) {
} }
createUserGroup() { createTeam() {
this.backendSrv.post('/api/user-groups', {name: this.userGroupName}).then((result) => { this.backendSrv.post('/api/teams', {name: this.teamName}).then((result) => {
if (result.userGroupId) { if (result.teamId) {
this.$location.path('/org/user-groups/edit/' + result.userGroupId); this.$location.path('/org/teams/edit/' + result.teamId);
} }
this.dismiss(); this.dismiss();
}); });
...@@ -24,14 +24,14 @@ export class CreateUserGroupCtrl { ...@@ -24,14 +24,14 @@ export class CreateUserGroupCtrl {
} }
} }
export function createUserGroupModal() { export function createTeamModal() {
return { return {
restrict: 'E', restrict: 'E',
templateUrl: 'public/app/features/org/partials/create_user_group.html', templateUrl: 'public/app/features/org/partials/create_team.html',
controller: CreateUserGroupCtrl, controller: CreateTeamCtrl,
bindToController: true, bindToController: true,
controllerAs: 'ctrl', controllerAs: 'ctrl',
}; };
} }
coreModule.directive('createUserGroupModal', createUserGroupModal); coreModule.directive('createTeamModal', createTeamModal);
<div class="modal-body"> <div class="modal-body">
<div class="modal-header"> <div class="modal-header">
<h2 class="modal-header-title"> <h2 class="modal-header-title">
<span class="p-l-1">Create User Group</span> <span class="p-l-1">Create Team</span>
</h2> </h2>
<a class="modal-header-close" ng-click="ctrl.dismiss();"> <a class="modal-header-close" ng-click="ctrl.dismiss();">
...@@ -10,14 +10,14 @@ ...@@ -10,14 +10,14 @@
</div> </div>
<div class="modal-content"> <div class="modal-content">
<form name="ctrl.createUserGroupForm" class="gf-form-group" novalidate> <form name="ctrl.createTeamForm" class="gf-form-group" novalidate>
<div class="p-t-2"> <div class="p-t-2">
<div class="gf-form-inline"> <div class="gf-form-inline">
<div class="gf-form max-width-21"> <div class="gf-form max-width-21">
<input type="text" class="gf-form-input" ng-model='ctrl.userGroupName' required give-focus="true" placeholder="Enter User Group Name"></input> <input type="text" class="gf-form-input" ng-model='ctrl.teamName' required give-focus="true" placeholder="Enter Team Name"></input>
</div> </div>
<div class="gf-form"> <div class="gf-form">
<button class="btn gf-form-btn btn-success" ng-click="ctrl.createUserGroup();ctrl.dismiss();">Create</button> <button class="btn gf-form-btn btn-success" ng-click="ctrl.createTeam();ctrl.dismiss();">Create</button>
</div> </div>
</div> </div>
</div> </div>
......
...@@ -2,13 +2,13 @@ ...@@ -2,13 +2,13 @@
<div class="page-container"> <div class="page-container">
<div class="page-header"> <div class="page-header">
<h1>Edit User Group</h1> <h1>Edit Team</h1>
</div> </div>
<form name="userGroupDetailsForm" class="gf-form-group gf-form-inline"> <form name="teamDetailsForm" class="gf-form-group gf-form-inline">
<div class="gf-form"> <div class="gf-form">
<span class="gf-form-label width-10">Name</span> <span class="gf-form-label width-10">Name</span>
<input type="text" required ng-model="ctrl.userGroup.name" class="gf-form-input max-width-14" > <input type="text" required ng-model="ctrl.team.name" class="gf-form-input max-width-14" >
</div> </div>
<div class="gf-form"> <div class="gf-form">
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
</form> </form>
<div class="gf-form-group"> <div class="gf-form-group">
<h3 class="page-heading">User Group Members</h3> <h3 class="page-heading">Team Members</h3>
<form name="ctrl.addMemberForm" class="gf-form-group"> <form name="ctrl.addMemberForm" class="gf-form-group">
<div class="gf-form"> <div class="gf-form">
...@@ -26,24 +26,24 @@ ...@@ -26,24 +26,24 @@
</div> </div>
</form> </form>
<table class="grafana-options-table" ng-show="ctrl.userGroupMembers.length > 0"> <table class="grafana-options-table" ng-show="ctrl.teamMembers.length > 0">
<tr> <tr>
<th>Username</th> <th>Username</th>
<th>Email</th> <th>Email</th>
<th></th> <th></th>
</tr> </tr>
<tr ng-repeat="member in ctrl.userGroupMembers"> <tr ng-repeat="member in ctrl.teamMembers">
<td>{{member.login}}</td> <td>{{member.login}}</td>
<td>{{member.email}}</td> <td>{{member.email}}</td>
<td style="width: 1%"> <td style="width: 1%">
<a ng-click="ctrl.removeUserGroupMember(member)" class="btn btn-danger btn-mini"> <a ng-click="ctrl.removeTeamMember(member)" class="btn btn-danger btn-mini">
<i class="fa fa-remove"></i> <i class="fa fa-remove"></i>
</a> </a>
</td> </td>
</tr> </tr>
</table> </table>
<div> <div>
<em class="muted" ng-hide="ctrl.userGroupMembers.length > 0"> <em class="muted" ng-hide="ctrl.teamMembers.length > 0">
This user group has no members yet. This team has no members yet.
</em> </em>
</div> </div>
...@@ -5,20 +5,20 @@ ...@@ -5,20 +5,20 @@
<div class="gf-form gf-form--grow"> <div class="gf-form gf-form--grow">
<label class="gf-form-label">Search</label> <label class="gf-form-label">Search</label>
<input type="text" class="gf-form-input max-width-20" placeholder="Find User Group by name" tabindex="1" give-focus="true" <input type="text" class="gf-form-input max-width-20" placeholder="Find Team by name" tabindex="1" give-focus="true"
ng-model="ctrl.query" ng-model-options="{ debounce: 500 }" spellcheck='false' ng-change="ctrl.get()" /> ng-model="ctrl.query" ng-model-options="{ debounce: 500 }" spellcheck='false' ng-change="ctrl.get()" />
</div> </div>
<div class="page-action-bar__spacer"></div> <div class="page-action-bar__spacer"></div>
<a class="btn btn-success" ng-click="ctrl.openUserGroupModal()"> <a class="btn btn-success" ng-click="ctrl.openTeamModal()">
<i class="fa fa-plus"></i> <i class="fa fa-plus"></i>
Add Team Add Team
</a> </a>
</div> </div>
<div class="admin-list-table"> <div class="admin-list-table">
<table class="filter-table form-inline" ng-show="ctrl.userGroups.length > 0"> <table class="filter-table form-inline" ng-show="ctrl.teams.length > 0">
<thead> <thead>
<tr> <tr>
<th>Name</th> <th>Name</th>
...@@ -27,18 +27,18 @@ ...@@ -27,18 +27,18 @@
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<tr ng-repeat="userGroup in ctrl.userGroups"> <tr ng-repeat="team in ctrl.teams">
<td> <td>
<a href="org/user-groups/edit/{{userGroup.id}}">{{userGroup.name}}</a> <a href="org/teams/edit/{{team.id}}">{{team.name}}</a>
</td> </td>
<td>#Count</td> <td>#Count</td>
<td class="text-right"> <td class="text-right">
<a href="org/user-groups/edit/{{userGroup.id}}" class="btn btn-inverse btn-small"> <a href="org/teams/edit/{{team.id}}" class="btn btn-inverse btn-small">
<i class="fa fa-edit"></i> <i class="fa fa-edit"></i>
Edit Edit
</a> </a>
&nbsp;&nbsp; &nbsp;&nbsp;
<a ng-click="ctrl.deleteUserGroup(userGroup)" class="btn btn-danger btn-small"> <a ng-click="ctrl.deleteTeam(team)" class="btn btn-danger btn-small">
<i class="fa fa-remove"></i> <i class="fa fa-remove"></i>
</a> </a>
</td> </td>
...@@ -58,7 +58,7 @@ ...@@ -58,7 +58,7 @@
</ol> </ol>
</div> </div>
<em class="muted" ng-hide="ctrl.userGroups.length > 0"> <em class="muted" ng-hide="ctrl.teams.length > 0">
No User Groups found. No Teams found.
</em> </em>
</div> </div>
import '../user_group_details_ctrl'; import '../team_details_ctrl';
import {describe, beforeEach, it, expect, sinon, angularMocks} from 'test/lib/common'; import {describe, beforeEach, it, expect, sinon, angularMocks} from 'test/lib/common';
import UserGroupDetailsCtrl from '../user_group_details_ctrl'; import TeamDetailsCtrl from '../team_details_ctrl';
describe('UserGroupDetailsCtrl', () => { describe('TeamDetailsCtrl', () => {
var ctx: any = {}; var ctx: any = {};
var backendSrv = { var backendSrv = {
searchUsers: sinon.stub().returns(Promise.resolve([])), searchUsers: sinon.stub().returns(Promise.resolve([])),
...@@ -16,7 +16,7 @@ var backendSrv = { ...@@ -16,7 +16,7 @@ var backendSrv = {
beforeEach(angularMocks.inject(($rootScope, $controller, $q) => { beforeEach(angularMocks.inject(($rootScope, $controller, $q) => {
ctx.$q = $q; ctx.$q = $q;
ctx.scope = $rootScope.$new(); ctx.scope = $rootScope.$new();
ctx.ctrl = $controller(UserGroupDetailsCtrl, { ctx.ctrl = $controller(TeamDetailsCtrl, {
$scope: ctx.scope, $scope: ctx.scope,
backendSrv: backendSrv, backendSrv: backendSrv,
$routeParams: {id: 1}, $routeParams: {id: 1},
...@@ -24,7 +24,7 @@ var backendSrv = { ...@@ -24,7 +24,7 @@ var backendSrv = {
}); });
})); }));
describe('when user is chosen to be added to user group', () => { describe('when user is chosen to be added to team', () => {
beforeEach(() => { beforeEach(() => {
const userItem = { const userItem = {
id: 2, id: 2,
...@@ -34,13 +34,13 @@ var backendSrv = { ...@@ -34,13 +34,13 @@ var backendSrv = {
}); });
it('should parse the result and save to db', () => { it('should parse the result and save to db', () => {
expect(backendSrv.post.getCall(0).args[0]).to.eql('/api/user-groups/1/members'); expect(backendSrv.post.getCall(0).args[0]).to.eql('/api/teams/1/members');
expect(backendSrv.post.getCall(0).args[1].userId).to.eql(2); expect(backendSrv.post.getCall(0).args[1].userId).to.eql(2);
}); });
it('should refresh the list after saving.', () => { it('should refresh the list after saving.', () => {
expect(backendSrv.get.getCall(0).args[0]).to.eql('/api/user-groups/1'); expect(backendSrv.get.getCall(0).args[0]).to.eql('/api/teams/1');
expect(backendSrv.get.getCall(1).args[0]).to.eql('/api/user-groups/1/members'); expect(backendSrv.get.getCall(1).args[0]).to.eql('/api/teams/1/members');
}); });
}); });
}); });
...@@ -2,9 +2,9 @@ ...@@ -2,9 +2,9 @@
import coreModule from 'app/core/core_module'; import coreModule from 'app/core/core_module';
export default class UserGroupDetailsCtrl { export default class TeamDetailsCtrl {
userGroup: UserGroup; team: Team;
userGroupMembers: User[] = []; teamMembers: User[] = [];
navModel: any; navModel: any;
constructor(private $scope, private backendSrv, private $routeParams, navModelSrv) { constructor(private $scope, private backendSrv, private $routeParams, navModelSrv) {
...@@ -14,49 +14,49 @@ export default class UserGroupDetailsCtrl { ...@@ -14,49 +14,49 @@ export default class UserGroupDetailsCtrl {
get() { get() {
if (this.$routeParams && this.$routeParams.id) { if (this.$routeParams && this.$routeParams.id) {
this.backendSrv.get(`/api/user-groups/${this.$routeParams.id}`) this.backendSrv.get(`/api/teams/${this.$routeParams.id}`)
.then(result => { .then(result => {
this.userGroup = result; this.team = result;
}); });
this.backendSrv.get(`/api/user-groups/${this.$routeParams.id}/members`) this.backendSrv.get(`/api/teams/${this.$routeParams.id}/members`)
.then(result => { .then(result => {
this.userGroupMembers = result; this.teamMembers = result;
}); });
} }
} }
removeUserGroupMember(userGroupMember: UserGroupMember) { removeTeamMember(teamMember: TeamMember) {
this.$scope.appEvent('confirm-modal', { this.$scope.appEvent('confirm-modal', {
title: 'Remove Member', title: 'Remove Member',
text: 'Are you sure you want to remove ' + userGroupMember.name + ' from this group?', text: 'Are you sure you want to remove ' + teamMember.name + ' from this group?',
yesText: "Remove", yesText: "Remove",
icon: "fa-warning", icon: "fa-warning",
onConfirm: () => { onConfirm: () => {
this.removeMemberConfirmed(userGroupMember); this.removeMemberConfirmed(teamMember);
} }
}); });
} }
removeMemberConfirmed(userGroupMember: UserGroupMember) { removeMemberConfirmed(teamMember: TeamMember) {
this.backendSrv.delete(`/api/user-groups/${this.$routeParams.id}/members/${userGroupMember.userId}`) this.backendSrv.delete(`/api/teams/${this.$routeParams.id}/members/${teamMember.userId}`)
.then(this.get.bind(this)); .then(this.get.bind(this));
} }
update() { update() {
if (!this.$scope.userGroupDetailsForm.$valid) { return; } if (!this.$scope.teamDetailsForm.$valid) { return; }
this.backendSrv.put('/api/user-groups/' + this.userGroup.id, {name: this.userGroup.name}); this.backendSrv.put('/api/teams/' + this.team.id, {name: this.team.name});
} }
userPicked(user) { userPicked(user) {
this.backendSrv.post(`/api/user-groups/${this.$routeParams.id}/members`, {userId: user.id}).then(() => { this.backendSrv.post(`/api/teams/${this.$routeParams.id}/members`, {userId: user.id}).then(() => {
this.$scope.$broadcast('user-picker-reset'); this.$scope.$broadcast('user-picker-reset');
this.get(); this.get();
}); });
} }
} }
export interface UserGroup { export interface Team {
id: number; id: number;
name: string; name: string;
} }
...@@ -68,10 +68,10 @@ export interface User { ...@@ -68,10 +68,10 @@ export interface User {
email: string; email: string;
} }
export interface UserGroupMember { export interface TeamMember {
userId: number; userId: number;
name: string; name: string;
} }
coreModule.controller('UserGroupDetailsCtrl', UserGroupDetailsCtrl); coreModule.controller('TeamDetailsCtrl', TeamDetailsCtrl);
...@@ -3,8 +3,8 @@ ...@@ -3,8 +3,8 @@
import coreModule from 'app/core/core_module'; import coreModule from 'app/core/core_module';
import {appEvents} from 'app/core/core'; import {appEvents} from 'app/core/core';
export class UserGroupsCtrl { export class TeamsCtrl {
userGroups: any; teams: any;
pages = []; pages = [];
perPage = 50; perPage = 50;
page = 1; page = 1;
...@@ -20,9 +20,9 @@ export class UserGroupsCtrl { ...@@ -20,9 +20,9 @@ export class UserGroupsCtrl {
} }
get() { get() {
this.backendSrv.get(`/api/user-groups/search?perpage=${this.perPage}&page=${this.page}&query=${this.query}`) this.backendSrv.get(`/api/teams/search?perpage=${this.perPage}&page=${this.page}&query=${this.query}`)
.then((result) => { .then((result) => {
this.userGroups = result.userGroups; this.teams = result.teams;
this.page = result.page; this.page = result.page;
this.perPage = result.perPage; this.perPage = result.perPage;
this.totalPages = Math.ceil(result.totalCount / result.perPage); this.totalPages = Math.ceil(result.totalCount / result.perPage);
...@@ -40,29 +40,29 @@ export class UserGroupsCtrl { ...@@ -40,29 +40,29 @@ export class UserGroupsCtrl {
this.get(); this.get();
} }
deleteUserGroup(userGroup) { deleteTeam(team) {
appEvents.emit('confirm-modal', { appEvents.emit('confirm-modal', {
title: 'Delete', title: 'Delete',
text: 'Are you sure you want to delete User Group ' + userGroup.name + '?', text: 'Are you sure you want to delete Team ' + team.name + '?',
yesText: "Delete", yesText: "Delete",
icon: "fa-warning", icon: "fa-warning",
onConfirm: () => { onConfirm: () => {
this.deleteUserGroupConfirmed(userGroup); this.deleteTeamConfirmed(team);
} }
}); });
} }
deleteUserGroupConfirmed(userGroup) { deleteTeamConfirmed(team) {
this.backendSrv.delete('/api/user-groups/' + userGroup.id) this.backendSrv.delete('/api/teams/' + team.id)
.then(this.get.bind(this)); .then(this.get.bind(this));
} }
openUserGroupModal() { openTeamModal() {
appEvents.emit('show-modal', { appEvents.emit('show-modal', {
templateHtml: '<create-user-group-modal></create-user-group-modal>', templateHtml: '<create-team-modal></create-team-modal>',
modalClass: 'modal--narrow' modalClass: 'modal--narrow'
}); });
} }
} }
coreModule.controller('UserGroupsCtrl', UserGroupsCtrl); coreModule.controller('TeamsCtrl', TeamsCtrl);
...@@ -13,14 +13,14 @@ ...@@ -13,14 +13,14 @@
</div> </div>
</div> </div>
</li> </li>
<li class="card-item-wrapper" ng-repeat="permission in ctrl.userGroupPermissions"> <li class="card-item-wrapper" ng-repeat="permission in ctrl.teamPermissions">
<div class="card-item card-item--alert"> <div class="card-item card-item--alert">
<div class="card-item-header"> <div class="card-item-header">
<div class="card-item-sub-name">{{permission.permissionName}}</div> <div class="card-item-sub-name">{{permission.permissionName}}</div>
</div> </div>
<div class="card-item-body"> <div class="card-item-body">
<div class="card-item-details"> <div class="card-item-details">
<div class="card-item-notice">{{permission.userGroup}}</div> <div class="card-item-notice">{{permission.team}}</div>
</div> </div>
</div> </div>
</div> </div>
......
...@@ -7,7 +7,7 @@ class PermissionListCtrl extends PanelCtrl { ...@@ -7,7 +7,7 @@ class PermissionListCtrl extends PanelCtrl {
static templateUrl = 'module.html'; static templateUrl = 'module.html';
userPermissions: any[]; userPermissions: any[];
userGroupPermissions: any[]; teamPermissions: any[];
roles: any[]; roles: any[];
panelDefaults = { panelDefaults = {
...@@ -48,7 +48,7 @@ class PermissionListCtrl extends PanelCtrl { ...@@ -48,7 +48,7 @@ class PermissionListCtrl extends PanelCtrl {
return this.backendSrv.get(`/api/dashboards/id/${this.panel.folderId}/acl`) return this.backendSrv.get(`/api/dashboards/id/${this.panel.folderId}/acl`)
.then(result => { .then(result => {
this.userPermissions = _.filter(result, p => { return p.userId > 0;}); this.userPermissions = _.filter(result, p => { return p.userId > 0;});
this.userGroupPermissions = _.filter(result, p => { return p.userGroupId > 0;}); this.teamPermissions = _.filter(result, p => { return p.teamId > 0;});
// this.roles = this.setRoles(result); // this.roles = this.setRoles(result);
}); });
} }
......
...@@ -51,8 +51,8 @@ ...@@ -51,8 +51,8 @@
background-image: url('../img/icons_#{$theme-name}_theme/icon_notification_channels.svg'); background-image: url('../img/icons_#{$theme-name}_theme/icon_notification_channels.svg');
} }
.gicon-user-group { .gicon-team {
background-image: url('../img/icons_#{$theme-name}_theme/icon_user_group.svg'); background-image: url('../img/icons_#{$theme-name}_theme/icon_team.svg');
} }
.gicon-org { .gicon-org {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment