diff options
author | Corey Hulen <corey@hulen.com> | 2016-05-06 11:28:22 -0700 |
---|---|---|
committer | Christopher Speller <crspeller@gmail.com> | 2016-05-06 14:28:22 -0400 |
commit | 6c75662b824491a20a757a5eec59556a866374b5 (patch) | |
tree | 2f531a680aaa45bc915d51764eb846bc1b80fa68 | |
parent | 4f799b980fd457e5dc97d2427a154576d7a5eded (diff) | |
download | chat-6c75662b824491a20a757a5eec59556a866374b5.tar.gz chat-6c75662b824491a20a757a5eec59556a866374b5.tar.bz2 chat-6c75662b824491a20a757a5eec59556a866374b5.zip |
PLT-2697 Fixing team admins (#2900)
* PLT-2697 Fixing team admins
* Fixing eslint error
* Fixing loc issues
* Fixing func
* Fixing func
30 files changed, 441 insertions, 141 deletions
diff --git a/api/apitestlib.go b/api/apitestlib.go index a7c2a9406..6372ea6b1 100644 --- a/api/apitestlib.go +++ b/api/apitestlib.go @@ -89,7 +89,7 @@ func (me *TestHelper) InitSystemAdmin() *TestHelper { c := &Context{} c.RequestId = model.NewId() c.IpAddress = "cmd_line" - UpdateRoles(c, me.SystemAdminUser, model.ROLE_SYSTEM_ADMIN) + UpdateUserRoles(c, me.SystemAdminUser, model.ROLE_SYSTEM_ADMIN) me.SystemAdminUser.Password = "Password1" me.LoginSystemAdmin() me.SystemAdminChannel = me.CreateChannel(me.SystemAdminClient, me.SystemAdminTeam) diff --git a/api/context.go b/api/context.go index 03d0046be..67b04c391 100644 --- a/api/context.go +++ b/api/context.go @@ -372,12 +372,12 @@ func (c *Context) IsTeamAdmin() bool { return true } - team := c.Session.GetTeamByTeamId(c.TeamId) - if team == nil { + teamMember := c.Session.GetTeamByTeamId(c.TeamId) + if teamMember == nil { return false } - return model.IsInRole(team.Roles, model.ROLE_TEAM_ADMIN) + return teamMember.IsTeamAdmin() } func (c *Context) RemoveSessionCookie(w http.ResponseWriter, r *http.Request) { diff --git a/api/team_test.go b/api/team_test.go index a58260fd2..30952b4d8 100644 --- a/api/team_test.go +++ b/api/team_test.go @@ -252,7 +252,7 @@ func TestGetAllTeams(t *testing.T) { c := &Context{} c.RequestId = model.NewId() c.IpAddress = "cmd_line" - UpdateRoles(c, user, model.ROLE_SYSTEM_ADMIN) + UpdateUserRoles(c, user, model.ROLE_SYSTEM_ADMIN) Client.Login(user.Email, "pwd") Client.SetTeamId(team.Id) @@ -301,7 +301,7 @@ func TestGetAllTeamListings(t *testing.T) { c := &Context{} c.RequestId = model.NewId() c.IpAddress = "cmd_line" - UpdateRoles(c, user, model.ROLE_SYSTEM_ADMIN) + UpdateUserRoles(c, user, model.ROLE_SYSTEM_ADMIN) Client.Login(user.Email, "pwd") Client.SetTeamId(team.Id) diff --git a/api/user.go b/api/user.go index de4242f24..60162d8f1 100644 --- a/api/user.go +++ b/api/user.go @@ -1372,16 +1372,23 @@ func updateRoles(c *Context, w http.ResponseWriter, r *http.Request) { return } + team_id := props["team_id"] + if !(len(user_id) == 26 || len(user_id) == 0) { + c.SetInvalidParam("updateRoles", "team_id") + return + } + new_roles := props["new_roles"] - if !model.IsValidUserRoles(new_roles) { + if !(model.IsValidUserRoles(new_roles) || model.IsValidTeamRoles(new_roles)) { c.SetInvalidParam("updateRoles", "new_roles") return } // If you are not the system admin then you can only demote yourself if !c.IsSystemAdmin() && user_id != c.Session.UserId { - c.Err = model.NewLocAppError("updateRoles", "api.user.update_roles.system_admin_set.app_error", nil, "") + c.Err = model.NewLocAppError("updateRoles", "api.user.update_roles.system_admin_needed.app_error", nil, "") c.Err.StatusCode = http.StatusForbidden + return } // Only another system admin can add the system admin role @@ -1399,36 +1406,78 @@ func updateRoles(c *Context, w http.ResponseWriter, r *http.Request) { user = result.Data.(*model.User) } - ruser := UpdateRoles(c, user, new_roles) - if c.Err != nil { - return - } + // if the team role has changed then lets update team members + if model.IsValidTeamRoles(new_roles) && len(team_id) > 0 { + + var members []*model.TeamMember + if result := <-Srv.Store.Team().GetTeamsForUser(user_id); result.Err != nil { + c.Err = result.Err + return + } else { + members = result.Data.([]*model.TeamMember) + } + + var member *model.TeamMember + for _, m := range members { + if m.TeamId == team_id { + member = m + } + } - uchan := Srv.Store.Session().UpdateRoles(user.Id, new_roles) - gchan := Srv.Store.Session().GetSessions(user.Id) + if member == nil { + c.SetInvalidParam("updateRoles", "team_id") + return + } - if result := <-uchan; result.Err != nil { - // soft error since the user roles were still updated - l4g.Error(result.Err) + if !c.IsSystemAdmin() { + currentUserTeamMember := c.Session.GetTeamByTeamId(team_id) + + // Only the system admin can modify other team + if currentUserTeamMember == nil { + c.Err = model.NewLocAppError("updateRoles", "api.user.update_roles.system_admin_needed.app_error", nil, "") + c.Err.StatusCode = http.StatusForbidden + return + } + + // Only another team admin can make a team admin + if !currentUserTeamMember.IsTeamAdmin() && model.IsInRole(new_roles, model.ROLE_TEAM_ADMIN) { + c.Err = model.NewLocAppError("updateRoles", "api.user.update_roles.team_admin_needed.app_error", nil, "") + c.Err.StatusCode = http.StatusForbidden + return + } + } + + member.Roles = new_roles + + if result := <-Srv.Store.Team().UpdateMember(member); result.Err != nil { + c.Err = result.Err + return + } } - if result := <-gchan; result.Err != nil { - // soft error since the user roles were still updated - l4g.Error(result.Err) - } else { - sessions := result.Data.([]*model.Session) - for _, s := range sessions { - sessionCache.Remove(s.Token) + // If the users role has changed then lets update the user + if model.IsValidUserRoles(new_roles) { + UpdateUserRoles(c, user, new_roles) + if c.Err != nil { + return + } + + uchan := Srv.Store.Session().UpdateRoles(user.Id, new_roles) + + if result := <-uchan; result.Err != nil { + // soft error since the user roles were still updated + l4g.Error(result.Err) } } - options := utils.Cfg.GetSanitizeOptions() - options["passwordupdate"] = false - ruser.Sanitize(options) - w.Write([]byte(ruser.ToJson())) + RemoveAllSessionsForUserId(user_id) + + data := make(map[string]string) + data["user_id"] = user_id + w.Write([]byte(model.MapToJson(data))) } -func UpdateRoles(c *Context, user *model.User, roles string) *model.User { +func UpdateUserRoles(c *Context, user *model.User, roles string) *model.User { user.Roles = roles diff --git a/api/user_test.go b/api/user_test.go index 629f7d257..1a3b36d4b 100644 --- a/api/user_test.go +++ b/api/user_test.go @@ -366,7 +366,7 @@ func TestGetUser(t *testing.T) { c := &Context{} c.RequestId = model.NewId() c.IpAddress = "cmd_line" - UpdateRoles(c, ruser.Data.(*model.User), model.ROLE_SYSTEM_ADMIN) + UpdateUserRoles(c, ruser.Data.(*model.User), model.ROLE_SYSTEM_ADMIN) Client.Login(user.Email, "pwd") @@ -791,7 +791,6 @@ func TestUserUpdateRoles(t *testing.T) { Client.Login(user.Email, "pwd") data["user_id"] = "junk" - data["new_roles"] = "admin" if _, err := Client.UpdateUserRoles(data); err == nil { t.Fatal("Should have errored, bad id") @@ -804,12 +803,141 @@ func TestUserUpdateRoles(t *testing.T) { } data["user_id"] = user2.Id + data["new_roles"] = "junk" if _, err := Client.UpdateUserRoles(data); err == nil { t.Fatal("Should have errored, bad role") } } +func TestUserUpdateRolesMoreCases(t *testing.T) { + th := Setup().InitSystemAdmin().InitBasic() + + data := make(map[string]string) + + // invalid team Id + data["user_id"] = th.BasicUser2.Id + data["new_roles"] = "" + data["team_id"] = model.NewId() + if _, err := th.BasicClient.UpdateUserRoles(data); err == nil { + t.Fatal("Should have errored") + } + + // user 1 is trying to change user 2 + data["user_id"] = th.BasicUser2.Id + data["new_roles"] = "" + data["team_id"] = th.BasicTeam.Id + if _, err := th.BasicClient.UpdateUserRoles(data); err == nil { + t.Fatal("Should have errored, you can only demote yourself") + } + + // user 1 is trying to promote user 2 + data["user_id"] = th.BasicUser2.Id + data["new_roles"] = model.ROLE_TEAM_ADMIN + data["team_id"] = th.BasicTeam.Id + if _, err := th.BasicClient.UpdateUserRoles(data); err == nil { + t.Fatal("Should have errored, you can only demote yourself") + } + + // user 1 is trying to promote user 2 + data["user_id"] = th.BasicUser2.Id + data["new_roles"] = model.ROLE_SYSTEM_ADMIN + data["team_id"] = th.BasicTeam.Id + if _, err := th.BasicClient.UpdateUserRoles(data); err == nil { + t.Fatal("Should have errored, you can only demote yourself") + } + + // user 1 is trying to promote himself + data["user_id"] = th.BasicUser.Id + data["new_roles"] = model.ROLE_TEAM_ADMIN + data["team_id"] = th.BasicTeam.Id + if _, err := th.BasicClient.UpdateUserRoles(data); err == nil { + t.Fatal("Should have errored, you cannot elevate your permissions") + } + + // user 1 is trying to promote himself + data["user_id"] = th.BasicUser.Id + data["new_roles"] = model.ROLE_SYSTEM_ADMIN + data["team_id"] = th.BasicTeam.Id + if _, err := th.BasicClient.UpdateUserRoles(data); err == nil { + t.Fatal("Should have errored, you cannot elevate your permissions") + } + + th.LoginSystemAdmin() + + // promote user to team admin + data["user_id"] = th.BasicUser.Id + data["new_roles"] = model.ROLE_TEAM_ADMIN + data["team_id"] = th.BasicTeam.Id + if _, err := th.SystemAdminClient.UpdateUserRoles(data); err != nil { + t.Fatal("Should have succeeded since they are system admin") + } + + // demote team admin to basic member + data["user_id"] = th.BasicUser.Id + data["new_roles"] = "" + data["team_id"] = th.BasicTeam.Id + if _, err := th.SystemAdminClient.UpdateUserRoles(data); err != nil { + t.Fatal("Should have succeeded since they are system admin") + } + + // re-promote user to team admin + data["user_id"] = th.BasicUser.Id + data["new_roles"] = model.ROLE_TEAM_ADMIN + data["team_id"] = th.BasicTeam.Id + if _, err := th.SystemAdminClient.UpdateUserRoles(data); err != nil { + t.Fatal("Should have succeeded since they are system admin") + } + + // user 1 is promoting user 2 to team admin + data["user_id"] = th.BasicUser2.Id + data["new_roles"] = model.ROLE_TEAM_ADMIN + data["team_id"] = th.BasicTeam.Id + if _, err := th.BasicClient.UpdateUserRoles(data); err == nil { + t.Fatal("Should have succeeded since they are team admin") + } + + // user 1 is trying to promote user 2 from team admin to system admin + data["user_id"] = th.BasicUser2.Id + data["new_roles"] = model.ROLE_SYSTEM_ADMIN + data["team_id"] = th.BasicTeam.Id + if _, err := th.BasicClient.UpdateUserRoles(data); err == nil { + t.Fatal("Should have errored, can only be system admin") + } + + // user 1 is demoting user 2 to a regular member + data["user_id"] = th.BasicUser2.Id + data["new_roles"] = "" + data["team_id"] = th.BasicTeam.Id + if _, err := th.BasicClient.UpdateUserRoles(data); err == nil { + t.Fatal("Should have succeeded since they are team admin") + } + + // user 1 is trying to demote system admin + data["user_id"] = th.SystemAdminUser.Id + data["new_roles"] = "" + data["team_id"] = th.BasicTeam.Id + if _, err := th.BasicClient.UpdateUserRoles(data); err == nil { + t.Fatal("Should have errored, can only be system admin") + } + + // user 1 as team admin is demoting himself + data["user_id"] = th.BasicUser.Id + data["new_roles"] = "" + data["team_id"] = th.BasicTeam.Id + if _, err := th.BasicClient.UpdateUserRoles(data); err != nil { + t.Fatal("Should have succeeded") + } + + // system admin demoting himself + data["user_id"] = th.SystemAdminUser.Id + data["new_roles"] = "" + data["team_id"] = "" + if _, err := th.SystemAdminClient.UpdateUserRoles(data); err != nil { + t.Fatal("Should have succeeded since they are system admin") + } +} + func TestUserUpdateDeviceId(t *testing.T) { th := Setup() Client := th.CreateClient() diff --git a/config/config.json b/config/config.json index 45da5770b..7eff8ad37 100644 --- a/config/config.json +++ b/config/config.json @@ -156,4 +156,4 @@ "Directory": "./data/", "EnableDaily": false } -} +}
\ No newline at end of file diff --git a/i18n/en.json b/i18n/en.json index 9013dbea9..b888beba0 100644 --- a/i18n/en.json +++ b/i18n/en.json @@ -1704,14 +1704,18 @@ "translation": "You do not have the appropriate permissions" }, { - "id": "api.user.update_roles.system_admin_mod.app_error", - "translation": "The system admin role can only by modified by another system admin" - }, - { "id": "api.user.update_roles.system_admin_set.app_error", "translation": "The system admin role can only be set by another system admin" }, { + "id": "api.user.update_roles.system_admin_needed.app_error", + "translation": "The system admin role is needed for this action" + }, + { + "id": "api.user.update_roles.team_admin_needed.app_error", + "translation": "The team admin role is needed for this action" + }, + { "id": "api.user.upload_profile_user.array.app_error", "translation": "Empty array under 'image' in request" }, diff --git a/i18n/es.json b/i18n/es.json index 54438b879..08d14fd7e 100644 --- a/i18n/es.json +++ b/i18n/es.json @@ -1704,10 +1704,6 @@ "translation": "No tienes los permisos apropiados" }, { - "id": "api.user.update_roles.system_admin_mod.app_error", - "translation": "El rol de administrador de sistema sólo puede ser modificado por otro administrador de sistema" - }, - { "id": "api.user.update_roles.system_admin_set.app_error", "translation": "El rol de adminsitrador de sistema sólo puede ser asignado por otro administrador de sistema" }, diff --git a/i18n/fr.json b/i18n/fr.json index d2290685c..bddbf85ce 100644 --- a/i18n/fr.json +++ b/i18n/fr.json @@ -1564,10 +1564,6 @@ "translation": "Vous n'avez pas les permissions appropriées" }, { - "id": "api.user.update_roles.system_admin_mod.app_error", - "translation": "Le rôle d'administrateur système ne peut être modifié que par un autre administrateur système" - }, - { "id": "api.user.update_roles.system_admin_set.app_error", "translation": "Le rôle d'administrateur système ne peut être donné que par un autre administrateur système" }, diff --git a/i18n/ja.json b/i18n/ja.json index 290fc74f7..7fbd65254 100644 --- a/i18n/ja.json +++ b/i18n/ja.json @@ -1676,10 +1676,6 @@ "translation": "あなたには必要な権限が付与されていません" }, { - "id": "api.user.update_roles.system_admin_mod.app_error", - "translation": "システム管理者の役割は、他のシステム管理者だけが設定変更できます" - }, - { "id": "api.user.update_roles.system_admin_set.app_error", "translation": "システム管理者の役割は、他のシステム管理者だけが設定できます" }, diff --git a/i18n/pt.json b/i18n/pt.json index f51513f48..573c75f19 100644 --- a/i18n/pt.json +++ b/i18n/pt.json @@ -1700,10 +1700,6 @@ "translation": "Você não tem a permissão apropriada" }, { - "id": "api.user.update_roles.system_admin_mod.app_error", - "translation": "A função de administrador do sistema só pode ser modificado por outro administrador do sistema" - }, - { "id": "api.user.update_roles.system_admin_set.app_error", "translation": "A função de administrador do sistema só pode ser definida por um outro administrador do sistema" }, diff --git a/mattermost.go b/mattermost.go index 172c42aa1..be9b08a95 100644 --- a/mattermost.go +++ b/mattermost.go @@ -721,7 +721,7 @@ func cmdAssignRole() { } if !user.IsInRole(flagRole) { - api.UpdateRoles(c, user, flagRole) + api.UpdateUserRoles(c, user, flagRole) } os.Exit(0) diff --git a/model/client.go b/model/client.go index 54f143cfe..a74adcd7a 100644 --- a/model/client.go +++ b/model/client.go @@ -1023,7 +1023,7 @@ func (c *Client) UpdateUserRoles(data map[string]string) (*Result, *AppError) { return nil, err } else { return &Result{r.Header.Get(HEADER_REQUEST_ID), - r.Header.Get(HEADER_ETAG_SERVER), UserFromJson(r.Body)}, nil + r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil } } @@ -1069,7 +1069,7 @@ func (c *Client) UpdateUserPassword(userId, currentPassword, newPassword string) return nil, err } else { return &Result{r.Header.Get(HEADER_REQUEST_ID), - r.Header.Get(HEADER_ETAG_SERVER), UserFromJson(r.Body)}, nil + r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil } } diff --git a/model/team_member.go b/model/team_member.go index 80ca9f2a3..ae687c109 100644 --- a/model/team_member.go +++ b/model/team_member.go @@ -58,6 +58,48 @@ func TeamMembersFromJson(data io.Reader) []*TeamMember { } } +func IsValidTeamRoles(teamRoles string) bool { + + roles := strings.Split(teamRoles, " ") + + for _, r := range roles { + if !isValidTeamRole(r) { + return false + } + } + + return true +} + +func isValidTeamRole(role string) bool { + if role == "" { + return true + } + + if role == ROLE_TEAM_ADMIN { + return true + } + + return false +} + +func IsInTeamRole(teamRoles string, inRole string) bool { + roles := strings.Split(teamRoles, " ") + + for _, r := range roles { + if r == inRole { + return true + } + + } + + return false +} + +func (o *TeamMember) IsTeamAdmin() bool { + return IsInTeamRole(o.Roles, ROLE_TEAM_ADMIN) +} + func (o *TeamMember) IsValid() *AppError { if len(o.TeamId) != 26 { diff --git a/web/web_test.go b/web/web_test.go index 7a0485215..d4d9a5f26 100644 --- a/web/web_test.go +++ b/web/web_test.go @@ -203,7 +203,7 @@ func TestIncomingWebhook(t *testing.T) { c := &api.Context{} c.RequestId = model.NewId() c.IpAddress = "cmd_line" - api.UpdateRoles(c, user, model.ROLE_SYSTEM_ADMIN) + api.UpdateUserRoles(c, user, model.ROLE_SYSTEM_ADMIN) ApiClient.Login(user.Email, "pwd") ApiClient.SetTeamId(team.Id) diff --git a/webapp/client/client.jsx b/webapp/client/client.jsx index 56eb4a137..d1e250e12 100644 --- a/webapp/client/client.jsx +++ b/webapp/client/client.jsx @@ -596,8 +596,9 @@ export default class Client { end(this.handleResponse.bind(this, 'updateUserNotifyProps', success, error)); } - updateRoles = (userId, newRoles, success, error) => { + updateRoles = (teamId, userId, newRoles, success, error) => { var data = { + team_id: teamId, user_id: userId, new_roles: newRoles }; diff --git a/webapp/components/admin_console/team_users.jsx b/webapp/components/admin_console/team_users.jsx index 2b0e6af0a..e41747737 100644 --- a/webapp/components/admin_console/team_users.jsx +++ b/webapp/components/admin_console/team_users.jsx @@ -19,10 +19,12 @@ export default class UserList extends React.Component { this.doPasswordReset = this.doPasswordReset.bind(this); this.doPasswordResetDismiss = this.doPasswordResetDismiss.bind(this); this.doPasswordResetSubmit = this.doPasswordResetSubmit.bind(this); + this.getTeamMemberForUser = this.getTeamMemberForUser.bind(this); this.state = { teamId: props.team.id, users: null, + teamMembers: null, serverError: null, showPasswordModal: false, user: null @@ -38,6 +40,21 @@ export default class UserList extends React.Component { } getTeamProfiles(teamId) { + Client.getTeamMembers( + teamId, + (data) => { + this.setState({ + teamMembers: data + }); + }, + (err) => { + this.setState({ + teamMembers: null, + serverError: err.message + }); + } + ); + Client.getProfilesForTeam( teamId, (users) => { @@ -110,6 +127,22 @@ export default class UserList extends React.Component { }); } + getTeamMemberForUser(userId) { + if (this.state.teamMembers) { + for (const index in this.state.teamMembers) { + if (this.state.teamMembers.hasOwnProperty(index)) { + var teamMember = this.state.teamMembers[index]; + + if (teamMember.user_id === userId) { + return teamMember; + } + } + } + } + + return null; + } + componentWillReceiveProps(newProps) { this.getTeamProfiles(newProps.team.id); } @@ -120,7 +153,7 @@ export default class UserList extends React.Component { serverError = <div className='form-group has-error'><label className='control-label'>{this.state.serverError}</label></div>; } - if (this.state.users == null) { + if (this.state.users == null || this.state.teamMembers == null) { return ( <div className='wrapper--fixed'> <h3> @@ -139,10 +172,14 @@ export default class UserList extends React.Component { } var memberList = this.state.users.map((user) => { + var teamMember = this.getTeamMemberForUser(user.id); + return ( <UserItem + team={this.props.team} key={'user_' + user.id} user={user} + teamMember={teamMember} refreshProfiles={this.getCurrentTeamProfiles} doPasswordReset={this.doPasswordReset} />); diff --git a/webapp/components/admin_console/user_item.jsx b/webapp/components/admin_console/user_item.jsx index 660f75a41..ef6bd9f45 100644 --- a/webapp/components/admin_console/user_item.jsx +++ b/webapp/components/admin_console/user_item.jsx @@ -42,6 +42,7 @@ export default class UserItem extends React.Component { this.handleDemote(this.props.user, ''); } else { Client.updateRoles( + this.props.team.id, this.props.user.id, '', () => { @@ -85,6 +86,7 @@ export default class UserItem extends React.Component { this.handleDemote(this.props.user, 'admin'); } else { Client.updateRoles( + this.props.team.id, this.props.user.id, 'admin', () => { @@ -101,6 +103,7 @@ export default class UserItem extends React.Component { e.preventDefault(); Client.updateRoles( + this.props.team.id, this.props.user.id, 'system_admin', () => { @@ -150,9 +153,12 @@ export default class UserItem extends React.Component { handleDemoteSubmit() { Client.updateRoles( + this.props.team.id, this.props.user.id, this.state.role, () => { + this.props.refreshProfiles(); + this.setState({ serverError: null, showDemoteModal: false, @@ -185,6 +191,7 @@ export default class UserItem extends React.Component { ); } + const teamMember = this.props.teamMember; const user = this.props.user; let currentRoles = ( <FormattedMessage @@ -192,32 +199,28 @@ export default class UserItem extends React.Component { defaultMessage='Member' /> ); - if (user.roles.length > 0) { - if (Utils.isSystemAdmin(user.roles)) { - currentRoles = ( - <FormattedMessage - id='admin.user_item.sysAdmin' - defaultMessage='System Admin' - /> - ); - } else if (Utils.isAdmin(user.roles)) { - currentRoles = ( - <FormattedMessage - id='admin.user_item.teamAdmin' - defaultMessage='Team Admin' - /> - ); - } else { - currentRoles = user.roles.charAt(0).toUpperCase() + user.roles.slice(1); - } - } - const email = user.email; - let showMakeMember = user.roles === 'admin' || user.roles === 'system_admin'; + if (teamMember.roles.length > 0 && Utils.isAdmin(teamMember.roles)) { + currentRoles = ( + <FormattedMessage + id='team_members_dropdown.teamAdmin' + defaultMessage='Team Admin' + /> + ); + } - //let showMakeAdmin = user.roles === '' || user.roles === 'system_admin'; - let showMakeAdmin = false; + if (user.roles.length > 0 && Utils.isSystemAdmin(user.roles)) { + currentRoles = ( + <FormattedMessage + id='team_members_dropdown.systemAdmin' + defaultMessage='System Admin' + /> + ); + } + const email = user.email; + let showMakeMember = teamMember.roles === 'admin' || user.roles === 'system_admin'; + let showMakeAdmin = teamMember.roles === '' && user.roles !== 'system_admin'; let showMakeSystemAdmin = user.roles === '' || user.roles === 'admin'; let showMakeActive = false; let showMakeNotActive = user.roles !== 'system_admin'; @@ -521,7 +524,9 @@ export default class UserItem extends React.Component { } UserItem.propTypes = { + team: React.PropTypes.object.isRequired, user: React.PropTypes.object.isRequired, + teamMember: React.PropTypes.object.isRequired, refreshProfiles: React.PropTypes.func.isRequired, doPasswordReset: React.PropTypes.func.isRequired }; diff --git a/webapp/components/audit_table.jsx b/webapp/components/audit_table.jsx index b1f155518..58b5b9af7 100644 --- a/webapp/components/audit_table.jsx +++ b/webapp/components/audit_table.jsx @@ -494,7 +494,7 @@ export function formatAuditInfo(audit, formatMessage) { if (actingUserInfo[0] === 'session_user') { const actingUser = UserStore.getProfile(actingUserInfo[1]); const user = UserStore.getCurrentUser(); - if (user && actingUser && (Utils.isAdmin(user.roles) || Utils.isSystemAdmin(user.roles))) { + if (user && actingUser && (Utils.isSystemAdmin(user.roles))) { auditDesc += formatMessage(holders.by, {username: actingUser.username}); } else if (user && actingUser) { auditDesc += formatMessage(holders.byAdmin); diff --git a/webapp/components/channel_header.jsx b/webapp/components/channel_header.jsx index de6ee20c9..992244915 100644 --- a/webapp/components/channel_header.jsx +++ b/webapp/components/channel_header.jsx @@ -18,6 +18,7 @@ import ToggleModalButton from './toggle_modal_button.jsx'; import ChannelStore from 'stores/channel_store.jsx'; import UserStore from 'stores/user_store.jsx'; +import TeamStore from 'stores/team_store.jsx'; import SearchStore from 'stores/search_store.jsx'; import PreferenceStore from 'stores/preference_store.jsx'; @@ -181,7 +182,7 @@ export default class ChannelHeader extends React.Component { ); let channelTitle = channel.display_name; const currentId = this.state.currentUser.id; - const isAdmin = Utils.isAdmin(this.state.memberChannel.roles) || Utils.isAdmin(this.state.currentUser.roles); + const isAdmin = Utils.isAdmin(this.state.memberChannel.roles) || TeamStore.isTeamAdminForCurrentTeam() || UserStore.isSystemAdminForCurrentUser(); const isDirect = (this.state.channel.type === 'D'); if (isDirect) { diff --git a/webapp/components/navbar.jsx b/webapp/components/navbar.jsx index 919a72d0a..21ca53649 100644 --- a/webapp/components/navbar.jsx +++ b/webapp/components/navbar.jsx @@ -452,7 +452,8 @@ export default class Navbar extends React.Component { /> </Popover> ); - isAdmin = Utils.isAdmin(this.state.member.roles); + + isAdmin = Utils.isAdmin(this.state.member.roles) || TeamStore.isTeamAdminForCurrentTeam() || UserStore.isSystemAdminForCurrentUser(); if (channel.type === 'O') { channelTitle = channel.display_name; diff --git a/webapp/components/navbar_dropdown.jsx b/webapp/components/navbar_dropdown.jsx index 7004a0cf3..7f1cfce7c 100644 --- a/webapp/components/navbar_dropdown.jsx +++ b/webapp/components/navbar_dropdown.jsx @@ -7,6 +7,7 @@ import * as Utils from 'utils/utils.jsx'; import * as GlobalActions from 'action_creators/global_actions.jsx'; import TeamStore from 'stores/team_store.jsx'; +import UserStore from 'stores/user_store.jsx'; import AboutBuildModal from './about_build_modal.jsx'; import TeamMembersModal from './team_members_modal.jsx'; import ToggleModalButton from './toggle_modal_button.jsx'; @@ -79,8 +80,8 @@ export default class NavbarDropdown extends React.Component { let integrationsLink = null; if (currentUser != null) { - isAdmin = Utils.isAdmin(currentUser.roles); - isSystemAdmin = Utils.isSystemAdmin(currentUser.roles); + isAdmin = TeamStore.isTeamAdminForCurrentTeam() || UserStore.isSystemAdminForCurrentUser(); + isSystemAdmin = UserStore.isSystemAdminForCurrentUser(); inviteLink = ( <li> diff --git a/webapp/components/post_info.jsx b/webapp/components/post_info.jsx index 3f81672e1..50b03c0be 100644 --- a/webapp/components/post_info.jsx +++ b/webapp/components/post_info.jsx @@ -5,6 +5,8 @@ import $ from 'jquery'; import * as Utils from 'utils/utils.jsx'; import TimeSince from './time_since.jsx'; import * as GlobalActions from 'action_creators/global_actions.jsx'; +import TeamStore from 'stores/team_store.jsx'; +import UserStore from 'stores/user_store.jsx'; import Constants from 'utils/constants.jsx'; @@ -30,7 +32,7 @@ export default class PostInfo extends React.Component { createDropdown() { var post = this.props.post; var isOwner = this.props.currentUser.id === post.user_id; - var isAdmin = Utils.isAdmin(this.props.currentUser.roles); + var isAdmin = TeamStore.isTeamAdminForCurrentTeam() || UserStore.isSystemAdminForCurrentUser(); if (post.state === Constants.POST_FAILED || post.state === Constants.POST_LOADING || Utils.isPostEphemeral(post)) { return ''; diff --git a/webapp/components/rhs_comment.jsx b/webapp/components/rhs_comment.jsx index f21ae24e7..5097e0573 100644 --- a/webapp/components/rhs_comment.jsx +++ b/webapp/components/rhs_comment.jsx @@ -6,6 +6,8 @@ import FileAttachmentList from './file_attachment_list.jsx'; import PostStore from 'stores/post_store.jsx'; import ChannelStore from 'stores/channel_store.jsx'; +import TeamStore from 'stores/team_store.jsx'; +import UserStore from 'stores/user_store.jsx'; import * as GlobalActions from 'action_creators/global_actions.jsx'; import AppDispatcher from '../dispatcher/app_dispatcher.jsx'; @@ -82,7 +84,7 @@ export default class RhsComment extends React.Component { } const isOwner = this.props.currentUser.id === post.user_id; - const isAdmin = Utils.isAdmin(this.props.currentUser.roles); + var isAdmin = TeamStore.isTeamAdminForCurrentTeam() || UserStore.isSystemAdminForCurrentUser(); var dropdownContents = []; diff --git a/webapp/components/rhs_root_post.jsx b/webapp/components/rhs_root_post.jsx index c771674a6..a9f6612dc 100644 --- a/webapp/components/rhs_root_post.jsx +++ b/webapp/components/rhs_root_post.jsx @@ -4,6 +4,7 @@ import ChannelStore from 'stores/channel_store.jsx'; import UserProfile from './user_profile.jsx'; import UserStore from 'stores/user_store.jsx'; +import TeamStore from 'stores/user_store.jsx'; import * as TextFormatting from 'utils/text_formatting.jsx'; import * as Utils from 'utils/utils.jsx'; import FileAttachmentList from './file_attachment_list.jsx'; @@ -39,7 +40,7 @@ export default class RhsRootPost extends React.Component { const post = this.props.post; const user = this.props.user; var isOwner = this.props.currentUser.id === post.user_id; - var isAdmin = Utils.isAdmin(this.props.currentUser.roles); + var isAdmin = TeamStore.isTeamAdminForCurrentTeam() || UserStore.isSystemAdminForCurrentUser(); var timestamp = UserStore.getProfile(post.user_id).update_at; var channel = ChannelStore.get(post.channel_id); diff --git a/webapp/components/sidebar_right_menu.jsx b/webapp/components/sidebar_right_menu.jsx index a48dcade6..b36d84b79 100644 --- a/webapp/components/sidebar_right_menu.jsx +++ b/webapp/components/sidebar_right_menu.jsx @@ -7,6 +7,7 @@ import UserSettingsModal from './user_settings/user_settings_modal.jsx'; import AboutBuildModal from './about_build_modal.jsx'; import UserStore from 'stores/user_store.jsx'; +import TeamStore from 'stores/team_store.jsx'; import PreferenceStore from 'stores/preference_store.jsx'; import * as GlobalActions from 'action_creators/global_actions.jsx'; @@ -77,8 +78,8 @@ export default class SidebarRightMenu extends React.Component { var isSystemAdmin = false; if (currentUser != null) { - isAdmin = Utils.isAdmin(currentUser.roles); - isSystemAdmin = Utils.isSystemAdmin(currentUser.roles); + isAdmin = TeamStore.isTeamAdminForCurrentTeam() || UserStore.isSystemAdminForCurrentUser(); + isSystemAdmin = UserStore.isSystemAdminForCurrentUser(); inviteLink = ( <li> diff --git a/webapp/components/team_members_dropdown.jsx b/webapp/components/team_members_dropdown.jsx index 251c2ce3b..b65b9e050 100644 --- a/webapp/components/team_members_dropdown.jsx +++ b/webapp/components/team_members_dropdown.jsx @@ -39,9 +39,11 @@ export default class TeamMembersDropdown extends React.Component { this.handleDemote(this.props.user, ''); } else { Client.updateRoles( + this.props.teamMember.team_id, this.props.user.id, '', () => { + AsyncClient.getTeamMembers(TeamStore.getCurrentId()); AsyncClient.getProfiles(); }, (err) => { @@ -53,6 +55,7 @@ export default class TeamMembersDropdown extends React.Component { handleMakeActive() { Client.updateActive(this.props.user.id, true, () => { + AsyncClient.getTeamMembers(TeamStore.getCurrentId()); AsyncClient.getProfiles(); AsyncClient.getChannelExtraInfo(ChannelStore.getCurrentId()); }, @@ -64,6 +67,7 @@ export default class TeamMembersDropdown extends React.Component { handleMakeNotActive() { Client.updateActive(this.props.user.id, false, () => { + AsyncClient.getTeamMembers(TeamStore.getCurrentId()); AsyncClient.getProfiles(); AsyncClient.getChannelExtraInfo(ChannelStore.getCurrentId()); }, @@ -78,9 +82,11 @@ export default class TeamMembersDropdown extends React.Component { this.handleDemote(this.props.user, 'admin'); } else { Client.updateRoles( + this.props.teamMember.team_id, this.props.user.id, 'admin', () => { + AsyncClient.getTeamMembers(TeamStore.getCurrentId()); AsyncClient.getProfiles(); }, (err) => { @@ -109,9 +115,13 @@ export default class TeamMembersDropdown extends React.Component { } handleDemoteSubmit() { Client.updateRoles( + this.props.teamMember.team_id, this.props.user.id, this.state.newRole, () => { + AsyncClient.getTeamMembers(TeamStore.getCurrentId()); + AsyncClient.getProfiles(); + const teamUrl = TeamStore.getCurrentTeamUrl(); if (teamUrl) { browserHistory.push(teamUrl); @@ -143,30 +153,26 @@ export default class TeamMembersDropdown extends React.Component { /> ); - if (user.roles.length > 0) { - if (Utils.isSystemAdmin(user.roles)) { - currentRoles = ( - <FormattedMessage - id='team_members_dropdown.systemAdmin' - defaultMessage='System Admin' - /> - ); - } else if (Utils.isAdmin(user.roles)) { - currentRoles = ( - <FormattedMessage - id='team_members_dropdown.teamAdmin' - defaultMessage='Team Admin' - /> - ); - } else { - currentRoles = user.roles.charAt(0).toUpperCase() + user.roles.slice(1); - } + if (teamMember.roles.length > 0 && Utils.isAdmin(teamMember.roles)) { + currentRoles = ( + <FormattedMessage + id='team_members_dropdown.teamAdmin' + defaultMessage='Team Admin' + /> + ); } - let showMakeMember = teamMember.roles === 'admin' || user.roles === 'system_admin'; + if (user.roles.length > 0 && Utils.isSystemAdmin(user.roles)) { + currentRoles = ( + <FormattedMessage + id='team_members_dropdown.systemAdmin' + defaultMessage='System Admin' + /> + ); + } - //let showMakeAdmin = teamMember.roles === '' && user.roles !== 'system_admin'; - let showMakeAdmin = false; + let showMakeMember = teamMember.roles === 'admin' || user.roles === 'system_admin'; + let showMakeAdmin = teamMember.roles === '' && user.roles !== 'system_admin'; let showMakeActive = false; let showMakeNotActive = user.roles !== 'system_admin'; @@ -221,38 +227,38 @@ export default class TeamMembersDropdown extends React.Component { let makeActive = null; if (showMakeActive) { - makeActive = ( - <li role='presentation'> - <a - role='menuitem' - href='#' - onClick={this.handleMakeActive} - > - <FormattedMessage - id='team_members_dropdown.makeActive' - defaultMessage='Make Active' - /> - </a> - </li> - ); + // makeActive = ( + // <li role='presentation'> + // <a + // role='menuitem' + // href='#' + // onClick={this.handleMakeActive} + // > + // <FormattedMessage + // id='team_members_dropdown.makeActive' + // defaultMessage='Make Active' + // /> + // </a> + // </li> + // ); } let makeNotActive = null; if (showMakeNotActive) { - makeNotActive = ( - <li role='presentation'> - <a - role='menuitem' - href='#' - onClick={this.handleMakeNotActive} - > - <FormattedMessage - id='team_members_dropdown.makeInactive' - defaultMessage='Make Inactive' - /> - </a> - </li> - ); + // makeNotActive = ( + // <li role='presentation'> + // <a + // role='menuitem' + // href='#' + // onClick={this.handleMakeNotActive} + // > + // <FormattedMessage + // id='team_members_dropdown.makeInactive' + // defaultMessage='Make Inactive' + // /> + // </a> + // </li> + // ); } const me = UserStore.getCurrentUser(); let makeDemoteModal = null; diff --git a/webapp/stores/team_store.jsx b/webapp/stores/team_store.jsx index 29e832633..8eebbaca5 100644 --- a/webapp/stores/team_store.jsx +++ b/webapp/stores/team_store.jsx @@ -3,6 +3,7 @@ import AppDispatcher from '../dispatcher/app_dispatcher.jsx'; import EventEmitter from 'events'; +import UserStore from 'stores/user_store.jsx'; import Constants from 'utils/constants.jsx'; const ActionTypes = Constants.ActionTypes; @@ -148,6 +149,22 @@ class TeamStoreClass extends EventEmitter { getTeamListings() { return this.teamListings; } + + isTeamAdminForCurrentTeam() { + if (!Utils) { + Utils = require('utils/utils.jsx'); //eslint-disable-line global-require + } + + const userId = UserStore.getCurrentId(); + var teamMembers = this.getTeamMembers(); + const teamMember = teamMembers.find((m) => m.user_id === userId && m.team_id === this.getCurrentId()); + + if (teamMember) { + return Utils.isAdmin(teamMember.roles); + } + + return false; + } } var TeamStore = new TeamStoreClass(); diff --git a/webapp/stores/user_store.jsx b/webapp/stores/user_store.jsx index 8ae1e1404..855222d47 100644 --- a/webapp/stores/user_store.jsx +++ b/webapp/stores/user_store.jsx @@ -13,6 +13,8 @@ const CHANGE_EVENT_SESSIONS = 'change_sessions'; const CHANGE_EVENT_AUDITS = 'change_audits'; const CHANGE_EVENT_STATUSES = 'change_statuses'; +var Utils; + class UserStoreClass extends EventEmitter { constructor() { super(); @@ -314,6 +316,20 @@ class UserStoreClass extends EventEmitter { setNoAccounts(noAccounts) { this.noAccounts = noAccounts; } + + isSystemAdminForCurrentUser() { + if (!Utils) { + Utils = require('utils/utils.jsx'); //eslint-disable-line global-require + } + + var current = this.getCurrentUser(); + + if (current) { + return Utils.isAdmin(current.roles); + } + + return false; + } } var UserStore = new UserStoreClass(); diff --git a/webapp/tests/client_user.test.jsx b/webapp/tests/client_user.test.jsx index 610308fa3..2b3b1b89a 100644 --- a/webapp/tests/client_user.test.jsx +++ b/webapp/tests/client_user.test.jsx @@ -206,12 +206,14 @@ describe('Client.User', function() { it('updateRoles', function(done) { TestHelper.initBasic(() => { var user = TestHelper.basicUser(); + var team = TestHelper.basicTeam(); TestHelper.basicClient().updateRoles( + team.id, user.id, '', function(data) { - assert.equal(data.roles, ''); + assert.equal(data.user_id, user.id); done(); }, function(err) { |