Adding new "VIEW_MEMBERS" permissions restrict the scope of users visibility (#10487)
* MM-14138: Adding new "VIEW_MEMBERS" permissions restrict the scope of users visibility * Fixing gofmt * Fixing broken tests * Addressing PR review comments from Miguel de la Cruz * Removed hack * A bit nicer and cleaner code in the UserBelongsToChannels function * Adding cluster cache invalidation for user team ids * Checking in the correct order permissions to not leek existency information * Adding restrictions to TeamMembers and User status requests * Fixing tests * Fixing status endpoint permissions checks * Adding more tests * Fixing tests * More tests and making the restrictions query based only on joins * Adding more tests * Adding more tests * fixing merge problems * Reverting status changes to avoid performance issues * Adding more tests * Fixing test * i18n extract * Adding extra method for get restrictions for a team * Add the new elasticsearch functions to search users with restrictions * Add missing translation string * Rename restrictedChannelIds to restrictedToChannels * Remove ToDo * Adding the permission to the SystemAdmin role during permissions migrations
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
5b70962f71
Коммит
c8920588a0
@@ -150,6 +150,7 @@ func (a *App) InvalidateAllCachesSkipSend() {
|
||||
mlog.Info("Purging all caches")
|
||||
a.Srv.sessionCache.Purge()
|
||||
ClearStatusCache()
|
||||
a.Srv.Store.Team().ClearCaches()
|
||||
a.Srv.Store.Channel().ClearCaches()
|
||||
a.Srv.Store.User().ClearCaches()
|
||||
a.Srv.Store.Post().ClearCaches()
|
||||
|
||||
@@ -254,7 +254,7 @@ func (a *App) GetAnalytics(name string, teamId string) (model.AnalyticsRows, *mo
|
||||
}
|
||||
|
||||
func (a *App) GetRecentlyActiveUsersForTeam(teamId string) (map[string]*model.User, *model.AppError) {
|
||||
result := <-a.Srv.Store.User().GetRecentlyActiveUsersForTeam(teamId, 0, 100)
|
||||
result := <-a.Srv.Store.User().GetRecentlyActiveUsersForTeam(teamId, 0, 100, nil)
|
||||
if result.Err != nil {
|
||||
return nil, result.Err
|
||||
}
|
||||
@@ -269,9 +269,9 @@ func (a *App) GetRecentlyActiveUsersForTeam(teamId string) (map[string]*model.Us
|
||||
return userMap, nil
|
||||
}
|
||||
|
||||
func (a *App) GetRecentlyActiveUsersForTeamPage(teamId string, page, perPage int, asAdmin bool) ([]*model.User, *model.AppError) {
|
||||
func (a *App) GetRecentlyActiveUsersForTeamPage(teamId string, page, perPage int, asAdmin bool, viewRestrictions *model.ViewUsersRestrictions) ([]*model.User, *model.AppError) {
|
||||
var users []*model.User
|
||||
result := <-a.Srv.Store.User().GetRecentlyActiveUsersForTeam(teamId, page*perPage, perPage)
|
||||
result := <-a.Srv.Store.User().GetRecentlyActiveUsersForTeam(teamId, page*perPage, perPage, viewRestrictions)
|
||||
if result.Err != nil {
|
||||
return nil, result.Err
|
||||
}
|
||||
@@ -280,9 +280,9 @@ func (a *App) GetRecentlyActiveUsersForTeamPage(teamId string, page, perPage int
|
||||
return a.sanitizeProfiles(users, asAdmin), nil
|
||||
}
|
||||
|
||||
func (a *App) GetNewUsersForTeamPage(teamId string, page, perPage int, asAdmin bool) ([]*model.User, *model.AppError) {
|
||||
func (a *App) GetNewUsersForTeamPage(teamId string, page, perPage int, asAdmin bool, viewRestrictions *model.ViewUsersRestrictions) ([]*model.User, *model.AppError) {
|
||||
var users []*model.User
|
||||
result := <-a.Srv.Store.User().GetNewUsersForTeam(teamId, page*perPage, perPage)
|
||||
result := <-a.Srv.Store.User().GetNewUsersForTeam(teamId, page*perPage, perPage, viewRestrictions)
|
||||
if result.Err != nil {
|
||||
return nil, result.Err
|
||||
}
|
||||
|
||||
@@ -125,6 +125,7 @@ func TestDoAdvancedPermissionsMigration(t *testing.T) {
|
||||
model.PERMISSION_JOIN_PUBLIC_TEAMS.Id,
|
||||
model.PERMISSION_CREATE_DIRECT_CHANNEL.Id,
|
||||
model.PERMISSION_CREATE_GROUP_CHANNEL.Id,
|
||||
model.PERMISSION_VIEW_MEMBERS.Id,
|
||||
model.PERMISSION_CREATE_TEAM.Id,
|
||||
},
|
||||
"system_post_all": []string{
|
||||
@@ -176,6 +177,7 @@ func TestDoAdvancedPermissionsMigration(t *testing.T) {
|
||||
model.PERMISSION_REMOVE_OTHERS_REACTIONS.Id,
|
||||
model.PERMISSION_LIST_PRIVATE_TEAMS.Id,
|
||||
model.PERMISSION_JOIN_PRIVATE_TEAMS.Id,
|
||||
model.PERMISSION_VIEW_MEMBERS.Id,
|
||||
model.PERMISSION_LIST_TEAM_CHANNELS.Id,
|
||||
model.PERMISSION_JOIN_PUBLIC_CHANNELS.Id,
|
||||
model.PERMISSION_READ_PUBLIC_CHANNEL.Id,
|
||||
@@ -305,6 +307,7 @@ func TestDoAdvancedPermissionsMigration(t *testing.T) {
|
||||
model.PERMISSION_JOIN_PUBLIC_TEAMS.Id,
|
||||
model.PERMISSION_CREATE_DIRECT_CHANNEL.Id,
|
||||
model.PERMISSION_CREATE_GROUP_CHANNEL.Id,
|
||||
model.PERMISSION_VIEW_MEMBERS.Id,
|
||||
model.PERMISSION_CREATE_TEAM.Id,
|
||||
},
|
||||
"system_post_all": []string{
|
||||
@@ -356,6 +359,7 @@ func TestDoAdvancedPermissionsMigration(t *testing.T) {
|
||||
model.PERMISSION_REMOVE_OTHERS_REACTIONS.Id,
|
||||
model.PERMISSION_LIST_PRIVATE_TEAMS.Id,
|
||||
model.PERMISSION_JOIN_PRIVATE_TEAMS.Id,
|
||||
model.PERMISSION_VIEW_MEMBERS.Id,
|
||||
model.PERMISSION_LIST_TEAM_CHANNELS.Id,
|
||||
model.PERMISSION_JOIN_PUBLIC_CHANNELS.Id,
|
||||
model.PERMISSION_READ_PUBLIC_CHANNEL.Id,
|
||||
@@ -523,6 +527,7 @@ func TestDoEmojisPermissionsMigration(t *testing.T) {
|
||||
model.PERMISSION_CREATE_EMOJIS.Id,
|
||||
model.PERMISSION_DELETE_EMOJIS.Id,
|
||||
model.PERMISSION_DELETE_OTHERS_EMOJIS.Id,
|
||||
model.PERMISSION_VIEW_MEMBERS.Id,
|
||||
}
|
||||
sort.Strings(expectedSystemAdmin)
|
||||
|
||||
@@ -583,6 +588,7 @@ func TestDoEmojisPermissionsMigration(t *testing.T) {
|
||||
model.PERMISSION_CREATE_TEAM.Id,
|
||||
model.PERMISSION_CREATE_EMOJIS.Id,
|
||||
model.PERMISSION_DELETE_EMOJIS.Id,
|
||||
model.PERMISSION_VIEW_MEMBERS.Id,
|
||||
}
|
||||
sort.Strings(expected3)
|
||||
sort.Strings(role3.Permissions)
|
||||
|
||||
@@ -420,7 +420,7 @@ func (a *App) createGroupChannel(userIds []string, creatorId string) (*model.Cha
|
||||
return nil, model.NewAppError("CreateGroupChannel", "api.channel.create_group.bad_size.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
result := <-a.Srv.Store.User().GetProfileByIds(userIds, true)
|
||||
result := <-a.Srv.Store.User().GetProfileByIds(userIds, true, nil)
|
||||
if result.Err != nil {
|
||||
return nil, result.Err
|
||||
}
|
||||
@@ -469,7 +469,7 @@ func (a *App) GetGroupChannel(userIds []string) (*model.Channel, *model.AppError
|
||||
return nil, model.NewAppError("GetGroupChannel", "api.channel.create_group.bad_size.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
result := <-a.Srv.Store.User().GetProfileByIds(userIds, true)
|
||||
result := <-a.Srv.Store.User().GetProfileByIds(userIds, true, nil)
|
||||
if result.Err != nil {
|
||||
return nil, result.Err
|
||||
}
|
||||
@@ -1907,7 +1907,7 @@ func (a *App) MoveChannel(team *model.Team, channel *model.Channel, user *model.
|
||||
}
|
||||
|
||||
if len(channelMemberIds) > 0 {
|
||||
teamMembers, err2 := a.GetTeamMembersByIds(team.Id, channelMemberIds)
|
||||
teamMembers, err2 := a.GetTeamMembersByIds(team.Id, channelMemberIds, nil)
|
||||
if err2 != nil {
|
||||
return err2
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ func (a *App) RegisterAllClusterMessageHandlers() {
|
||||
a.Cluster.RegisterClusterMessageHandler(model.CLUSTER_EVENT_INVALIDATE_CACHE_FOR_CHANNEL_BY_NAME, a.ClusterInvalidateCacheForChannelByNameHandler)
|
||||
a.Cluster.RegisterClusterMessageHandler(model.CLUSTER_EVENT_INVALIDATE_CACHE_FOR_CHANNEL, a.ClusterInvalidateCacheForChannelHandler)
|
||||
a.Cluster.RegisterClusterMessageHandler(model.CLUSTER_EVENT_INVALIDATE_CACHE_FOR_USER, a.ClusterInvalidateCacheForUserHandler)
|
||||
a.Cluster.RegisterClusterMessageHandler(model.CLUSTER_EVENT_INVALIDATE_CACHE_FOR_USER_TEAMS, a.ClusterInvalidateCacheForUserTeamsHandler)
|
||||
a.Cluster.RegisterClusterMessageHandler(model.CLUSTER_EVENT_CLEAR_SESSION_CACHE_FOR_USER, a.ClusterClearSessionCacheForUserHandler)
|
||||
}
|
||||
|
||||
@@ -65,6 +66,10 @@ func (a *App) ClusterInvalidateCacheForUserHandler(msg *model.ClusterMessage) {
|
||||
a.InvalidateCacheForUserSkipClusterSend(msg.Data)
|
||||
}
|
||||
|
||||
func (a *App) ClusterInvalidateCacheForUserTeamsHandler(msg *model.ClusterMessage) {
|
||||
a.InvalidateCacheForUserTeamsSkipClusterSend(msg.Data)
|
||||
}
|
||||
|
||||
func (a *App) ClusterClearSessionCacheForUserHandler(msg *model.ClusterMessage) {
|
||||
a.ClearSessionCacheForUserSkipClusterSend(msg.Data)
|
||||
}
|
||||
|
||||
@@ -802,7 +802,7 @@ func TestImportImportUser(t *testing.T) {
|
||||
Position: ptrStr(model.NewId()),
|
||||
}
|
||||
|
||||
teamMembers, err := th.App.GetTeamMembers(team.Id, 0, 1000)
|
||||
teamMembers, err := th.App.GetTeamMembers(team.Id, 0, 1000, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to get team member count")
|
||||
}
|
||||
@@ -884,7 +884,7 @@ func TestImportImportUser(t *testing.T) {
|
||||
assert.Nil(t, err)
|
||||
|
||||
// Check no new member objects were created because dry run mode.
|
||||
tmc, err := th.App.GetTeamMembers(team.Id, 0, 1000)
|
||||
tmc, err := th.App.GetTeamMembers(team.Id, 0, 1000, nil)
|
||||
require.Nil(t, err, "Failed to get Team Member Count")
|
||||
require.Len(t, tmc, teamMemberCount, "Number of team members not as expected")
|
||||
|
||||
@@ -935,7 +935,7 @@ func TestImportImportUser(t *testing.T) {
|
||||
assert.NotNil(t, err)
|
||||
|
||||
// Check no new member objects were created because all tests should have failed so far.
|
||||
tmc, err = th.App.GetTeamMembers(team.Id, 0, 1000)
|
||||
tmc, err = th.App.GetTeamMembers(team.Id, 0, 1000, nil)
|
||||
require.Nil(t, err, "Failed to get Team Member Count")
|
||||
require.Len(t, tmc, teamMemberCount)
|
||||
|
||||
@@ -958,7 +958,7 @@ func TestImportImportUser(t *testing.T) {
|
||||
assert.NotNil(t, err)
|
||||
|
||||
// Check only new team member object created because dry run mode.
|
||||
tmc, err = th.App.GetTeamMembers(team.Id, 0, 1000)
|
||||
tmc, err = th.App.GetTeamMembers(team.Id, 0, 1000, nil)
|
||||
require.Nil(t, err, "Failed to get Team Member Count")
|
||||
require.Len(t, tmc, teamMemberCount+1)
|
||||
|
||||
@@ -991,7 +991,7 @@ func TestImportImportUser(t *testing.T) {
|
||||
assert.Nil(t, err)
|
||||
|
||||
// Check only new channel member object created because dry run mode.
|
||||
tmc, err = th.App.GetTeamMembers(team.Id, 0, 1000)
|
||||
tmc, err = th.App.GetTeamMembers(team.Id, 0, 1000, nil)
|
||||
require.Nil(t, err, "Failed to get Team Member Count")
|
||||
require.Len(t, tmc, teamMemberCount+1, "Number of team members not as expected")
|
||||
|
||||
@@ -1046,7 +1046,7 @@ func TestImportImportUser(t *testing.T) {
|
||||
checkPreference(t, th.App, user.Id, model.PREFERENCE_CATEGORY_THEME, team.Id, *(*data.Teams)[0].Theme)
|
||||
|
||||
// No more new member objects.
|
||||
tmc, err = th.App.GetTeamMembers(team.Id, 0, 1000)
|
||||
tmc, err = th.App.GetTeamMembers(team.Id, 0, 1000, nil)
|
||||
require.Nil(t, err, "Failed to get Team Member Count")
|
||||
require.Len(t, tmc, teamMemberCount+1, "Number of team members not as expected")
|
||||
|
||||
|
||||
@@ -125,7 +125,7 @@ func (a *App) SendNotifications(post *model.Post, team *model.Team, channel *mod
|
||||
}
|
||||
|
||||
if len(m.OtherPotentialMentions) > 0 && !post.IsSystemMessage() {
|
||||
if result := <-a.Srv.Store.User().GetProfilesByUsernames(m.OtherPotentialMentions, team.Id); result.Err == nil {
|
||||
if result := <-a.Srv.Store.User().GetProfilesByUsernames(m.OtherPotentialMentions, &model.ViewUsersRestrictions{Teams: []string{team.Id}}); result.Err == nil {
|
||||
channelMentions := model.UserSlice(result.Data.([]*model.User)).FilterByActive(true)
|
||||
|
||||
var outOfChannelMentions model.UserSlice
|
||||
|
||||
@@ -22,6 +22,7 @@ const (
|
||||
MIGRATION_KEY_ADD_BOT_PERMISSIONS = "add_bot_permissions"
|
||||
MIGRATION_KEY_APPLY_CHANNEL_MANAGE_DELETE_TO_CHANNEL_USER = "apply_channel_manage_delete_to_channel_user"
|
||||
MIGRATION_KEY_REMOVE_CHANNEL_MANAGE_DELETE_FROM_TEAM_USER = "remove_channel_manage_delete_from_team_user"
|
||||
MIGRATION_KEY_VIEW_MEMBERS_NEW_PERMISSION = "view_members_new_permission"
|
||||
|
||||
PERMISSION_MANAGE_SYSTEM = "manage_system"
|
||||
PERMISSION_MANAGE_EMOJIS = "manage_emojis"
|
||||
@@ -49,6 +50,7 @@ const (
|
||||
PERMISSION_DELETE_PRIVATE_CHANNEL = "delete_private_channel"
|
||||
PERMISSION_MANAGE_PUBLIC_CHANNEL_PROPERTIES = "manage_public_channel_properties"
|
||||
PERMISSION_MANAGE_PRIVATE_CHANNEL_PROPERTIES = "manage_private_channel_properties"
|
||||
PERMISSION_VIEW_MEMBERS = "view_members"
|
||||
)
|
||||
|
||||
func isRole(role string) func(string, map[string]map[string]bool) bool {
|
||||
@@ -258,6 +260,19 @@ func removeChannelManageDeleteFromTeamUser() permissionsMap {
|
||||
}
|
||||
}
|
||||
|
||||
func getViewMembersPermissionMigration() permissionsMap {
|
||||
return permissionsMap{
|
||||
permissionTransformation{
|
||||
On: isRole(model.SYSTEM_USER_ROLE_ID),
|
||||
Add: []string{PERMISSION_VIEW_MEMBERS},
|
||||
},
|
||||
permissionTransformation{
|
||||
On: isRole(model.SYSTEM_ADMIN_ROLE_ID),
|
||||
Add: []string{PERMISSION_VIEW_MEMBERS},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// DoPermissionsMigrations execute all the permissions migrations need by the current version.
|
||||
func (a *App) DoPermissionsMigrations() *model.AppError {
|
||||
PermissionsMigrations := []struct {
|
||||
@@ -271,6 +286,7 @@ func (a *App) DoPermissionsMigrations() *model.AppError {
|
||||
{Key: MIGRATION_KEY_ADD_BOT_PERMISSIONS, Migration: getAddBotPermissionsMigration},
|
||||
{Key: MIGRATION_KEY_APPLY_CHANNEL_MANAGE_DELETE_TO_CHANNEL_USER, Migration: applyChannelManageDeleteToChannelUser},
|
||||
{Key: MIGRATION_KEY_REMOVE_CHANNEL_MANAGE_DELETE_FROM_TEAM_USER, Migration: removeChannelManageDeleteFromTeamUser},
|
||||
{Key: MIGRATION_KEY_VIEW_MEMBERS_NEW_PERMISSION, Migration: getViewMembersPermissionMigration},
|
||||
}
|
||||
|
||||
for _, migration := range PermissionsMigrations {
|
||||
|
||||
@@ -173,7 +173,7 @@ func (api *PluginAPI) DeleteTeamMember(teamId, userId, requestorId string) *mode
|
||||
}
|
||||
|
||||
func (api *PluginAPI) GetTeamMembers(teamId string, page, perPage int) ([]*model.TeamMember, *model.AppError) {
|
||||
return api.app.GetTeamMembers(teamId, page*perPage, perPage)
|
||||
return api.app.GetTeamMembers(teamId, page*perPage, perPage, nil)
|
||||
}
|
||||
|
||||
func (api *PluginAPI) GetTeamMember(teamId, userId string) (*model.TeamMember, *model.AppError) {
|
||||
@@ -222,7 +222,7 @@ func (api *PluginAPI) GetUserByUsername(name string) (*model.User, *model.AppErr
|
||||
}
|
||||
|
||||
func (api *PluginAPI) GetUsersByUsernames(usernames []string) ([]*model.User, *model.AppError) {
|
||||
return api.app.GetUsersByUsernames(usernames, true)
|
||||
return api.app.GetUsersByUsernames(usernames, true, nil)
|
||||
}
|
||||
|
||||
func (api *PluginAPI) GetUsersInTeam(teamId string, page int, perPage int) ([]*model.User, *model.AppError) {
|
||||
|
||||
@@ -780,7 +780,7 @@ func (a *App) DeletePostFiles(post *model.Post) {
|
||||
func (a *App) parseAndFetchChannelIdByNameFromInFilter(channelName, userId, teamId string, includeDeleted bool) (*model.Channel, error) {
|
||||
if strings.HasPrefix(channelName, "@") && strings.Contains(channelName, ",") {
|
||||
var userIds []string
|
||||
users, err := a.GetUsersByUsernames(strings.Split(channelName[1:], ","), false)
|
||||
users, err := a.GetUsersByUsernames(strings.Split(channelName[1:], ","), false, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -66,7 +66,7 @@ func replaceUserIds(userStore store.UserStore, text string) string {
|
||||
userIds = append(userIds, match[1])
|
||||
}
|
||||
|
||||
if res := <-userStore.GetProfileByIds(userIds, true); res.Err == nil {
|
||||
if res := <-userStore.GetProfileByIds(userIds, true, nil); res.Err == nil {
|
||||
for _, user := range res.Data.([]*model.User) {
|
||||
text = strings.Replace(text, "<@"+user.Id+">", "@"+user.Username, -1)
|
||||
}
|
||||
|
||||
@@ -114,7 +114,7 @@ func TestCreateDefaultMemberships(t *testing.T) {
|
||||
t.Errorf("error retrieving channel member: %s", err.Error())
|
||||
}
|
||||
|
||||
tMembers, err := th.App.GetTeamMembers(singersTeam.Id, 0, 999)
|
||||
tMembers, err := th.App.GetTeamMembers(singersTeam.Id, 0, 999, nil)
|
||||
if err != nil {
|
||||
t.Errorf("error retrieving team members: %s", err.Error())
|
||||
}
|
||||
@@ -143,7 +143,7 @@ func TestCreateDefaultMemberships(t *testing.T) {
|
||||
t.Errorf("wrong error: %s", err.Id)
|
||||
}
|
||||
|
||||
tMembers, err = th.App.GetTeamMembers(nerdsTeam.Id, 0, 999)
|
||||
tMembers, err = th.App.GetTeamMembers(nerdsTeam.Id, 0, 999, nil)
|
||||
if err != nil {
|
||||
t.Errorf("error retrieving team members: %s", err.Error())
|
||||
}
|
||||
@@ -185,7 +185,7 @@ func TestCreateDefaultMemberships(t *testing.T) {
|
||||
t.Errorf("wrong error: %s", err.Id)
|
||||
}
|
||||
|
||||
tMembers, err = th.App.GetTeamMembers(nerdsTeam.Id, 0, 999)
|
||||
tMembers, err = th.App.GetTeamMembers(nerdsTeam.Id, 0, 999, nil)
|
||||
if err != nil {
|
||||
t.Errorf("error retrieving team members: %s", err.Error())
|
||||
}
|
||||
@@ -366,7 +366,7 @@ func TestDeleteGroupMemberships(t *testing.T) {
|
||||
require.Nil(t, err)
|
||||
|
||||
// verify the member count
|
||||
tmembers, err := th.App.GetTeamMembers(th.BasicTeam.Id, 0, 100)
|
||||
tmembers, err := th.App.GetTeamMembers(th.BasicTeam.Id, 0, 100, nil)
|
||||
require.Nil(t, err)
|
||||
require.Len(t, tmembers, 3)
|
||||
|
||||
@@ -383,7 +383,7 @@ func TestDeleteGroupMemberships(t *testing.T) {
|
||||
require.Nil(t, appErr)
|
||||
|
||||
// verify the new member counts
|
||||
tmembers, err = th.App.GetTeamMembers(th.BasicTeam.Id, 0, 100)
|
||||
tmembers, err = th.App.GetTeamMembers(th.BasicTeam.Id, 0, 100, nil)
|
||||
require.Nil(t, err)
|
||||
require.Len(t, tmembers, 1)
|
||||
require.Equal(t, th.SystemAdminUser.Id, tmembers[0].UserId)
|
||||
|
||||
10
app/team.go
10
app/team.go
@@ -559,6 +559,7 @@ func (a *App) JoinUserToTeam(team *model.Team, user *model.User, userRequestorId
|
||||
|
||||
a.ClearSessionCacheForUser(user.Id)
|
||||
a.InvalidateCacheForUser(user.Id)
|
||||
a.InvalidateCacheForUserTeams(user.Id)
|
||||
|
||||
message := model.NewWebSocketEvent(model.WEBSOCKET_EVENT_ADDED_TO_TEAM, "", "", user.Id, nil)
|
||||
message.Add("team_id", team.Id)
|
||||
@@ -693,16 +694,16 @@ func (a *App) GetTeamMembersForUserWithPagination(userId string, page, perPage i
|
||||
return result.Data.([]*model.TeamMember), nil
|
||||
}
|
||||
|
||||
func (a *App) GetTeamMembers(teamId string, offset int, limit int) ([]*model.TeamMember, *model.AppError) {
|
||||
result := <-a.Srv.Store.Team().GetMembers(teamId, offset, limit)
|
||||
func (a *App) GetTeamMembers(teamId string, offset int, limit int, restrictions *model.ViewUsersRestrictions) ([]*model.TeamMember, *model.AppError) {
|
||||
result := <-a.Srv.Store.Team().GetMembers(teamId, offset, limit, restrictions)
|
||||
if result.Err != nil {
|
||||
return nil, result.Err
|
||||
}
|
||||
return result.Data.([]*model.TeamMember), nil
|
||||
}
|
||||
|
||||
func (a *App) GetTeamMembersByIds(teamId string, userIds []string) ([]*model.TeamMember, *model.AppError) {
|
||||
result := <-a.Srv.Store.Team().GetMembersByIds(teamId, userIds)
|
||||
func (a *App) GetTeamMembersByIds(teamId string, userIds []string, restrictions *model.ViewUsersRestrictions) ([]*model.TeamMember, *model.AppError) {
|
||||
result := <-a.Srv.Store.Team().GetMembersByIds(teamId, userIds, restrictions)
|
||||
if result.Err != nil {
|
||||
return nil, result.Err
|
||||
}
|
||||
@@ -932,6 +933,7 @@ func (a *App) LeaveTeam(team *model.Team, user *model.User, requestorId string)
|
||||
|
||||
a.ClearSessionCacheForUser(user.Id)
|
||||
a.InvalidateCacheForUser(user.Id)
|
||||
a.InvalidateCacheForUserTeams(user.Id)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -756,10 +756,10 @@ func TestGetTeamMembers(t *testing.T) {
|
||||
sort.Sort(userIDs)
|
||||
|
||||
// Fetch team members multipile times
|
||||
members, err := th.App.GetTeamMembers(th.BasicTeam.Id, 0, 5)
|
||||
members, err := th.App.GetTeamMembers(th.BasicTeam.Id, 0, 5, nil)
|
||||
require.Nil(t, err)
|
||||
// This should return 5 members
|
||||
members2, err := th.App.GetTeamMembers(th.BasicTeam.Id, 5, 6)
|
||||
members2, err := th.App.GetTeamMembers(th.BasicTeam.Id, 5, 6, nil)
|
||||
require.Nil(t, err)
|
||||
members = append(members, members2...)
|
||||
|
||||
@@ -776,7 +776,7 @@ func TestGetTeamStats(t *testing.T) {
|
||||
teamStats, err := th.App.GetTeamStats(th.BasicTeam.Id)
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, teamStats)
|
||||
members, err := th.App.GetTeamMembers(th.BasicTeam.Id, 0, 5)
|
||||
members, err := th.App.GetTeamMembers(th.BasicTeam.Id, 0, 5, nil)
|
||||
require.Nil(t, err)
|
||||
assert.Equal(t, int64(len(members)), teamStats.TotalMemberCount)
|
||||
}
|
||||
|
||||
255
app/user.go
255
app/user.go
@@ -447,8 +447,8 @@ func (a *App) GetUsersPage(options *model.UserGetOptions, asAdmin bool) ([]*mode
|
||||
return a.sanitizeProfiles(users, asAdmin), nil
|
||||
}
|
||||
|
||||
func (a *App) GetUsersEtag() string {
|
||||
return fmt.Sprintf("%v.%v.%v", (<-a.Srv.Store.User().GetEtagForAllProfiles()).Data.(string), a.Config().PrivacySettings.ShowFullName, a.Config().PrivacySettings.ShowEmailAddress)
|
||||
func (a *App) GetUsersEtag(restrictionsHash string) string {
|
||||
return fmt.Sprintf("%v.%v.%v.%v", (<-a.Srv.Store.User().GetEtagForAllProfiles()).Data.(string), a.Config().PrivacySettings.ShowFullName, a.Config().PrivacySettings.ShowEmailAddress, restrictionsHash)
|
||||
}
|
||||
|
||||
func (a *App) GetUsersInTeam(options *model.UserGetOptions) ([]*model.User, *model.AppError) {
|
||||
@@ -459,8 +459,8 @@ func (a *App) GetUsersInTeam(options *model.UserGetOptions) ([]*model.User, *mod
|
||||
return result.Data.([]*model.User), nil
|
||||
}
|
||||
|
||||
func (a *App) GetUsersNotInTeam(teamId string, offset int, limit int) ([]*model.User, *model.AppError) {
|
||||
result := <-a.Srv.Store.User().GetProfilesNotInTeam(teamId, offset, limit)
|
||||
func (a *App) GetUsersNotInTeam(teamId string, offset int, limit int, viewRestrictions *model.ViewUsersRestrictions) ([]*model.User, *model.AppError) {
|
||||
result := <-a.Srv.Store.User().GetProfilesNotInTeam(teamId, offset, limit, viewRestrictions)
|
||||
if result.Err != nil {
|
||||
return nil, result.Err
|
||||
}
|
||||
@@ -476,8 +476,8 @@ func (a *App) GetUsersInTeamPage(options *model.UserGetOptions, asAdmin bool) ([
|
||||
return a.sanitizeProfiles(users, asAdmin), nil
|
||||
}
|
||||
|
||||
func (a *App) GetUsersNotInTeamPage(teamId string, page int, perPage int, asAdmin bool) ([]*model.User, *model.AppError) {
|
||||
users, err := a.GetUsersNotInTeam(teamId, page*perPage, perPage)
|
||||
func (a *App) GetUsersNotInTeamPage(teamId string, page int, perPage int, asAdmin bool, viewRestrictions *model.ViewUsersRestrictions) ([]*model.User, *model.AppError) {
|
||||
users, err := a.GetUsersNotInTeam(teamId, page*perPage, perPage, viewRestrictions)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -485,12 +485,12 @@ func (a *App) GetUsersNotInTeamPage(teamId string, page int, perPage int, asAdmi
|
||||
return a.sanitizeProfiles(users, asAdmin), nil
|
||||
}
|
||||
|
||||
func (a *App) GetUsersInTeamEtag(teamId string) string {
|
||||
return fmt.Sprintf("%v.%v.%v", (<-a.Srv.Store.User().GetEtagForProfiles(teamId)).Data.(string), a.Config().PrivacySettings.ShowFullName, a.Config().PrivacySettings.ShowEmailAddress)
|
||||
func (a *App) GetUsersInTeamEtag(teamId string, restrictionsHash string) string {
|
||||
return fmt.Sprintf("%v.%v.%v.%v", (<-a.Srv.Store.User().GetEtagForProfiles(teamId)).Data.(string), a.Config().PrivacySettings.ShowFullName, a.Config().PrivacySettings.ShowEmailAddress, restrictionsHash)
|
||||
}
|
||||
|
||||
func (a *App) GetUsersNotInTeamEtag(teamId string) string {
|
||||
return fmt.Sprintf("%v.%v.%v", (<-a.Srv.Store.User().GetEtagForProfilesNotInTeam(teamId)).Data.(string), a.Config().PrivacySettings.ShowFullName, a.Config().PrivacySettings.ShowEmailAddress)
|
||||
func (a *App) GetUsersNotInTeamEtag(teamId string, restrictionsHash string) string {
|
||||
return fmt.Sprintf("%v.%v.%v.%v", (<-a.Srv.Store.User().GetEtagForProfilesNotInTeam(teamId)).Data.(string), a.Config().PrivacySettings.ShowFullName, a.Config().PrivacySettings.ShowEmailAddress, restrictionsHash)
|
||||
}
|
||||
|
||||
func (a *App) GetUsersInChannel(channelId string, offset int, limit int) ([]*model.User, *model.AppError) {
|
||||
@@ -541,16 +541,16 @@ func (a *App) GetUsersInChannelPageByStatus(channelId string, page int, perPage
|
||||
return a.sanitizeProfiles(users, asAdmin), nil
|
||||
}
|
||||
|
||||
func (a *App) GetUsersNotInChannel(teamId string, channelId string, offset int, limit int) ([]*model.User, *model.AppError) {
|
||||
result := <-a.Srv.Store.User().GetProfilesNotInChannel(teamId, channelId, offset, limit)
|
||||
func (a *App) GetUsersNotInChannel(teamId string, channelId string, offset int, limit int, viewRestrictions *model.ViewUsersRestrictions) ([]*model.User, *model.AppError) {
|
||||
result := <-a.Srv.Store.User().GetProfilesNotInChannel(teamId, channelId, offset, limit, viewRestrictions)
|
||||
if result.Err != nil {
|
||||
return nil, result.Err
|
||||
}
|
||||
return result.Data.([]*model.User), nil
|
||||
}
|
||||
|
||||
func (a *App) GetUsersNotInChannelMap(teamId string, channelId string, offset int, limit int, asAdmin bool) (map[string]*model.User, *model.AppError) {
|
||||
users, err := a.GetUsersNotInChannel(teamId, channelId, offset, limit)
|
||||
func (a *App) GetUsersNotInChannelMap(teamId string, channelId string, offset int, limit int, asAdmin bool, viewRestrictions *model.ViewUsersRestrictions) (map[string]*model.User, *model.AppError) {
|
||||
users, err := a.GetUsersNotInChannel(teamId, channelId, offset, limit, viewRestrictions)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -565,8 +565,8 @@ func (a *App) GetUsersNotInChannelMap(teamId string, channelId string, offset in
|
||||
return userMap, nil
|
||||
}
|
||||
|
||||
func (a *App) GetUsersNotInChannelPage(teamId string, channelId string, page int, perPage int, asAdmin bool) ([]*model.User, *model.AppError) {
|
||||
users, err := a.GetUsersNotInChannel(teamId, channelId, page*perPage, perPage)
|
||||
func (a *App) GetUsersNotInChannelPage(teamId string, channelId string, page int, perPage int, asAdmin bool, viewRestrictions *model.ViewUsersRestrictions) ([]*model.User, *model.AppError) {
|
||||
users, err := a.GetUsersNotInChannel(teamId, channelId, page*perPage, perPage, viewRestrictions)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -574,8 +574,8 @@ func (a *App) GetUsersNotInChannelPage(teamId string, channelId string, page int
|
||||
return a.sanitizeProfiles(users, asAdmin), nil
|
||||
}
|
||||
|
||||
func (a *App) GetUsersWithoutTeamPage(page int, perPage int, asAdmin bool) ([]*model.User, *model.AppError) {
|
||||
users, err := a.GetUsersWithoutTeam(page*perPage, perPage)
|
||||
func (a *App) GetUsersWithoutTeamPage(page int, perPage int, asAdmin bool, viewRestrictions *model.ViewUsersRestrictions) ([]*model.User, *model.AppError) {
|
||||
users, err := a.GetUsersWithoutTeam(page*perPage, perPage, viewRestrictions)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -583,8 +583,8 @@ func (a *App) GetUsersWithoutTeamPage(page int, perPage int, asAdmin bool) ([]*m
|
||||
return a.sanitizeProfiles(users, asAdmin), nil
|
||||
}
|
||||
|
||||
func (a *App) GetUsersWithoutTeam(offset int, limit int) ([]*model.User, *model.AppError) {
|
||||
result := <-a.Srv.Store.User().GetProfilesWithoutTeam(offset, limit)
|
||||
func (a *App) GetUsersWithoutTeam(offset int, limit int, viewRestrictions *model.ViewUsersRestrictions) ([]*model.User, *model.AppError) {
|
||||
result := <-a.Srv.Store.User().GetProfilesWithoutTeam(offset, limit, viewRestrictions)
|
||||
if result.Err != nil {
|
||||
return nil, result.Err
|
||||
}
|
||||
@@ -609,16 +609,16 @@ func (a *App) GetChannelGroupUsers(channelID string) ([]*model.User, *model.AppE
|
||||
return result.Data.([]*model.User), nil
|
||||
}
|
||||
|
||||
func (a *App) GetUsersByIds(userIds []string, asAdmin bool) ([]*model.User, *model.AppError) {
|
||||
result := <-a.Srv.Store.User().GetProfileByIds(userIds, true)
|
||||
func (a *App) GetUsersByIds(userIds []string, asAdmin bool, viewRestrictions *model.ViewUsersRestrictions) ([]*model.User, *model.AppError) {
|
||||
result := <-a.Srv.Store.User().GetProfileByIds(userIds, viewRestrictions == nil, viewRestrictions)
|
||||
if result.Err != nil {
|
||||
return nil, result.Err
|
||||
}
|
||||
return a.sanitizeProfiles(result.Data.([]*model.User), asAdmin), nil
|
||||
}
|
||||
|
||||
func (a *App) GetUsersByUsernames(usernames []string, asAdmin bool) ([]*model.User, *model.AppError) {
|
||||
result := <-a.Srv.Store.User().GetProfilesByUsernames(usernames, "")
|
||||
func (a *App) GetUsersByUsernames(usernames []string, asAdmin bool, viewRestrictions *model.ViewUsersRestrictions) ([]*model.User, *model.AppError) {
|
||||
result := <-a.Srv.Store.User().GetProfilesByUsernames(usernames, viewRestrictions)
|
||||
if result.Err != nil {
|
||||
return nil, result.Err
|
||||
}
|
||||
@@ -1601,9 +1601,10 @@ func (a *App) GetVerifyEmailToken(token string) (*model.Token, *model.AppError)
|
||||
}
|
||||
|
||||
// GetTotalUsersStats is used for the DM list total
|
||||
func (a *App) GetTotalUsersStats() (*model.UsersStats, *model.AppError) {
|
||||
func (a *App) GetTotalUsersStats(viewRestrictions *model.ViewUsersRestrictions) (*model.UsersStats, *model.AppError) {
|
||||
result := <-a.Srv.Store.User().Count(model.UserCountOptions{
|
||||
IncludeBotAccounts: true,
|
||||
ViewRestrictions: viewRestrictions,
|
||||
})
|
||||
if result.Err != nil {
|
||||
return nil, result.Err
|
||||
@@ -1682,12 +1683,20 @@ func (a *App) SearchUsersInTeam(teamId string, term string, options *model.UserS
|
||||
esInterface := a.Elasticsearch
|
||||
license := a.License()
|
||||
if esInterface != nil && *a.Config().ElasticsearchSettings.EnableAutocomplete && license != nil && *license.Features.Elasticsearch {
|
||||
usersIds, err := a.Elasticsearch.SearchUsersInTeam(teamId, term, options)
|
||||
listOfAllowedChannels, err := a.GetViewUsersRestrictionsForTeam(a.Session.UserId, teamId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(listOfAllowedChannels) == 0 {
|
||||
return []*model.User{}, nil
|
||||
}
|
||||
|
||||
usersIds, err := a.Elasticsearch.SearchUsersInTeam(teamId, listOfAllowedChannels, term, options)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result = <-a.Srv.Store.User().GetProfileByIds(usersIds, false)
|
||||
result = <-a.Srv.Store.User().GetProfileByIds(usersIds, false, nil)
|
||||
} else {
|
||||
result = <-a.Srv.Store.User().Search(teamId, term, options)
|
||||
}
|
||||
@@ -1738,12 +1747,25 @@ func (a *App) AutocompleteUsersInChannel(teamId string, channelId string, term s
|
||||
esInterface := a.Elasticsearch
|
||||
license := a.License()
|
||||
if esInterface != nil && *a.Config().ElasticsearchSettings.EnableAutocomplete && license != nil && *license.Features.Elasticsearch {
|
||||
uchanIds, nuchanIds, err := a.Elasticsearch.SearchUsersInChannel(teamId, channelId, term, options)
|
||||
listOfAllowedChannels, err := a.getListOfAllowedChannelsForTeam(teamId, options.ViewRestrictions)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
uchan = a.Srv.Store.User().GetProfileByIds(uchanIds, false)
|
||||
nuchan = a.Srv.Store.User().GetProfileByIds(nuchanIds, false)
|
||||
if len(listOfAllowedChannels) == 0 {
|
||||
return &model.UserAutocompleteInChannel{}, nil
|
||||
}
|
||||
uchanIds := []string{}
|
||||
nuchanIds := []string{}
|
||||
if !strings.Contains(strings.Join(listOfAllowedChannels, "."), channelId) {
|
||||
nuchanIds, err = a.Elasticsearch.SearchUsersInTeam(teamId, listOfAllowedChannels, term, options)
|
||||
} else {
|
||||
uchanIds, nuchanIds, err = a.Elasticsearch.SearchUsersInChannel(teamId, channelId, listOfAllowedChannels, term, options)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
uchan = a.Srv.Store.User().GetProfileByIds(uchanIds, false, nil)
|
||||
nuchan = a.Srv.Store.User().GetProfileByIds(nuchanIds, false, nil)
|
||||
} else {
|
||||
uchan = a.Srv.Store.User().SearchInChannel(channelId, term, options)
|
||||
nuchan = a.Srv.Store.User().SearchNotInChannel(teamId, channelId, term, options)
|
||||
@@ -1785,12 +1807,20 @@ func (a *App) AutocompleteUsersInTeam(teamId string, term string, options *model
|
||||
esInterface := a.Elasticsearch
|
||||
license := a.License()
|
||||
if esInterface != nil && *a.Config().ElasticsearchSettings.EnableAutocomplete && license != nil && *license.Features.Elasticsearch {
|
||||
usersIds, err := a.Elasticsearch.SearchUsersInTeam(teamId, term, options)
|
||||
listOfAllowedChannels, err := a.getListOfAllowedChannelsForTeam(teamId, options.ViewRestrictions)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(listOfAllowedChannels) == 0 {
|
||||
return &model.UserAutocompleteInTeam{}, nil
|
||||
}
|
||||
|
||||
usersIds, err := a.Elasticsearch.SearchUsersInTeam(teamId, listOfAllowedChannels, term, options)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result = <-a.Srv.Store.User().GetProfileByIds(usersIds, false)
|
||||
result = <-a.Srv.Store.User().GetProfileByIds(usersIds, false, nil)
|
||||
} else {
|
||||
result = <-a.Srv.Store.User().Search(teamId, term, options)
|
||||
}
|
||||
@@ -1865,6 +1895,16 @@ func (a *App) UpdateOAuthUserAttrs(userData io.Reader, user *model.User, provide
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *App) RestrictUsersGetByPermissions(userId string, options *model.UserGetOptions) (*model.UserGetOptions, *model.AppError) {
|
||||
restrictions, err := a.GetViewUsersRestrictions(userId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
options.ViewRestrictions = restrictions
|
||||
return options, nil
|
||||
}
|
||||
|
||||
// FilterNonGroupTeamMembers returns the subset of the given user IDs of the users who are not members of groups
|
||||
// associated to the team.
|
||||
func (a *App) FilterNonGroupTeamMembers(userIDs []string, team *model.Team) ([]string, error) {
|
||||
@@ -1930,3 +1970,154 @@ func (a *App) FilterNonGroupChannelMembers(userIDs []string, channel *model.Chan
|
||||
|
||||
return nonMemberIDs, nil
|
||||
}
|
||||
|
||||
func (a *App) RestrictUsersSearchByPermissions(userId string, options *model.UserSearchOptions) (*model.UserSearchOptions, *model.AppError) {
|
||||
restrictions, err := a.GetViewUsersRestrictions(userId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
options.ViewRestrictions = restrictions
|
||||
return options, nil
|
||||
}
|
||||
|
||||
func (a *App) UserCanSeeOtherUser(userId string, otherUserId string) (bool, *model.AppError) {
|
||||
if userId == otherUserId {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
restrictions, err := a.GetViewUsersRestrictions(userId)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if restrictions == nil {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
if len(restrictions.Teams) > 0 {
|
||||
result, err := a.userBelongsToTeams(otherUserId, restrictions.Teams)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if result {
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
|
||||
if len(restrictions.Channels) > 0 {
|
||||
result, err := a.userBelongsToChannels(otherUserId, restrictions.Channels)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if result {
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func (a *App) userBelongsToTeams(userId string, teamIds []string) (bool, *model.AppError) {
|
||||
result := <-a.Srv.Store.Team().UserBelongsToTeams(userId, teamIds)
|
||||
if result.Err != nil {
|
||||
return false, result.Err
|
||||
}
|
||||
return result.Data.(bool), nil
|
||||
}
|
||||
|
||||
func (a *App) userBelongsToChannels(userId string, channelIds []string) (bool, *model.AppError) {
|
||||
result := <-a.Srv.Store.Channel().UserBelongsToChannels(userId, channelIds)
|
||||
if result.Err != nil {
|
||||
return false, result.Err
|
||||
}
|
||||
return result.Data.(bool), nil
|
||||
}
|
||||
|
||||
func (a *App) GetViewUsersRestrictions(userId string) (*model.ViewUsersRestrictions, *model.AppError) {
|
||||
if a.HasPermissionTo(userId, model.PERMISSION_VIEW_MEMBERS) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
result := <-a.Srv.Store.Team().GetUserTeamIds(userId, true)
|
||||
if result.Err != nil {
|
||||
return nil, result.Err
|
||||
}
|
||||
teamIds := result.Data.([]string)
|
||||
|
||||
teamIdsWithPermission := []string{}
|
||||
teamIdsWithoutPermission := []string{}
|
||||
for _, teamId := range teamIds {
|
||||
if a.HasPermissionToTeam(userId, teamId, model.PERMISSION_VIEW_MEMBERS) {
|
||||
teamIdsWithPermission = append(teamIdsWithPermission, teamId)
|
||||
} else {
|
||||
teamIdsWithoutPermission = append(teamIdsWithoutPermission, teamId)
|
||||
}
|
||||
}
|
||||
|
||||
if len(teamIdsWithoutPermission) == 0 {
|
||||
return &model.ViewUsersRestrictions{Teams: teamIdsWithPermission}, nil
|
||||
}
|
||||
|
||||
userChannelMembers := <-a.Srv.Store.Channel().GetAllChannelMembersForUser(userId, true, true)
|
||||
if userChannelMembers.Err != nil {
|
||||
return nil, userChannelMembers.Err
|
||||
}
|
||||
|
||||
channelIds := []string{}
|
||||
for channelId := range userChannelMembers.Data.(map[string]string) {
|
||||
channelIds = append(channelIds, channelId)
|
||||
}
|
||||
|
||||
return &model.ViewUsersRestrictions{Teams: teamIdsWithPermission, Channels: channelIds}, nil
|
||||
}
|
||||
|
||||
func (a *App) GetViewUsersRestrictionsForTeam(userId string, teamId string) ([]string, *model.AppError) {
|
||||
if a.HasPermissionTo(userId, model.PERMISSION_VIEW_MEMBERS) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
if a.HasPermissionToTeam(userId, teamId, model.PERMISSION_VIEW_MEMBERS) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
result := <-a.Srv.Store.Channel().GetMembersForUser(teamId, userId)
|
||||
if result.Err != nil {
|
||||
return nil, result.Err
|
||||
}
|
||||
|
||||
channelIds := []string{}
|
||||
for _, membership := range *result.Data.(*model.ChannelMembers) {
|
||||
channelIds = append(channelIds, membership.ChannelId)
|
||||
}
|
||||
|
||||
return channelIds, nil
|
||||
}
|
||||
|
||||
func (a *App) getListOfAllowedChannelsForTeam(teamId string, viewRestrictions *model.ViewUsersRestrictions) ([]string, *model.AppError) {
|
||||
var listOfAllowedChannels []string
|
||||
if viewRestrictions == nil || strings.Contains(strings.Join(viewRestrictions.Teams, "."), teamId) {
|
||||
result := <-a.Srv.Store.Channel().GetTeamChannels(teamId)
|
||||
if result.Err != nil {
|
||||
return nil, result.Err
|
||||
}
|
||||
channelIds := []string{}
|
||||
for _, channel := range *result.Data.(*model.ChannelList) {
|
||||
channelIds = append(channelIds, channel.Id)
|
||||
}
|
||||
|
||||
return channelIds, nil
|
||||
}
|
||||
|
||||
cresult := <-a.Srv.Store.Channel().GetChannelsByIds(viewRestrictions.Channels)
|
||||
if cresult.Err != nil {
|
||||
return nil, cresult.Err
|
||||
}
|
||||
for _, c := range cresult.Data.([]*model.Channel) {
|
||||
if c.TeamId == teamId {
|
||||
listOfAllowedChannels = append(listOfAllowedChannels, c.Id)
|
||||
}
|
||||
}
|
||||
|
||||
return listOfAllowedChannels, nil
|
||||
}
|
||||
|
||||
203
app/user_test.go
203
app/user_test.go
@@ -704,3 +704,206 @@ func TestPasswordRecovery(t *testing.T) {
|
||||
err = th.App.ResetPasswordFromToken(token.Token, "abcdefgh")
|
||||
assert.NotNil(t, err)
|
||||
}
|
||||
|
||||
func TestGetViewUsersRestrictions(t *testing.T) {
|
||||
th := Setup(t).InitBasic()
|
||||
defer th.TearDown()
|
||||
|
||||
team1 := th.CreateTeam()
|
||||
team2 := th.CreateTeam()
|
||||
th.CreateTeam() // Another team
|
||||
|
||||
user1 := th.CreateUser()
|
||||
|
||||
th.LinkUserToTeam(user1, team1)
|
||||
th.LinkUserToTeam(user1, team2)
|
||||
|
||||
th.App.UpdateTeamMemberRoles(team1.Id, user1.Id, "team_user team_admin")
|
||||
|
||||
team1channel1 := th.CreateChannel(team1)
|
||||
team1channel2 := th.CreateChannel(team1)
|
||||
th.CreateChannel(team1) // Another channel
|
||||
team1offtopic, err := th.App.GetChannelByName("off-topic", team1.Id, false)
|
||||
require.Nil(t, err)
|
||||
team1townsquare, err := th.App.GetChannelByName("town-square", team1.Id, false)
|
||||
require.Nil(t, err)
|
||||
|
||||
team2channel1 := th.CreateChannel(team2)
|
||||
th.CreateChannel(team2) // Another channel
|
||||
team2offtopic, err := th.App.GetChannelByName("off-topic", team2.Id, false)
|
||||
require.Nil(t, err)
|
||||
team2townsquare, err := th.App.GetChannelByName("town-square", team2.Id, false)
|
||||
require.Nil(t, err)
|
||||
|
||||
th.App.AddUserToChannel(user1, team1channel1)
|
||||
th.App.AddUserToChannel(user1, team1channel2)
|
||||
th.App.AddUserToChannel(user1, team2channel1)
|
||||
|
||||
addPermission := func(role *model.Role, permission string) *model.AppError {
|
||||
newPermissions := append(role.Permissions, permission)
|
||||
_, err := th.App.PatchRole(role, &model.RolePatch{Permissions: &newPermissions})
|
||||
return err
|
||||
}
|
||||
|
||||
removePermission := func(role *model.Role, permission string) *model.AppError {
|
||||
newPermissions := []string{}
|
||||
for _, oldPermission := range role.Permissions {
|
||||
if permission != oldPermission {
|
||||
newPermissions = append(newPermissions, oldPermission)
|
||||
}
|
||||
}
|
||||
_, err := th.App.PatchRole(role, &model.RolePatch{Permissions: &newPermissions})
|
||||
return err
|
||||
}
|
||||
|
||||
t.Run("VIEW_MEMBERS permission granted at system level", func(t *testing.T) {
|
||||
restrictions, err := th.App.GetViewUsersRestrictions(user1.Id)
|
||||
require.Nil(t, err)
|
||||
|
||||
assert.Nil(t, restrictions)
|
||||
})
|
||||
|
||||
t.Run("VIEW_MEMBERS permission granted at team level", func(t *testing.T) {
|
||||
systemUserRole, err := th.App.GetRoleByName(model.SYSTEM_USER_ROLE_ID)
|
||||
require.Nil(t, err)
|
||||
teamUserRole, err := th.App.GetRoleByName(model.TEAM_USER_ROLE_ID)
|
||||
require.Nil(t, err)
|
||||
|
||||
require.Nil(t, removePermission(systemUserRole, model.PERMISSION_VIEW_MEMBERS.Id))
|
||||
defer addPermission(systemUserRole, model.PERMISSION_VIEW_MEMBERS.Id)
|
||||
require.Nil(t, addPermission(teamUserRole, model.PERMISSION_VIEW_MEMBERS.Id))
|
||||
defer removePermission(teamUserRole, model.PERMISSION_VIEW_MEMBERS.Id)
|
||||
|
||||
restrictions, err := th.App.GetViewUsersRestrictions(user1.Id)
|
||||
require.Nil(t, err)
|
||||
|
||||
assert.NotNil(t, restrictions)
|
||||
assert.NotNil(t, restrictions.Teams)
|
||||
assert.Len(t, restrictions.Channels, 0)
|
||||
assert.ElementsMatch(t, []string{team1.Id, team2.Id}, restrictions.Teams)
|
||||
})
|
||||
|
||||
t.Run("VIEW_MEMBERS permission not granted at any level", func(t *testing.T) {
|
||||
systemUserRole, err := th.App.GetRoleByName(model.SYSTEM_USER_ROLE_ID)
|
||||
require.Nil(t, err)
|
||||
require.Nil(t, removePermission(systemUserRole, model.PERMISSION_VIEW_MEMBERS.Id))
|
||||
defer addPermission(systemUserRole, model.PERMISSION_VIEW_MEMBERS.Id)
|
||||
|
||||
restrictions, err := th.App.GetViewUsersRestrictions(user1.Id)
|
||||
require.Nil(t, err)
|
||||
|
||||
assert.NotNil(t, restrictions)
|
||||
assert.Len(t, restrictions.Teams, 0)
|
||||
assert.NotNil(t, restrictions.Channels)
|
||||
assert.ElementsMatch(t, []string{team1townsquare.Id, team1offtopic.Id, team1channel1.Id, team1channel2.Id, team2townsquare.Id, team2offtopic.Id, team2channel1.Id}, restrictions.Channels)
|
||||
})
|
||||
|
||||
t.Run("VIEW_MEMBERS permission for some teams but not for others", func(t *testing.T) {
|
||||
systemUserRole, err := th.App.GetRoleByName(model.SYSTEM_USER_ROLE_ID)
|
||||
require.Nil(t, err)
|
||||
teamAdminRole, err := th.App.GetRoleByName(model.TEAM_ADMIN_ROLE_ID)
|
||||
require.Nil(t, err)
|
||||
|
||||
require.Nil(t, removePermission(systemUserRole, model.PERMISSION_VIEW_MEMBERS.Id))
|
||||
defer addPermission(systemUserRole, model.PERMISSION_VIEW_MEMBERS.Id)
|
||||
require.Nil(t, addPermission(teamAdminRole, model.PERMISSION_VIEW_MEMBERS.Id))
|
||||
defer removePermission(teamAdminRole, model.PERMISSION_VIEW_MEMBERS.Id)
|
||||
|
||||
restrictions, err := th.App.GetViewUsersRestrictions(user1.Id)
|
||||
require.Nil(t, err)
|
||||
|
||||
assert.NotNil(t, restrictions)
|
||||
assert.NotNil(t, restrictions.Teams)
|
||||
assert.NotNil(t, restrictions.Channels)
|
||||
assert.ElementsMatch(t, restrictions.Teams, []string{team1.Id})
|
||||
assert.ElementsMatch(t, []string{team1townsquare.Id, team1offtopic.Id, team1channel1.Id, team1channel2.Id, team2townsquare.Id, team2offtopic.Id, team2channel1.Id}, restrictions.Channels)
|
||||
})
|
||||
}
|
||||
|
||||
func TestGetViewUsersRestrictionsForTeam(t *testing.T) {
|
||||
th := Setup(t).InitBasic()
|
||||
defer th.TearDown()
|
||||
|
||||
team1 := th.CreateTeam()
|
||||
team2 := th.CreateTeam()
|
||||
th.CreateTeam() // Another team
|
||||
|
||||
user1 := th.CreateUser()
|
||||
|
||||
th.LinkUserToTeam(user1, team1)
|
||||
th.LinkUserToTeam(user1, team2)
|
||||
|
||||
th.App.UpdateTeamMemberRoles(team1.Id, user1.Id, "team_user team_admin")
|
||||
|
||||
team1channel1 := th.CreateChannel(team1)
|
||||
team1channel2 := th.CreateChannel(team1)
|
||||
th.CreateChannel(team1) // Another channel
|
||||
team1offtopic, err := th.App.GetChannelByName("off-topic", team1.Id, false)
|
||||
require.Nil(t, err)
|
||||
team1townsquare, err := th.App.GetChannelByName("town-square", team1.Id, false)
|
||||
require.Nil(t, err)
|
||||
|
||||
team2channel1 := th.CreateChannel(team2)
|
||||
th.CreateChannel(team2) // Another channel
|
||||
team2offtopic, err := th.App.GetChannelByName("off-topic", team2.Id, false)
|
||||
require.Nil(t, err)
|
||||
team2townsquare, err := th.App.GetChannelByName("town-square", team2.Id, false)
|
||||
require.Nil(t, err)
|
||||
|
||||
th.App.AddUserToChannel(user1, team1channel1)
|
||||
th.App.AddUserToChannel(user1, team1channel2)
|
||||
th.App.AddUserToChannel(user1, team2channel1)
|
||||
|
||||
addPermission := func(role *model.Role, permission string) *model.AppError {
|
||||
newPermissions := append(role.Permissions, permission)
|
||||
_, err := th.App.PatchRole(role, &model.RolePatch{Permissions: &newPermissions})
|
||||
return err
|
||||
}
|
||||
|
||||
removePermission := func(role *model.Role, permission string) *model.AppError {
|
||||
newPermissions := []string{}
|
||||
for _, oldPermission := range role.Permissions {
|
||||
if permission != oldPermission {
|
||||
newPermissions = append(newPermissions, oldPermission)
|
||||
}
|
||||
}
|
||||
_, err := th.App.PatchRole(role, &model.RolePatch{Permissions: &newPermissions})
|
||||
return err
|
||||
}
|
||||
|
||||
t.Run("VIEW_MEMBERS permission granted at system level", func(t *testing.T) {
|
||||
restrictions, err := th.App.GetViewUsersRestrictionsForTeam(user1.Id, team1.Id)
|
||||
require.Nil(t, err)
|
||||
|
||||
assert.Nil(t, restrictions)
|
||||
})
|
||||
|
||||
t.Run("VIEW_MEMBERS permission granted at team level", func(t *testing.T) {
|
||||
systemUserRole, err := th.App.GetRoleByName(model.SYSTEM_USER_ROLE_ID)
|
||||
require.Nil(t, err)
|
||||
teamUserRole, err := th.App.GetRoleByName(model.TEAM_USER_ROLE_ID)
|
||||
require.Nil(t, err)
|
||||
|
||||
require.Nil(t, removePermission(systemUserRole, model.PERMISSION_VIEW_MEMBERS.Id))
|
||||
defer addPermission(systemUserRole, model.PERMISSION_VIEW_MEMBERS.Id)
|
||||
require.Nil(t, addPermission(teamUserRole, model.PERMISSION_VIEW_MEMBERS.Id))
|
||||
defer removePermission(teamUserRole, model.PERMISSION_VIEW_MEMBERS.Id)
|
||||
|
||||
restrictions, err := th.App.GetViewUsersRestrictionsForTeam(user1.Id, team1.Id)
|
||||
require.Nil(t, err)
|
||||
assert.Nil(t, restrictions)
|
||||
})
|
||||
|
||||
t.Run("VIEW_MEMBERS permission not granted at any level", func(t *testing.T) {
|
||||
systemUserRole, err := th.App.GetRoleByName(model.SYSTEM_USER_ROLE_ID)
|
||||
require.Nil(t, err)
|
||||
require.Nil(t, removePermission(systemUserRole, model.PERMISSION_VIEW_MEMBERS.Id))
|
||||
defer addPermission(systemUserRole, model.PERMISSION_VIEW_MEMBERS.Id)
|
||||
|
||||
restrictions, err := th.App.GetViewUsersRestrictionsForTeam(user1.Id, team1.Id)
|
||||
require.Nil(t, err)
|
||||
|
||||
assert.NotNil(t, restrictions)
|
||||
assert.ElementsMatch(t, []string{team1townsquare.Id, team1offtopic.Id, team1channel1.Id, team1channel2.Id, team2townsquare.Id, team2offtopic.Id, team2channel1.Id}, restrictions)
|
||||
})
|
||||
}
|
||||
|
||||
1088
app/user_viewmembers_test.go
Обычный файл
1088
app/user_viewmembers_test.go
Обычный файл
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
@@ -303,6 +303,19 @@ func (a *App) InvalidateCacheForUser(userId string) {
|
||||
}
|
||||
}
|
||||
|
||||
func (a *App) InvalidateCacheForUserTeams(userId string) {
|
||||
a.InvalidateCacheForUserTeamsSkipClusterSend(userId)
|
||||
|
||||
if a.Cluster != nil {
|
||||
msg := &model.ClusterMessage{
|
||||
Event: model.CLUSTER_EVENT_INVALIDATE_CACHE_FOR_USER_TEAMS,
|
||||
SendType: model.CLUSTER_SEND_BEST_EFFORT,
|
||||
Data: userId,
|
||||
}
|
||||
a.Cluster.SendClusterMessage(msg)
|
||||
}
|
||||
}
|
||||
|
||||
func (a *App) InvalidateCacheForUserSkipClusterSend(userId string) {
|
||||
a.Srv.Store.Channel().InvalidateAllChannelMembersForUser(userId)
|
||||
a.Srv.Store.User().InvalidateProfilesInChannelCacheByUser(userId)
|
||||
@@ -314,6 +327,15 @@ func (a *App) InvalidateCacheForUserSkipClusterSend(userId string) {
|
||||
}
|
||||
}
|
||||
|
||||
func (a *App) InvalidateCacheForUserTeamsSkipClusterSend(userId string) {
|
||||
a.Srv.Store.Team().InvalidateAllTeamIdsForUser(userId)
|
||||
|
||||
hub := a.GetHubForUserId(userId)
|
||||
if hub != nil {
|
||||
hub.InvalidateUser(userId)
|
||||
}
|
||||
}
|
||||
|
||||
func (a *App) InvalidateCacheForWebhook(webhookId string) {
|
||||
a.InvalidateCacheForWebhookSkipClusterSend(webhookId)
|
||||
|
||||
|
||||
Ссылка в новой задаче
Block a user