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
Этот коммит содержится в:
Jesús Espino
2019-04-29 16:56:56 +02:00
коммит произвёл GitHub
родитель 5b70962f71
Коммит c8920588a0
41 изменённых файлов: 2785 добавлений и 259 удалений

Просмотреть файл

@@ -295,6 +295,17 @@ func getTeamMember(c *Context, w http.ResponseWriter, r *http.Request) {
return
}
canSee, err := c.App.UserCanSeeOtherUser(c.App.Session.UserId, c.Params.UserId)
if err != nil {
c.Err = err
return
}
if !canSee {
c.SetPermissionError(model.PERMISSION_VIEW_MEMBERS)
return
}
team, err := c.App.GetTeamMember(c.Params.TeamId, c.Params.UserId)
if err != nil {
c.Err = err
@@ -315,7 +326,13 @@ func getTeamMembers(c *Context, w http.ResponseWriter, r *http.Request) {
return
}
members, err := c.App.GetTeamMembers(c.Params.TeamId, c.Params.Page*c.Params.PerPage, c.Params.PerPage)
restrictions, err := c.App.GetViewUsersRestrictions(c.App.Session.UserId)
if err != nil {
c.Err = err
return
}
members, err := c.App.GetTeamMembers(c.Params.TeamId, c.Params.Page*c.Params.PerPage, c.Params.PerPage, restrictions)
if err != nil {
c.Err = err
return
@@ -335,6 +352,17 @@ func getTeamMembersForUser(c *Context, w http.ResponseWriter, r *http.Request) {
return
}
canSee, err := c.App.UserCanSeeOtherUser(c.App.Session.UserId, c.Params.UserId)
if err != nil {
c.Err = err
return
}
if !canSee {
c.SetPermissionError(model.PERMISSION_VIEW_MEMBERS)
return
}
members, err := c.App.GetTeamMembersForUser(c.Params.UserId)
if err != nil {
c.Err = err
@@ -362,7 +390,13 @@ func getTeamMembersByIds(c *Context, w http.ResponseWriter, r *http.Request) {
return
}
members, err := c.App.GetTeamMembersByIds(c.Params.TeamId, userIds)
restrictions, err := c.App.GetViewUsersRestrictions(c.App.Session.UserId)
if err != nil {
c.Err = err
return
}
members, err := c.App.GetTeamMembersByIds(c.Params.TeamId, userIds, restrictions)
if err != nil {
c.Err = err
return

Просмотреть файл

@@ -111,7 +111,16 @@ func getUser(c *Context, w http.ResponseWriter, r *http.Request) {
return
}
// No permission check required
canSee, err := c.App.UserCanSeeOtherUser(c.App.Session.UserId, c.Params.UserId)
if err != nil {
c.SetPermissionError(model.PERMISSION_VIEW_MEMBERS)
return
}
if !canSee {
c.SetPermissionError(model.PERMISSION_VIEW_MEMBERS)
return
}
user, err := c.App.GetUser(c.Params.UserId)
if err != nil {
@@ -154,14 +163,32 @@ func getUserByUsername(c *Context, w http.ResponseWriter, r *http.Request) {
return
}
// No permission check required
user, err := c.App.GetUserByUsername(c.Params.Username)
if err != nil {
restrictions, err2 := c.App.GetViewUsersRestrictions(c.App.Session.UserId)
if err2 != nil {
c.Err = err2
return
}
if restrictions != nil {
c.SetPermissionError(model.PERMISSION_VIEW_MEMBERS)
return
}
c.Err = err
return
}
canSee, err := c.App.UserCanSeeOtherUser(c.App.Session.UserId, user.Id)
if err != nil {
c.Err = err
return
}
if !canSee {
c.SetPermissionError(model.PERMISSION_VIEW_MEMBERS)
return
}
if c.IsSystemAdmin() || c.App.Session.UserId == user.Id {
userTermsOfService, err := c.App.GetUserTermsOfService(user.Id)
if err != nil && err.StatusCode != http.StatusNotFound {
@@ -196,8 +223,6 @@ func getUserByEmail(c *Context, w http.ResponseWriter, r *http.Request) {
return
}
// No permission check required, but still prevent users who can't see another user's email address from using this
sanitizeOptions := c.App.GetSanitizeOptions(c.IsSystemAdmin())
if !sanitizeOptions["email"] {
c.Err = model.NewAppError("getUserByEmail", "api.user.get_user_by_email.permissions.app_error", nil, "userId="+c.App.Session.UserId, http.StatusForbidden)
@@ -206,10 +231,30 @@ func getUserByEmail(c *Context, w http.ResponseWriter, r *http.Request) {
user, err := c.App.GetUserByEmail(c.Params.Email)
if err != nil {
restrictions, err2 := c.App.GetViewUsersRestrictions(c.App.Session.UserId)
if err2 != nil {
c.Err = err2
return
}
if restrictions != nil {
c.SetPermissionError(model.PERMISSION_VIEW_MEMBERS)
return
}
c.Err = err
return
}
canSee, err := c.App.UserCanSeeOtherUser(c.App.Session.UserId, user.Id)
if err != nil {
c.Err = err
return
}
if !canSee {
c.SetPermissionError(model.PERMISSION_VIEW_MEMBERS)
return
}
etag := user.Etag(*c.App.Config().PrivacySettings.ShowFullName, *c.App.Config().PrivacySettings.ShowEmailAddress)
if c.HandleEtag(etag, "Get User", w, r) {
@@ -227,18 +272,23 @@ func getDefaultProfileImage(c *Context, w http.ResponseWriter, r *http.Request)
return
}
users, err := c.App.GetUsersByIds([]string{c.Params.UserId}, c.IsSystemAdmin())
canSee, err := c.App.UserCanSeeOtherUser(c.App.Session.UserId, c.Params.UserId)
if err != nil {
c.Err = err
return
}
if len(users) == 0 {
c.Err = model.NewAppError("getProfileImage", "api.user.get_profile_image.not_found.app_error", nil, "", http.StatusNotFound)
if !canSee {
c.SetPermissionError(model.PERMISSION_VIEW_MEMBERS)
return
}
user, err := c.App.GetUser(c.Params.UserId)
if err != nil {
c.Err = err
return
}
user := users[0]
img, err := c.App.GetDefaultProfileImage(user)
if err != nil {
c.Err = err
@@ -256,18 +306,23 @@ func getProfileImage(c *Context, w http.ResponseWriter, r *http.Request) {
return
}
users, err := c.App.GetUsersByIds([]string{c.Params.UserId}, c.IsSystemAdmin())
canSee, err := c.App.UserCanSeeOtherUser(c.App.Session.UserId, c.Params.UserId)
if err != nil {
c.Err = err
return
}
if len(users) == 0 {
c.Err = model.NewAppError("getProfileImage", "api.user.get_profile_image.not_found.app_error", nil, "", http.StatusNotFound)
if !canSee {
c.SetPermissionError(model.PERMISSION_VIEW_MEMBERS)
return
}
user, err := c.App.GetUser(c.Params.UserId)
if err != nil {
c.Err = err
return
}
user := users[0]
etag := strconv.FormatInt(user.LastPictureUpdate, 10)
if c.HandleEtag(etag, "Get Profile Image", w, r) {
return
@@ -376,7 +431,13 @@ func getTotalUsersStats(c *Context, w http.ResponseWriter, r *http.Request) {
return
}
stats, err := c.App.GetTotalUsersStats()
restrictions, err := c.App.GetViewUsersRestrictions(c.App.Session.UserId)
if err != nil {
c.Err = err
return
}
stats, err := c.App.GetTotalUsersStats(restrictions)
if err != nil {
c.Err = err
return
@@ -419,21 +480,27 @@ func getUsers(c *Context, w http.ResponseWriter, r *http.Request) {
withoutTeamBool, _ := strconv.ParseBool(withoutTeam)
inactiveBool, _ := strconv.ParseBool(inactive)
restrictions, err := c.App.GetViewUsersRestrictions(c.App.Session.UserId)
if err != nil {
c.Err = err
return
}
userGetOptions := &model.UserGetOptions{
InTeamId: inTeamId,
InChannelId: inChannelId,
NotInTeamId: notInTeamId,
NotInChannelId: notInChannelId,
WithoutTeam: withoutTeamBool,
Inactive: inactiveBool,
Role: role,
Sort: sort,
Page: c.Params.Page,
PerPage: c.Params.PerPage,
InTeamId: inTeamId,
InChannelId: inChannelId,
NotInTeamId: notInTeamId,
NotInChannelId: notInChannelId,
WithoutTeam: withoutTeamBool,
Inactive: inactiveBool,
Role: role,
Sort: sort,
Page: c.Params.Page,
PerPage: c.Params.PerPage,
ViewRestrictions: restrictions,
}
var profiles []*model.User
var err *model.AppError
etag := ""
if withoutTeamBool, _ := strconv.ParseBool(withoutTeam); withoutTeamBool {
@@ -443,26 +510,26 @@ func getUsers(c *Context, w http.ResponseWriter, r *http.Request) {
return
}
profiles, err = c.App.GetUsersWithoutTeamPage(c.Params.Page, c.Params.PerPage, c.IsSystemAdmin())
profiles, err = c.App.GetUsersWithoutTeamPage(c.Params.Page, c.Params.PerPage, c.IsSystemAdmin(), restrictions)
} else if len(notInChannelId) > 0 {
if !c.App.SessionHasPermissionToChannel(c.App.Session, notInChannelId, model.PERMISSION_READ_CHANNEL) {
c.SetPermissionError(model.PERMISSION_READ_CHANNEL)
return
}
profiles, err = c.App.GetUsersNotInChannelPage(inTeamId, notInChannelId, c.Params.Page, c.Params.PerPage, c.IsSystemAdmin())
profiles, err = c.App.GetUsersNotInChannelPage(inTeamId, notInChannelId, c.Params.Page, c.Params.PerPage, c.IsSystemAdmin(), restrictions)
} else if len(notInTeamId) > 0 {
if !c.App.SessionHasPermissionToTeam(c.App.Session, notInTeamId, model.PERMISSION_VIEW_TEAM) {
c.SetPermissionError(model.PERMISSION_VIEW_TEAM)
return
}
etag = c.App.GetUsersNotInTeamEtag(inTeamId)
etag = c.App.GetUsersNotInTeamEtag(inTeamId, restrictions.Hash())
if c.HandleEtag(etag, "Get Users Not in Team", w, r) {
return
}
profiles, err = c.App.GetUsersNotInTeamPage(notInTeamId, c.Params.Page, c.Params.PerPage, c.IsSystemAdmin())
profiles, err = c.App.GetUsersNotInTeamPage(notInTeamId, c.Params.Page, c.Params.PerPage, c.IsSystemAdmin(), restrictions)
} else if len(inTeamId) > 0 {
if !c.App.SessionHasPermissionToTeam(c.App.Session, inTeamId, model.PERMISSION_VIEW_TEAM) {
c.SetPermissionError(model.PERMISSION_VIEW_TEAM)
@@ -470,11 +537,11 @@ func getUsers(c *Context, w http.ResponseWriter, r *http.Request) {
}
if sort == "last_activity_at" {
profiles, err = c.App.GetRecentlyActiveUsersForTeamPage(inTeamId, c.Params.Page, c.Params.PerPage, c.IsSystemAdmin())
profiles, err = c.App.GetRecentlyActiveUsersForTeamPage(inTeamId, c.Params.Page, c.Params.PerPage, c.IsSystemAdmin(), restrictions)
} else if sort == "create_at" {
profiles, err = c.App.GetNewUsersForTeamPage(inTeamId, c.Params.Page, c.Params.PerPage, c.IsSystemAdmin())
profiles, err = c.App.GetNewUsersForTeamPage(inTeamId, c.Params.Page, c.Params.PerPage, c.IsSystemAdmin(), restrictions)
} else {
etag = c.App.GetUsersInTeamEtag(inTeamId)
etag = c.App.GetUsersInTeamEtag(inTeamId, restrictions.Hash())
if c.HandleEtag(etag, "Get Users in Team", w, r) {
return
}
@@ -491,12 +558,16 @@ func getUsers(c *Context, w http.ResponseWriter, r *http.Request) {
profiles, err = c.App.GetUsersInChannelPage(inChannelId, c.Params.Page, c.Params.PerPage, c.IsSystemAdmin())
}
} else {
// No permission check required
etag = c.App.GetUsersEtag()
etag = c.App.GetUsersEtag(restrictions.Hash())
if c.HandleEtag(etag, "Get Users", w, r) {
return
}
userGetOptions, err = c.App.RestrictUsersGetByPermissions(c.App.Session.UserId, userGetOptions)
if err != nil {
c.Err = err
return
}
profiles, err = c.App.GetUsersPage(userGetOptions, c.IsSystemAdmin())
}
@@ -520,9 +591,13 @@ func getUsersByIds(c *Context, w http.ResponseWriter, r *http.Request) {
return
}
// No permission check required
restrictions, err := c.App.GetViewUsersRestrictions(c.App.Session.UserId)
if err != nil {
c.Err = err
return
}
users, err := c.App.GetUsersByIds(userIds, c.IsSystemAdmin())
users, err := c.App.GetUsersByIds(userIds, c.IsSystemAdmin(), restrictions)
if err != nil {
c.Err = err
return
@@ -539,9 +614,13 @@ func getUsersByNames(c *Context, w http.ResponseWriter, r *http.Request) {
return
}
// No permission check required
restrictions, err := c.App.GetViewUsersRestrictions(c.App.Session.UserId)
if err != nil {
c.Err = err
return
}
users, err := c.App.GetUsersByUsernames(usernames, c.IsSystemAdmin())
users, err := c.App.GetUsersByUsernames(usernames, c.IsSystemAdmin(), restrictions)
if err != nil {
c.Err = err
return
@@ -607,6 +686,12 @@ func searchUsers(c *Context, w http.ResponseWriter, r *http.Request) {
options.AllowFullNames = *c.App.Config().PrivacySettings.ShowFullName
}
options, err := c.App.RestrictUsersSearchByPermissions(c.App.Session.UserId, options)
if err != nil {
c.Err = err
return
}
profiles, err := c.App.SearchUsers(props, options)
if err != nil {
c.Err = err
@@ -670,6 +755,13 @@ func autocompleteUsers(c *Context, w http.ResponseWriter, r *http.Request) {
autocomplete.Users = result.InChannel
autocomplete.OutOfChannel = result.OutOfChannel
} else if len(teamId) > 0 {
var err *model.AppError
options, err = c.App.RestrictUsersSearchByPermissions(c.App.Session.UserId, options)
if err != nil {
c.Err = err
return
}
result, err := c.App.AutocompleteUsersInTeam(teamId, name, options)
if err != nil {
c.Err = err
@@ -678,7 +770,13 @@ func autocompleteUsers(c *Context, w http.ResponseWriter, r *http.Request) {
autocomplete.Users = result.InTeam
} else {
// No permission check required
var err *model.AppError
options, err = c.App.RestrictUsersSearchByPermissions(c.App.Session.UserId, options)
if err != nil {
c.Err = err
return
}
result, err := c.App.SearchUsersInTeam("", name, options)
if err != nil {
c.Err = err

Просмотреть файл

@@ -525,7 +525,7 @@ func TestGetBotUser(t *testing.T) {
defer th.RestoreDefaultRolePermissions(th.SaveDefaultRolePermissions())
th.AddPermissionToRole(model.PERMISSION_CREATE_BOT.Id, model.TEAM_USER_ROLE_ID)
th.App.UpdateUserRoles(th.BasicUser.Id, model.TEAM_USER_ROLE_ID, false)
th.App.UpdateUserRoles(th.BasicUser.Id, model.SYSTEM_USER_ROLE_ID+" "+model.TEAM_USER_ROLE_ID, false)
bot := &model.Bot{
Username: GenerateTestUsername(),
@@ -538,6 +538,7 @@ func TestGetBotUser(t *testing.T) {
defer th.App.PermanentDeleteBot(createdBot.UserId)
botUser, resp := th.Client.GetUser(createdBot.UserId, "")
CheckNoError(t, resp)
require.Equal(t, bot.Username, botUser.Username)
require.True(t, botUser.IsBot)
}

471
api4/user_viewmembers_test.go Обычный файл
Просмотреть файл

@@ -0,0 +1,471 @@
package api4
import (
"testing"
"github.com/mattermost/mattermost-server/model"
"github.com/stretchr/testify/require"
)
func TestApiResctrictedViewMembers(t *testing.T) {
th := Setup()
defer th.TearDown()
// Create first account for system admin
_, err := th.App.CreateUser(&model.User{Email: th.GenerateTestEmail(), Nickname: "test user0", Password: "test-password-0", Username: "test-user-0", Roles: model.SYSTEM_USER_ROLE_ID})
require.Nil(t, err)
user1, err := th.App.CreateUser(&model.User{Email: th.GenerateTestEmail(), Nickname: "test user1", Password: "test-password-1", Username: "test-user-1", Roles: model.SYSTEM_USER_ROLE_ID})
require.Nil(t, err)
user2, err := th.App.CreateUser(&model.User{Email: th.GenerateTestEmail(), Nickname: "test user2", Password: "test-password-2", Username: "test-user-2", Roles: model.SYSTEM_USER_ROLE_ID})
require.Nil(t, err)
user3, err := th.App.CreateUser(&model.User{Email: th.GenerateTestEmail(), Nickname: "test user3", Password: "test-password-3", Username: "test-user-3", Roles: model.SYSTEM_USER_ROLE_ID})
require.Nil(t, err)
user4, err := th.App.CreateUser(&model.User{Email: th.GenerateTestEmail(), Nickname: "test user4", Password: "test-password-4", Username: "test-user-4", Roles: model.SYSTEM_USER_ROLE_ID})
require.Nil(t, err)
user5, err := th.App.CreateUser(&model.User{Email: th.GenerateTestEmail(), Nickname: "test user5", Password: "test-password-5", Username: "test-user-5", Roles: model.SYSTEM_USER_ROLE_ID})
require.Nil(t, err)
team1, err := th.App.CreateTeam(&model.Team{DisplayName: "dn_" + model.NewId(), Name: GenerateTestTeamName(), Email: th.GenerateTestEmail(), Type: model.TEAM_OPEN})
require.Nil(t, err)
team2, err := th.App.CreateTeam(&model.Team{DisplayName: "dn_" + model.NewId(), Name: GenerateTestTeamName(), Email: th.GenerateTestEmail(), Type: model.TEAM_OPEN})
require.Nil(t, err)
channel1, err := th.App.CreateChannel(&model.Channel{DisplayName: "dn_" + model.NewId(), Name: "name_" + model.NewId(), Type: model.CHANNEL_OPEN, TeamId: team1.Id, CreatorId: model.NewId()}, false)
require.Nil(t, err)
channel2, err := th.App.CreateChannel(&model.Channel{DisplayName: "dn_" + model.NewId(), Name: "name_" + model.NewId(), Type: model.CHANNEL_OPEN, TeamId: team1.Id, CreatorId: model.NewId()}, false)
require.Nil(t, err)
channel3, err := th.App.CreateChannel(&model.Channel{DisplayName: "dn_" + model.NewId(), Name: "name_" + model.NewId(), Type: model.CHANNEL_OPEN, TeamId: team2.Id, CreatorId: model.NewId()}, false)
require.Nil(t, err)
th.LinkUserToTeam(user1, team1)
th.LinkUserToTeam(user2, team1)
th.LinkUserToTeam(user3, team2)
th.LinkUserToTeam(user4, team1)
th.LinkUserToTeam(user4, team2)
th.AddUserToChannel(user1, channel1)
th.AddUserToChannel(user2, channel2)
th.AddUserToChannel(user3, channel3)
th.AddUserToChannel(user4, channel1)
th.AddUserToChannel(user4, channel3)
th.App.SetStatusOnline(user1.Id, true)
th.App.SetStatusOnline(user2.Id, true)
th.App.SetStatusOnline(user3.Id, true)
th.App.SetStatusOnline(user4.Id, true)
th.App.SetStatusOnline(user5.Id, true)
_, resp := th.Client.Login(user1.Username, "test-password-1")
CheckNoError(t, resp)
t.Run("getUser", func(t *testing.T) {
testCases := []struct {
Name string
RestrictedTo string
UserId string
ExpectedError string
}{
{
"Get visible user without restrictions",
"",
user5.Id,
"",
},
{
"Get not existing user without restrictions",
"",
model.NewId(),
"store.sql_user.missing_account.const",
},
{
"Get not existing user with restrictions to teams",
"teams",
model.NewId(),
"api.context.permissions.app_error",
},
{
"Get visible user with restrictions to teams",
"teams",
user2.Id,
"",
},
{
"Get not visible user with restrictions to teams",
"teams",
user5.Id,
"api.context.permissions.app_error",
},
{
"Get not existing user with restrictions to channels",
"channels",
model.NewId(),
"api.context.permissions.app_error",
},
{
"Get visible user with restrictions to channels",
"channels",
user4.Id,
"",
},
{
"Get not visible user with restrictions to channels",
"channels",
user3.Id,
"api.context.permissions.app_error",
},
}
defer th.RestoreDefaultRolePermissions(th.SaveDefaultRolePermissions())
for _, tc := range testCases {
t.Run(tc.Name, func(t *testing.T) {
if tc.RestrictedTo == "channels" {
th.RemovePermissionFromRole(model.PERMISSION_VIEW_MEMBERS.Id, model.SYSTEM_USER_ROLE_ID)
th.RemovePermissionFromRole(model.PERMISSION_VIEW_MEMBERS.Id, model.TEAM_USER_ROLE_ID)
} else if tc.RestrictedTo == "teams" {
th.RemovePermissionFromRole(model.PERMISSION_VIEW_MEMBERS.Id, model.SYSTEM_USER_ROLE_ID)
th.AddPermissionToRole(model.PERMISSION_VIEW_MEMBERS.Id, model.TEAM_USER_ROLE_ID)
} else {
th.RemovePermissionFromRole(model.PERMISSION_VIEW_MEMBERS.Id, model.TEAM_USER_ROLE_ID)
th.AddPermissionToRole(model.PERMISSION_VIEW_MEMBERS.Id, model.SYSTEM_USER_ROLE_ID)
}
_, resp := th.Client.GetUser(tc.UserId, "")
require.Nil(t, err)
if tc.ExpectedError != "" {
CheckErrorMessage(t, resp, tc.ExpectedError)
} else {
CheckNoError(t, resp)
}
})
}
})
t.Run("getUserByUsername", func(t *testing.T) {
testCases := []struct {
Name string
RestrictedTo string
Username string
ExpectedError string
}{
{
"Get visible user without restrictions",
"",
user5.Username,
"",
},
{
"Get not existing user without restrictions",
"",
model.NewId(),
"store.sql_user.get_by_username.app_error",
},
{
"Get not existing user with restrictions to teams",
"teams",
model.NewId(),
"api.context.permissions.app_error",
},
{
"Get visible user with restrictions to teams",
"teams",
user2.Username,
"",
},
{
"Get not visible user with restrictions to teams",
"teams",
user5.Username,
"api.context.permissions.app_error",
},
{
"Get not existing user with restrictions to channels",
"channels",
model.NewId(),
"api.context.permissions.app_error",
},
{
"Get visible user with restrictions to channels",
"channels",
user4.Username,
"",
},
{
"Get not visible user with restrictions to channels",
"channels",
user3.Username,
"api.context.permissions.app_error",
},
}
defer th.RestoreDefaultRolePermissions(th.SaveDefaultRolePermissions())
for _, tc := range testCases {
t.Run(tc.Name, func(t *testing.T) {
if tc.RestrictedTo == "channels" {
th.RemovePermissionFromRole(model.PERMISSION_VIEW_MEMBERS.Id, model.SYSTEM_USER_ROLE_ID)
th.RemovePermissionFromRole(model.PERMISSION_VIEW_MEMBERS.Id, model.TEAM_USER_ROLE_ID)
} else if tc.RestrictedTo == "teams" {
th.RemovePermissionFromRole(model.PERMISSION_VIEW_MEMBERS.Id, model.SYSTEM_USER_ROLE_ID)
th.AddPermissionToRole(model.PERMISSION_VIEW_MEMBERS.Id, model.TEAM_USER_ROLE_ID)
} else {
th.RemovePermissionFromRole(model.PERMISSION_VIEW_MEMBERS.Id, model.TEAM_USER_ROLE_ID)
th.AddPermissionToRole(model.PERMISSION_VIEW_MEMBERS.Id, model.SYSTEM_USER_ROLE_ID)
}
_, resp := th.Client.GetUserByUsername(tc.Username, "")
require.Nil(t, err)
if tc.ExpectedError != "" {
CheckErrorMessage(t, resp, tc.ExpectedError)
} else {
CheckNoError(t, resp)
}
})
}
})
t.Run("getUserByEmail", func(t *testing.T) {
testCases := []struct {
Name string
RestrictedTo string
Email string
ExpectedError string
}{
{
"Get visible user without restrictions",
"",
user5.Email,
"",
},
{
"Get not existing user without restrictions",
"",
th.GenerateTestEmail(),
"store.sql_user.missing_account.const",
},
{
"Get not existing user with restrictions to teams",
"teams",
th.GenerateTestEmail(),
"api.context.permissions.app_error",
},
{
"Get visible user with restrictions to teams",
"teams",
user2.Email,
"",
},
{
"Get not visible user with restrictions to teams",
"teams",
user5.Email,
"api.context.permissions.app_error",
},
{
"Get not existing user with restrictions to channels",
"channels",
th.GenerateTestEmail(),
"api.context.permissions.app_error",
},
{
"Get visible user with restrictions to channels",
"channels",
user4.Email,
"",
},
{
"Get not visible user with restrictions to channels",
"channels",
user3.Email,
"api.context.permissions.app_error",
},
}
defer th.RestoreDefaultRolePermissions(th.SaveDefaultRolePermissions())
for _, tc := range testCases {
t.Run(tc.Name, func(t *testing.T) {
if tc.RestrictedTo == "channels" {
th.RemovePermissionFromRole(model.PERMISSION_VIEW_MEMBERS.Id, model.SYSTEM_USER_ROLE_ID)
th.RemovePermissionFromRole(model.PERMISSION_VIEW_MEMBERS.Id, model.TEAM_USER_ROLE_ID)
} else if tc.RestrictedTo == "teams" {
th.RemovePermissionFromRole(model.PERMISSION_VIEW_MEMBERS.Id, model.SYSTEM_USER_ROLE_ID)
th.AddPermissionToRole(model.PERMISSION_VIEW_MEMBERS.Id, model.TEAM_USER_ROLE_ID)
} else {
th.RemovePermissionFromRole(model.PERMISSION_VIEW_MEMBERS.Id, model.TEAM_USER_ROLE_ID)
th.AddPermissionToRole(model.PERMISSION_VIEW_MEMBERS.Id, model.SYSTEM_USER_ROLE_ID)
}
_, resp := th.Client.GetUserByEmail(tc.Email, "")
require.Nil(t, err)
if tc.ExpectedError != "" {
CheckErrorMessage(t, resp, tc.ExpectedError)
} else {
CheckNoError(t, resp)
}
})
}
})
t.Run("getDefaultProfileImage", func(t *testing.T) {
testCases := []struct {
Name string
RestrictedTo string
UserId string
ExpectedError string
}{
{
"Get visible user without restrictions",
"",
user5.Id,
"",
},
{
"Get not existing user without restrictions",
"",
model.NewId(),
"store.sql_user.missing_account.const",
},
{
"Get not existing user with restrictions to teams",
"teams",
model.NewId(),
"api.context.permissions.app_error",
},
{
"Get visible user with restrictions to teams",
"teams",
user2.Id,
"",
},
{
"Get not visible user with restrictions to teams",
"teams",
user5.Id,
"api.context.permissions.app_error",
},
{
"Get not existing user with restrictions to channels",
"channels",
model.NewId(),
"api.context.permissions.app_error",
},
{
"Get visible user with restrictions to channels",
"channels",
user4.Id,
"",
},
{
"Get not visible user with restrictions to channels",
"channels",
user3.Id,
"api.context.permissions.app_error",
},
}
defer th.RestoreDefaultRolePermissions(th.SaveDefaultRolePermissions())
for _, tc := range testCases {
t.Run(tc.Name, func(t *testing.T) {
if tc.RestrictedTo == "channels" {
th.RemovePermissionFromRole(model.PERMISSION_VIEW_MEMBERS.Id, model.SYSTEM_USER_ROLE_ID)
th.RemovePermissionFromRole(model.PERMISSION_VIEW_MEMBERS.Id, model.TEAM_USER_ROLE_ID)
} else if tc.RestrictedTo == "teams" {
th.RemovePermissionFromRole(model.PERMISSION_VIEW_MEMBERS.Id, model.SYSTEM_USER_ROLE_ID)
th.AddPermissionToRole(model.PERMISSION_VIEW_MEMBERS.Id, model.TEAM_USER_ROLE_ID)
} else {
th.RemovePermissionFromRole(model.PERMISSION_VIEW_MEMBERS.Id, model.TEAM_USER_ROLE_ID)
th.AddPermissionToRole(model.PERMISSION_VIEW_MEMBERS.Id, model.SYSTEM_USER_ROLE_ID)
}
_, resp := th.Client.GetDefaultProfileImage(tc.UserId)
require.Nil(t, err)
if tc.ExpectedError != "" {
CheckErrorMessage(t, resp, tc.ExpectedError)
} else {
CheckNoError(t, resp)
}
})
}
})
t.Run("getProfileImage", func(t *testing.T) {
testCases := []struct {
Name string
RestrictedTo string
UserId string
ExpectedError string
}{
{
"Get visible user without restrictions",
"",
user5.Id,
"",
},
{
"Get not existing user without restrictions",
"",
model.NewId(),
"store.sql_user.missing_account.const",
},
{
"Get not existing user with restrictions to teams",
"teams",
model.NewId(),
"api.context.permissions.app_error",
},
{
"Get visible user with restrictions to teams",
"teams",
user2.Id,
"",
},
{
"Get not visible user with restrictions to teams",
"teams",
user5.Id,
"api.context.permissions.app_error",
},
{
"Get not existing user with restrictions to channels",
"channels",
model.NewId(),
"api.context.permissions.app_error",
},
{
"Get visible user with restrictions to channels",
"channels",
user4.Id,
"",
},
{
"Get not visible user with restrictions to channels",
"channels",
user3.Id,
"api.context.permissions.app_error",
},
}
defer th.RestoreDefaultRolePermissions(th.SaveDefaultRolePermissions())
for _, tc := range testCases {
t.Run(tc.Name, func(t *testing.T) {
if tc.RestrictedTo == "channels" {
th.RemovePermissionFromRole(model.PERMISSION_VIEW_MEMBERS.Id, model.SYSTEM_USER_ROLE_ID)
th.RemovePermissionFromRole(model.PERMISSION_VIEW_MEMBERS.Id, model.TEAM_USER_ROLE_ID)
} else if tc.RestrictedTo == "teams" {
th.RemovePermissionFromRole(model.PERMISSION_VIEW_MEMBERS.Id, model.SYSTEM_USER_ROLE_ID)
th.AddPermissionToRole(model.PERMISSION_VIEW_MEMBERS.Id, model.TEAM_USER_ROLE_ID)
} else {
th.RemovePermissionFromRole(model.PERMISSION_VIEW_MEMBERS.Id, model.TEAM_USER_ROLE_ID)
th.AddPermissionToRole(model.PERMISSION_VIEW_MEMBERS.Id, model.SYSTEM_USER_ROLE_ID)
}
_, resp := th.Client.GetProfileImage(tc.UserId, "")
require.Nil(t, err)
if tc.ExpectedError != "" {
CheckErrorMessage(t, resp, tc.ExpectedError)
} else {
CheckNoError(t, resp)
}
})
}
})
}

Просмотреть файл

@@ -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)

Просмотреть файл

@@ -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)
}

Просмотреть файл

@@ -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
}

Просмотреть файл

@@ -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 Обычный файл

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@@ -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)

Просмотреть файл

@@ -19,8 +19,8 @@ type ElasticsearchInterface interface {
SearchChannels(teamId, term string) ([]string, *model.AppError)
DeleteChannel(channel *model.Channel) *model.AppError
IndexUser(user *model.User, teamsIds, channelsIds []string) *model.AppError
SearchUsersInChannel(teamId, channelId, term string, options *model.UserSearchOptions) ([]string, []string, *model.AppError)
SearchUsersInTeam(teamId, term string, options *model.UserSearchOptions) ([]string, *model.AppError)
SearchUsersInChannel(teamId, channelId string, restrictedToChannels []string, term string, options *model.UserSearchOptions) ([]string, []string, *model.AppError)
SearchUsersInTeam(teamId string, restrictedToChannels []string, term string, options *model.UserSearchOptions) ([]string, *model.AppError)
DeleteUser(user *model.User) *model.AppError
TestConfig(cfg *model.Config) *model.AppError
PurgeIndexes() *model.AppError

Просмотреть файл

@@ -2298,10 +2298,6 @@
"id": "api.user.get_authorization_code.unsupported.app_error",
"translation": "Unsupported OAuth service provider"
},
{
"id": "api.user.get_profile_image.not_found.app_error",
"translation": "Unable to get profile image, user not found."
},
{
"id": "api.user.get_user_by_email.permissions.app_error",
"translation": "Unable to get user by email."
@@ -5586,6 +5582,10 @@
"id": "store.sql_channel.update_member.app_error",
"translation": "We encountered an error updating the channel member"
},
{
"id": "store.sql_channel.user_belongs_to_channels.app_error",
"translation": "Unable to determine if the user belongs to a list of channels"
},
{
"id": "store.sql_channel_member_history.get_users_in_channel_during.app_error",
"translation": "Failed to get users in channel during specified time period"
@@ -6450,6 +6450,10 @@
"id": "store.sql_team.get_unread.app_error",
"translation": "Unable to get the teams unread messages"
},
{
"id": "store.sql_team.get_user_team_ids.app_error",
"translation": "Unable to get the list of teams of a user"
},
{
"id": "store.sql_team.migrate_team_members.commit_transaction.app_error",
"translation": "Failed to commit the database transaction"
@@ -6534,6 +6538,10 @@
"id": "store.sql_team.update_last_team_icon_update.app_error",
"translation": "Unable to update the date of the last team icon update"
},
{
"id": "store.sql_team.user_belongs_to_teams.app_error",
"translation": "Unable to determine if the user belongs to a list of teams"
},
{
"id": "store.sql_terms_of_service.save.app_error",
"translation": "Unable to save terms of service."

Просмотреть файл

@@ -20,6 +20,7 @@ const (
CLUSTER_EVENT_INVALIDATE_CACHE_FOR_CHANNEL_BY_NAME = "inv_channel_name"
CLUSTER_EVENT_INVALIDATE_CACHE_FOR_CHANNEL = "inv_channel"
CLUSTER_EVENT_INVALIDATE_CACHE_FOR_USER = "inv_user"
CLUSTER_EVENT_INVALIDATE_CACHE_FOR_USER_TEAMS = "inv_user_teams"
CLUSTER_EVENT_CLEAR_SESSION_CACHE_FOR_USER = "clear_session_user"
CLUSTER_EVENT_INVALIDATE_CACHE_FOR_ROLES = "inv_roles"
CLUSTER_EVENT_INVALIDATE_CACHE_FOR_SCHEMES = "inv_schemes"

Просмотреть файл

@@ -85,6 +85,7 @@ var PERMISSION_READ_BOTS *Permission
var PERMISSION_READ_OTHERS_BOTS *Permission
var PERMISSION_MANAGE_BOTS *Permission
var PERMISSION_MANAGE_OTHERS_BOTS *Permission
var PERMISSION_VIEW_MEMBERS *Permission
// General permission that encompasses all system admin functions
// in the future this could be broken up to allow access to some
@@ -519,6 +520,12 @@ func initializePermissions() {
"authentication.permisssions.manage_jobs.description",
PERMISSION_SCOPE_SYSTEM,
}
PERMISSION_VIEW_MEMBERS = &Permission{
"view_members",
"authentication.permisssions.view_members.name",
"authentication.permisssions.view_members.description",
PERMISSION_SCOPE_TEAM,
}
ALL_PERMISSIONS = []*Permission{
PERMISSION_INVITE_USER,
@@ -591,6 +598,7 @@ func initializePermissions() {
PERMISSION_MANAGE_BOTS,
PERMISSION_MANAGE_OTHERS_BOTS,
PERMISSION_MANAGE_SYSTEM,
PERMISSION_VIEW_MEMBERS,
}
}

Просмотреть файл

@@ -268,6 +268,7 @@ func MakeDefaultRoles() map[string]*Role {
PERMISSION_JOIN_PUBLIC_TEAMS.Id,
PERMISSION_CREATE_DIRECT_CHANNEL.Id,
PERMISSION_CREATE_GROUP_CHANNEL.Id,
PERMISSION_VIEW_MEMBERS.Id,
},
SchemeManaged: true,
BuiltIn: true,
@@ -357,6 +358,7 @@ func MakeDefaultRoles() map[string]*Role {
PERMISSION_REMOVE_OTHERS_REACTIONS.Id,
PERMISSION_LIST_PRIVATE_TEAMS.Id,
PERMISSION_JOIN_PRIVATE_TEAMS.Id,
PERMISSION_VIEW_MEMBERS.Id,
},
roles[TEAM_USER_ROLE_ID].Permissions...,
),

Просмотреть файл

@@ -4,6 +4,7 @@
package model
import (
"crypto/sha256"
"encoding/json"
"fmt"
"io"
@@ -118,6 +119,22 @@ type UserForIndexing struct {
ChannelsIds []string `json:"channel_id"`
}
type ViewUsersRestrictions struct {
Teams []string
Channels []string
}
func (r *ViewUsersRestrictions) Hash() string {
if r == nil {
return ""
}
ids := append(r.Teams, r.Channels...)
sort.Strings(ids)
hash := sha256.New()
hash.Write([]byte(strings.Join(ids, "")))
return fmt.Sprintf("%x", hash.Sum(nil))
}
type UserSlice []*User
func (u UserSlice) Usernames() []string {

Просмотреть файл

@@ -13,4 +13,6 @@ type UserCountOptions struct {
ExcludeRegularUsers bool
// Only include users on a specific team. "" for any team.
TeamId string
// Restrict to search in a list of teams and channels
ViewRestrictions *ViewUsersRestrictions
}

Просмотреть файл

@@ -20,6 +20,8 @@ type UserGetOptions struct {
Role string
// Sorting option
Sort string
// Restrict to search in a list of teams and channels
ViewRestrictions *ViewUsersRestrictions
// Page
Page int
// Page size

Просмотреть файл

@@ -57,4 +57,6 @@ type UserSearchOptions struct {
Limit int
// Filters for the given role
Role string
// Restrict to search in a list of teams and channels
ViewRestrictions *ViewUsersRestrictions
}

Просмотреть файл

@@ -2604,3 +2604,27 @@ func (s SqlChannelStore) GetChannelsBatchForIndexing(startTime, endTime int64, l
result.Data = channels
})
}
func (s SqlChannelStore) UserBelongsToChannels(userId string, channelIds []string) store.StoreChannel {
return store.Do(func(result *store.StoreResult) {
query := s.getQueryBuilder().
Select("Count(*)").
From("ChannelMembers").
Where(sq.And{
sq.Eq{"UserId": userId},
sq.Eq{"ChannelId": channelIds},
})
queryString, args, err := query.ToSql()
if err != nil {
result.Err = model.NewAppError("SqlChannelStore.UserBelongsToChannels", "store.sql_channel.user_belongs_to_channels.app_error", nil, err.Error(), http.StatusInternalServerError)
return
}
c, err := s.GetReplica().SelectInt(queryString, args...)
if err != nil {
result.Err = model.NewAppError("SqlChannelStore.UserBelongsToChannels", "store.sql_channel.user_belongs_to_channels.app_error", nil, err.Error(), http.StatusInternalServerError)
return
}
result.Data = c > 0
})
}

Просмотреть файл

@@ -124,7 +124,7 @@ func NewSqlSupplier(settings model.SqlSettings, metrics einterfaces.MetricsInter
supplier.initConnection()
supplier.oldStores.team = NewSqlTeamStore(supplier)
supplier.oldStores.team = NewSqlTeamStore(supplier, metrics)
supplier.oldStores.channel = NewSqlChannelStore(supplier, metrics)
supplier.oldStores.post = NewSqlPostStore(supplier, metrics)
supplier.oldStores.user = NewSqlUserStore(supplier, metrics)

Просмотреть файл

@@ -5,21 +5,28 @@ package sqlstore
import (
"database/sql"
"fmt"
"net/http"
"strconv"
"strings"
sq "github.com/Masterminds/squirrel"
"github.com/mattermost/gorp"
"github.com/mattermost/mattermost-server/einterfaces"
"github.com/mattermost/mattermost-server/model"
"github.com/mattermost/mattermost-server/store"
"github.com/mattermost/mattermost-server/utils"
)
const (
TEAM_MEMBER_EXISTS_ERROR = "store.sql_team.save_member.exists.app_error"
TEAM_MEMBER_EXISTS_ERROR = "store.sql_team.save_member.exists.app_error"
ALL_TEAM_IDS_FOR_USER_CACHE_SIZE = model.SESSION_CACHE_SIZE
ALL_TEAM_IDS_FOR_USER_CACHE_SEC = 1800 // 30 mins
)
type SqlTeamStore struct {
SqlStore
metrics einterfaces.MetricsInterface
}
type teamMember struct {
@@ -132,8 +139,11 @@ func (db teamMemberWithSchemeRolesList) ToModel() []*model.TeamMember {
return tms
}
func NewSqlTeamStore(sqlStore SqlStore) store.TeamStore {
s := &SqlTeamStore{sqlStore}
func NewSqlTeamStore(sqlStore SqlStore, metrics einterfaces.MetricsInterface) store.TeamStore {
s := &SqlTeamStore{
sqlStore,
metrics,
}
for _, db := range sqlStore.GetAllConns() {
table := db.AddTableWithName(model.Team{}, "Teams").SetKeys(false, "Id")
@@ -224,6 +234,11 @@ func (s SqlTeamStore) Update(team *model.Team) (*model.Team, *model.AppError) {
return nil, model.NewAppError("SqlTeamStore.Update", "store.sql_team.update.app_error", nil, "id="+team.Id, http.StatusInternalServerError)
}
if oldTeam.DeleteAt == 0 && team.DeleteAt != 0 {
// Invalidate this cache after any team deletion
allTeamIdsForUserCache.Purge()
}
return team, nil
}
@@ -461,21 +476,21 @@ func (s SqlTeamStore) AnalyticsTeamCount() store.StoreChannel {
})
}
var TEAM_MEMBERS_WITH_SCHEME_SELECT_QUERY = `
SELECT
TeamMembers.*,
TeamScheme.DefaultTeamUserRole TeamSchemeDefaultUserRole,
TeamScheme.DefaultTeamAdminRole TeamSchemeDefaultAdminRole
FROM
TeamMembers
LEFT JOIN
Teams ON TeamMembers.TeamId = Teams.Id
LEFT JOIN
Schemes TeamScheme ON Teams.SchemeId = TeamScheme.Id
`
func (s SqlTeamStore) getTeamMembersWithSchemeSelectQuery() sq.SelectBuilder {
return s.getQueryBuilder().
Select(
"TeamMembers.*",
"TeamScheme.DefaultTeamUserRole TeamSchemeDefaultUserRole",
"TeamScheme.DefaultTeamAdminRole TeamSchemeDefaultAdminRole",
).
From("TeamMembers").
LeftJoin("Teams ON TeamMembers.TeamId = Teams.Id").
LeftJoin("Schemes TeamScheme ON Teams.SchemeId = TeamScheme.Id")
}
func (s SqlTeamStore) SaveMember(member *model.TeamMember, maxUsersPerTeam int) store.StoreChannel {
return store.Do(func(result *store.StoreResult) {
defer s.InvalidateAllTeamIdsForUser(member.UserId)
if result.Err = member.IsValid(); result.Err != nil {
return
}
@@ -517,8 +532,18 @@ func (s SqlTeamStore) SaveMember(member *model.TeamMember, maxUsersPerTeam int)
return
}
query := s.getTeamMembersWithSchemeSelectQuery().
Where(sq.Eq{"TeamMembers.TeamId": dbMember.TeamId}).
Where(sq.Eq{"TeamMembers.UserId": dbMember.UserId})
queryString, args, err := query.ToSql()
if err != nil {
result.Err = model.NewAppError("SqlTeamStore.SaveMember", "store.sql_team.get_member.app_error", nil, err.Error(), http.StatusInternalServerError)
return
}
var retrievedMember teamMemberWithSchemeRoles
if err := s.GetMaster().SelectOne(&retrievedMember, TEAM_MEMBERS_WITH_SCHEME_SELECT_QUERY+"WHERE TeamMembers.TeamId = :TeamId AND TeamMembers.UserId = :UserId", map[string]interface{}{"TeamId": dbMember.TeamId, "UserId": dbMember.UserId}); err != nil {
if err := s.GetMaster().SelectOne(&retrievedMember, queryString, args...); err != nil {
if err == sql.ErrNoRows {
result.Err = model.NewAppError("SqlTeamStore.SaveMember", "store.sql_team.get_member.missing.app_error", nil, "team_id="+dbMember.TeamId+"user_id="+dbMember.UserId+","+err.Error(), http.StatusNotFound)
return
@@ -543,8 +568,18 @@ func (s SqlTeamStore) UpdateMember(member *model.TeamMember) store.StoreChannel
return
}
query := s.getTeamMembersWithSchemeSelectQuery().
Where(sq.Eq{"TeamMembers.TeamId": member.TeamId}).
Where(sq.Eq{"TeamMembers.UserId": member.UserId})
queryString, args, err := query.ToSql()
if err != nil {
result.Err = model.NewAppError("SqlTeamStore.UpdateMember", "store.sql_team.get_member.app_error", nil, err.Error(), http.StatusInternalServerError)
return
}
var retrievedMember teamMemberWithSchemeRoles
if err := s.GetMaster().SelectOne(&retrievedMember, TEAM_MEMBERS_WITH_SCHEME_SELECT_QUERY+"WHERE TeamMembers.TeamId = :TeamId AND TeamMembers.UserId = :UserId", map[string]interface{}{"TeamId": member.TeamId, "UserId": member.UserId}); err != nil {
if err := s.GetMaster().SelectOne(&retrievedMember, queryString, args...); err != nil {
if err == sql.ErrNoRows {
result.Err = model.NewAppError("SqlTeamStore.UpdateMember", "store.sql_team.get_member.missing.app_error", nil, "team_id="+member.TeamId+"user_id="+member.UserId+","+err.Error(), http.StatusNotFound)
return
@@ -559,8 +594,18 @@ func (s SqlTeamStore) UpdateMember(member *model.TeamMember) store.StoreChannel
func (s SqlTeamStore) GetMember(teamId string, userId string) store.StoreChannel {
return store.Do(func(result *store.StoreResult) {
query := s.getTeamMembersWithSchemeSelectQuery().
Where(sq.Eq{"TeamMembers.TeamId": teamId}).
Where(sq.Eq{"TeamMembers.UserId": userId})
queryString, args, err := query.ToSql()
if err != nil {
result.Err = model.NewAppError("SqlTeamStore.GetMember", "store.sql_team.get_member.app_error", nil, err.Error(), http.StatusInternalServerError)
return
}
var dbMember teamMemberWithSchemeRoles
err := s.GetReplica().SelectOne(&dbMember, TEAM_MEMBERS_WITH_SCHEME_SELECT_QUERY+"WHERE TeamMembers.TeamId = :TeamId AND TeamMembers.UserId = :UserId", map[string]interface{}{"TeamId": teamId, "UserId": userId})
err = s.GetReplica().SelectOne(&dbMember, queryString, args...)
if err != nil {
if err == sql.ErrNoRows {
result.Err = model.NewAppError("SqlTeamStore.GetMember", "store.sql_team.get_member.missing.app_error", nil, "teamId="+teamId+" userId="+userId+" "+err.Error(), http.StatusNotFound)
@@ -573,10 +618,24 @@ func (s SqlTeamStore) GetMember(teamId string, userId string) store.StoreChannel
})
}
func (s SqlTeamStore) GetMembers(teamId string, offset int, limit int) store.StoreChannel {
func (s SqlTeamStore) GetMembers(teamId string, offset int, limit int, restrictions *model.ViewUsersRestrictions) store.StoreChannel {
return store.Do(func(result *store.StoreResult) {
query := s.getTeamMembersWithSchemeSelectQuery().
Where(sq.Eq{"TeamMembers.TeamId": teamId}).
Where(sq.Eq{"TeamMembers.DeleteAt": 0}).
Limit(uint64(limit)).
Offset(uint64(offset))
query = applyTeamMemberViewRestrictionsFilter(query, teamId, restrictions)
queryString, args, err := query.ToSql()
if err != nil {
result.Err = model.NewAppError("SqlTeamStore.GetMembers", "store.sql_team.get_members.app_error", nil, err.Error(), http.StatusInternalServerError)
return
}
var dbMembers teamMemberWithSchemeRolesList
_, err := s.GetReplica().Select(&dbMembers, TEAM_MEMBERS_WITH_SCHEME_SELECT_QUERY+"WHERE TeamMembers.TeamId = :TeamId AND TeamMembers.DeleteAt = 0 LIMIT :Limit OFFSET :Offset", map[string]interface{}{"TeamId": teamId, "Limit": limit, "Offset": offset})
_, err = s.GetReplica().Select(&dbMembers, queryString, args...)
if err != nil {
result.Err = model.NewAppError("SqlTeamStore.GetMembers", "store.sql_team.get_members.app_error", nil, "teamId="+teamId+" "+err.Error(), http.StatusInternalServerError)
return
@@ -629,24 +688,27 @@ func (s SqlTeamStore) GetActiveMemberCount(teamId string) store.StoreChannel {
})
}
func (s SqlTeamStore) GetMembersByIds(teamId string, userIds []string) store.StoreChannel {
func (s SqlTeamStore) GetMembersByIds(teamId string, userIds []string, restrictions *model.ViewUsersRestrictions) store.StoreChannel {
return store.Do(func(result *store.StoreResult) {
var dbMembers teamMemberWithSchemeRolesList
props := make(map[string]interface{})
idQuery := ""
for index, userId := range userIds {
if len(idQuery) > 0 {
idQuery += ", "
}
props["userId"+strconv.Itoa(index)] = userId
idQuery += ":userId" + strconv.Itoa(index)
if len(userIds) == 0 {
result.Err = model.NewAppError("SqlTeamStore.GetMembersByIds", "store.sql_team.get_members_by_ids.app_error", nil, "Invalid list of user ids", http.StatusInternalServerError)
}
props["TeamId"] = teamId
query := s.getTeamMembersWithSchemeSelectQuery().
Where(sq.Eq{"TeamMembers.TeamId": teamId}).
Where(sq.Eq{"TeamMembers.UserId": userIds}).
Where(sq.Eq{"TeamMembers.DeleteAt": 0})
if _, err := s.GetReplica().Select(&dbMembers, TEAM_MEMBERS_WITH_SCHEME_SELECT_QUERY+"WHERE TeamMembers.TeamId = :TeamId AND TeamMembers.UserId IN ("+idQuery+") AND TeamMembers.DeleteAt = 0", props); err != nil {
query = applyTeamMemberViewRestrictionsFilter(query, teamId, restrictions)
queryString, args, err := query.ToSql()
if err != nil {
result.Err = model.NewAppError("SqlTeamStore.GetMembersByIds", "store.sql_team.get_members_by_ids.app_error", nil, err.Error(), http.StatusInternalServerError)
return
}
var dbMembers teamMemberWithSchemeRolesList
if _, err := s.GetReplica().Select(&dbMembers, queryString, args...); err != nil {
result.Err = model.NewAppError("SqlTeamStore.GetMembersByIds", "store.sql_team.get_members_by_ids.app_error", nil, "teamId="+teamId+" "+err.Error(), http.StatusInternalServerError)
return
}
@@ -656,8 +718,17 @@ func (s SqlTeamStore) GetMembersByIds(teamId string, userIds []string) store.Sto
func (s SqlTeamStore) GetTeamsForUser(userId string) store.StoreChannel {
return store.Do(func(result *store.StoreResult) {
query := s.getTeamMembersWithSchemeSelectQuery().
Where(sq.Eq{"TeamMembers.UserId": userId})
queryString, args, err := query.ToSql()
if err != nil {
result.Err = model.NewAppError("SqlTeamStore.GetMembers", "store.sql_team.get_members.app_error", nil, err.Error(), http.StatusInternalServerError)
return
}
var dbMembers teamMemberWithSchemeRolesList
_, err := s.GetReplica().Select(&dbMembers, TEAM_MEMBERS_WITH_SCHEME_SELECT_QUERY+"WHERE TeamMembers.UserId = :UserId", map[string]interface{}{"UserId": userId})
_, err = s.GetReplica().Select(&dbMembers, queryString, args...)
if err != nil {
result.Err = model.NewAppError("SqlTeamStore.GetMembers", "store.sql_team.get_members.app_error", nil, "userId="+userId+" "+err.Error(), http.StatusInternalServerError)
return
@@ -669,9 +740,19 @@ func (s SqlTeamStore) GetTeamsForUser(userId string) store.StoreChannel {
func (s SqlTeamStore) GetTeamsForUserWithPagination(userId string, page, perPage int) store.StoreChannel {
return store.Do(func(result *store.StoreResult) {
query := s.getTeamMembersWithSchemeSelectQuery().
Where(sq.Eq{"TeamMembers.UserId": userId}).
Limit(uint64(perPage)).
Offset(uint64(page * perPage))
queryString, args, err := query.ToSql()
if err != nil {
result.Err = model.NewAppError("SqlTeamStore.GetTeamsForUserWithPagination", "store.sql_team.get_members.app_error", nil, err.Error(), http.StatusInternalServerError)
return
}
var dbMembers teamMemberWithSchemeRolesList
offset := page * perPage
_, err := s.GetReplica().Select(&dbMembers, TEAM_MEMBERS_WITH_SCHEME_SELECT_QUERY+"WHERE TeamMembers.UserId = :UserId Limit :Limit Offset :Offset", map[string]interface{}{"UserId": userId, "Limit": perPage, "Offset": offset})
_, err = s.GetReplica().Select(&dbMembers, queryString, args...)
if err != nil {
result.Err = model.NewAppError("SqlTeamStore.GetTeamsForUserWithPagination", "store.sql_team.get_members.app_error", nil, "userId="+userId+" "+err.Error(), http.StatusInternalServerError)
return
@@ -731,7 +812,7 @@ func (s SqlTeamStore) RemoveMember(teamId string, userId string) store.StoreChan
return store.Do(func(result *store.StoreResult) {
_, err := s.GetMaster().Exec("DELETE FROM TeamMembers WHERE TeamId = :TeamId AND UserId = :UserId", map[string]interface{}{"TeamId": teamId, "UserId": userId})
if err != nil {
result.Err = model.NewAppError("SqlChannelStore.RemoveMember", "store.sql_team.remove_member.app_error", nil, "team_id="+teamId+", user_id="+userId+", "+err.Error(), http.StatusInternalServerError)
result.Err = model.NewAppError("SqlTeamStore.RemoveMember", "store.sql_team.remove_member.app_error", nil, "team_id="+teamId+", user_id="+userId+", "+err.Error(), http.StatusInternalServerError)
}
})
}
@@ -740,7 +821,7 @@ func (s SqlTeamStore) RemoveAllMembersByTeam(teamId string) store.StoreChannel {
return store.Do(func(result *store.StoreResult) {
_, err := s.GetMaster().Exec("DELETE FROM TeamMembers WHERE TeamId = :TeamId", map[string]interface{}{"TeamId": teamId})
if err != nil {
result.Err = model.NewAppError("SqlChannelStore.RemoveMember", "store.sql_team.remove_member.app_error", nil, "team_id="+teamId+", "+err.Error(), http.StatusInternalServerError)
result.Err = model.NewAppError("SqlTeamStore.RemoveMember", "store.sql_team.remove_member.app_error", nil, "team_id="+teamId+", "+err.Error(), http.StatusInternalServerError)
}
})
}
@@ -749,7 +830,7 @@ func (s SqlTeamStore) RemoveAllMembersByUser(userId string) store.StoreChannel {
return store.Do(func(result *store.StoreResult) {
_, err := s.GetMaster().Exec("DELETE FROM TeamMembers WHERE UserId = :UserId", map[string]interface{}{"UserId": userId})
if err != nil {
result.Err = model.NewAppError("SqlChannelStore.RemoveMember", "store.sql_team.remove_member.app_error", nil, "user_id="+userId+", "+err.Error(), http.StatusInternalServerError)
result.Err = model.NewAppError("SqlTeamStore.RemoveMember", "store.sql_team.remove_member.app_error", nil, "user_id="+userId+", "+err.Error(), http.StatusInternalServerError)
}
})
}
@@ -849,6 +930,22 @@ func (s SqlTeamStore) ResetAllTeamSchemes() store.StoreChannel {
})
}
var allTeamIdsForUserCache = utils.NewLru(ALL_TEAM_IDS_FOR_USER_CACHE_SIZE)
func (s SqlTeamStore) ClearCaches() {
allTeamIdsForUserCache.Purge()
if s.metrics != nil {
s.metrics.IncrementMemCacheInvalidationCounter("All Team Ids for User - Purge")
}
}
func (s SqlTeamStore) InvalidateAllTeamIdsForUser(userId string) {
allTeamIdsForUserCache.Remove(userId)
if s.metrics != nil {
s.metrics.IncrementMemCacheInvalidationCounter("All Team Ids for User - Remove by UserId")
}
}
func (s SqlTeamStore) ClearAllCustomRoleAssignments() store.StoreChannel {
return store.Do(func(result *store.StoreResult) {
builtInRoles := model.MakeDefaultRoles()
@@ -944,6 +1041,48 @@ func (s SqlTeamStore) GetAllForExportAfter(limit int, afterId string) store.Stor
})
}
func (s SqlTeamStore) GetUserTeamIds(userId string, allowFromCache bool) store.StoreChannel {
return store.Do(func(result *store.StoreResult) {
if allowFromCache {
if cacheItem, ok := allTeamIdsForUserCache.Get(userId); ok {
if s.metrics != nil {
s.metrics.IncrementMemCacheHitCounter("All Team Ids for User")
}
result.Data = cacheItem.([]string)
return
}
}
if s.metrics != nil {
s.metrics.IncrementMemCacheMissCounter("All Team Ids for User")
}
var teamIds []string
_, err := s.GetReplica().Select(&teamIds, `
SELECT
TeamId
FROM
TeamMembers
INNER JOIN
Teams ON TeamMembers.TeamId = Teams.Id
WHERE
TeamMembers.UserId = :UserId
AND TeamMembers.DeleteAt = 0
AND Teams.DeleteAt = 0`,
map[string]interface{}{"UserId": userId})
if err != nil {
result.Err = model.NewAppError("SqlTeamStore.GetUserTeamIds", "store.sql_team.get_user_team_ids.app_error", nil, "userId="+userId+" "+err.Error(), http.StatusInternalServerError)
return
}
result.Data = teamIds
if allowFromCache {
allTeamIdsForUserCache.AddWithExpiresInSecs(userId, teamIds, ALL_TEAM_IDS_FOR_USER_CACHE_SEC)
}
})
}
func (s SqlTeamStore) GetTeamMembersForExport(userId string) store.StoreChannel {
return store.Do(func(result *store.StoreResult) {
var members []*model.TeamMemberForExport
@@ -967,3 +1106,56 @@ func (s SqlTeamStore) GetTeamMembersForExport(userId string) store.StoreChannel
result.Data = members
})
}
func (s SqlTeamStore) UserBelongsToTeams(userId string, teamIds []string) store.StoreChannel {
return store.Do(func(result *store.StoreResult) {
props := make(map[string]interface{})
props["UserId"] = userId
idQuery := ""
for index, teamId := range teamIds {
if len(idQuery) > 0 {
idQuery += ", "
}
props["teamId"+strconv.Itoa(index)] = teamId
idQuery += ":teamId" + strconv.Itoa(index)
}
c, err := s.GetReplica().SelectInt("SELECT Count(*) FROM TeamMembers WHERE UserId = :UserId AND TeamId IN ("+idQuery+") AND DeleteAt = 0", props)
if err != nil {
result.Err = model.NewAppError("SqlTeamStore.UserBelongsToTeams", "store.sql_team.user_belongs_to_teams.app_error", nil, err.Error(), http.StatusInternalServerError)
return
}
result.Data = c > 0
})
}
func applyTeamMemberViewRestrictionsFilter(query sq.SelectBuilder, teamId string, restrictions *model.ViewUsersRestrictions) sq.SelectBuilder {
if restrictions == nil {
return query
}
// If you have no access to teams or channels, return and empty result.
if restrictions.Teams != nil && len(restrictions.Teams) == 0 && restrictions.Channels != nil && len(restrictions.Channels) == 0 {
return query.Where("1 = 0")
}
teams := make([]interface{}, len(restrictions.Teams))
for i, v := range restrictions.Teams {
teams[i] = v
}
channels := make([]interface{}, len(restrictions.Channels))
for i, v := range restrictions.Channels {
channels[i] = v
}
resultQuery := query.Join("Users ru ON (TeamMembers.UserId = ru.Id)")
if restrictions.Teams != nil && len(restrictions.Teams) > 0 {
resultQuery = resultQuery.Join(fmt.Sprintf("TeamMembers rtm ON ( rtm.UserId = ru.Id AND rtm.DeleteAt = 0 AND rtm.TeamId IN (%s))", sq.Placeholders(len(teams))), teams...)
}
if restrictions.Channels != nil && len(restrictions.Channels) > 0 {
resultQuery = resultQuery.Join(fmt.Sprintf("ChannelMembers rcm ON ( rcm.UserId = ru.Id AND rcm.ChannelId IN (%s))", sq.Placeholders(len(channels))), channels...)
}
return resultQuery.Distinct()
}

Просмотреть файл

@@ -407,6 +407,8 @@ func (us SqlUserStore) GetAllProfiles(options *model.UserGetOptions) store.Store
OrderBy("u.Username ASC").
Offset(uint64(options.Page * options.PerPage)).Limit(uint64(options.PerPage))
query = applyViewRestrictionsFilter(query, options.ViewRestrictions, true)
query = applyRoleFilter(query, options.Role, isPostgreSQL)
if options.Inactive {
@@ -466,6 +468,8 @@ func (us SqlUserStore) GetProfiles(options *model.UserGetOptions) store.StoreCha
OrderBy("u.Username ASC").
Offset(uint64(options.Page * options.PerPage)).Limit(uint64(options.PerPage))
query = applyViewRestrictionsFilter(query, options.ViewRestrictions, true)
query = applyRoleFilter(query, options.Role, isPostgreSQL)
if options.Inactive {
@@ -632,7 +636,7 @@ func (us SqlUserStore) GetAllProfilesInChannel(channelId string, allowFromCache
})
}
func (us SqlUserStore) GetProfilesNotInChannel(teamId string, channelId string, offset int, limit int) store.StoreChannel {
func (us SqlUserStore) GetProfilesNotInChannel(teamId string, channelId string, offset int, limit int, viewRestrictions *model.ViewUsersRestrictions) store.StoreChannel {
return store.Do(func(result *store.StoreResult) {
query := us.usersQuery.
Join("TeamMembers tm ON ( tm.UserId = u.Id AND tm.DeleteAt = 0 AND tm.TeamId = ? )", teamId).
@@ -641,6 +645,8 @@ func (us SqlUserStore) GetProfilesNotInChannel(teamId string, channelId string,
OrderBy("u.Username ASC").
Offset(uint64(offset)).Limit(uint64(limit))
query = applyViewRestrictionsFilter(query, viewRestrictions, true)
queryString, args, err := query.ToSql()
if err != nil {
result.Err = model.NewAppError("SqlUserStore.GetProfilesNotInChannel", "store.sql_user.app_error", nil, err.Error(), http.StatusInternalServerError)
@@ -661,7 +667,7 @@ func (us SqlUserStore) GetProfilesNotInChannel(teamId string, channelId string,
})
}
func (us SqlUserStore) GetProfilesWithoutTeam(offset int, limit int) store.StoreChannel {
func (us SqlUserStore) GetProfilesWithoutTeam(offset int, limit int, viewRestrictions *model.ViewUsersRestrictions) store.StoreChannel {
return store.Do(func(result *store.StoreResult) {
query := us.usersQuery.
Where(`(
@@ -676,6 +682,8 @@ func (us SqlUserStore) GetProfilesWithoutTeam(offset int, limit int) store.Store
OrderBy("u.Username ASC").
Offset(uint64(offset)).Limit(uint64(limit))
query = applyViewRestrictionsFilter(query, viewRestrictions, true)
queryString, args, err := query.ToSql()
if err != nil {
result.Err = model.NewAppError("SqlUserStore.GetProfilesWithoutTeam", "store.sql_user.app_error", nil, err.Error(), http.StatusInternalServerError)
@@ -696,13 +704,11 @@ func (us SqlUserStore) GetProfilesWithoutTeam(offset int, limit int) store.Store
})
}
func (us SqlUserStore) GetProfilesByUsernames(usernames []string, teamId string) store.StoreChannel {
func (us SqlUserStore) GetProfilesByUsernames(usernames []string, viewRestrictions *model.ViewUsersRestrictions) store.StoreChannel {
return store.Do(func(result *store.StoreResult) {
query := us.usersQuery
if teamId != "" {
query = query.Join("TeamMembers tm ON (tm.UserId = u.Id AND tm.TeamId = ?)", teamId)
}
query = applyViewRestrictionsFilter(query, viewRestrictions, true)
query = query.
Where(map[string]interface{}{
@@ -731,7 +737,7 @@ type UserWithLastActivityAt struct {
LastActivityAt int64
}
func (us SqlUserStore) GetRecentlyActiveUsersForTeam(teamId string, offset, limit int) store.StoreChannel {
func (us SqlUserStore) GetRecentlyActiveUsersForTeam(teamId string, offset, limit int, viewRestrictions *model.ViewUsersRestrictions) store.StoreChannel {
return store.Do(func(result *store.StoreResult) {
query := us.usersQuery.
Column("s.LastActivityAt").
@@ -741,6 +747,8 @@ func (us SqlUserStore) GetRecentlyActiveUsersForTeam(teamId string, offset, limi
OrderBy("u.Username ASC").
Offset(uint64(offset)).Limit(uint64(limit))
query = applyViewRestrictionsFilter(query, viewRestrictions, true)
queryString, args, err := query.ToSql()
if err != nil {
result.Err = model.NewAppError("SqlUserStore.GetRecentlyActiveUsers", "store.sql_user.app_error", nil, err.Error(), http.StatusInternalServerError)
@@ -766,7 +774,7 @@ func (us SqlUserStore) GetRecentlyActiveUsersForTeam(teamId string, offset, limi
})
}
func (us SqlUserStore) GetNewUsersForTeam(teamId string, offset, limit int) store.StoreChannel {
func (us SqlUserStore) GetNewUsersForTeam(teamId string, offset, limit int, viewRestrictions *model.ViewUsersRestrictions) store.StoreChannel {
return store.Do(func(result *store.StoreResult) {
query := us.usersQuery.
Join("TeamMembers tm ON (tm.UserId = u.Id AND tm.TeamId = ?)", teamId).
@@ -774,6 +782,8 @@ func (us SqlUserStore) GetNewUsersForTeam(teamId string, offset, limit int) stor
OrderBy("u.Username ASC").
Offset(uint64(offset)).Limit(uint64(limit))
query = applyViewRestrictionsFilter(query, viewRestrictions, true)
queryString, args, err := query.ToSql()
if err != nil {
result.Err = model.NewAppError("SqlUserStore.GetNewUsersForTeam", "store.sql_user.app_error", nil, err.Error(), http.StatusInternalServerError)
@@ -794,7 +804,7 @@ func (us SqlUserStore) GetNewUsersForTeam(teamId string, offset, limit int) stor
})
}
func (us SqlUserStore) GetProfileByIds(userIds []string, allowFromCache bool) store.StoreChannel {
func (us SqlUserStore) GetProfileByIds(userIds []string, allowFromCache bool, viewRestrictions *model.ViewUsersRestrictions) store.StoreChannel {
return store.Do(func(result *store.StoreResult) {
users := []*model.User{}
remainingUserIds := make([]string, 0)
@@ -832,6 +842,8 @@ func (us SqlUserStore) GetProfileByIds(userIds []string, allowFromCache bool) st
}).
OrderBy("u.Username ASC")
query = applyViewRestrictionsFilter(query, viewRestrictions, true)
queryString, args, err := query.ToSql()
if err != nil {
result.Err = model.NewAppError("SqlUserStore.GetProfileByIds", "store.sql_user.app_error", nil, err.Error(), http.StatusInternalServerError)
@@ -1039,18 +1051,18 @@ func (us SqlUserStore) PermanentDelete(userId string) store.StoreChannel {
func (us SqlUserStore) Count(options model.UserCountOptions) store.StoreChannel {
return store.Do(func(result *store.StoreResult) {
query := sq.Select("COUNT(Users.Id)").From("Users")
query := sq.Select("COUNT(DISTINCT u.Id)").From("Users AS u")
if !options.IncludeDeleted {
query = query.Where("Users.DeleteAt = 0")
query = query.Where("u.DeleteAt = 0")
}
if options.IncludeBotAccounts {
if options.ExcludeRegularUsers {
query = query.Join("Bots ON Users.Id = Bots.UserId")
query = query.Join("Bots ON u.Id = Bots.UserId")
}
} else {
query = query.LeftJoin("Bots ON Users.Id = Bots.UserId").Where("Bots.UserId IS NULL")
query = query.LeftJoin("Bots ON u.Id = Bots.UserId").Where("Bots.UserId IS NULL")
if options.ExcludeRegularUsers {
// Currenty this doesn't make sense because it will always return 0
result.Err = model.NewAppError("SqlUserStore.Count", "store.sql_user.count.app_error", nil, "", http.StatusInternalServerError)
@@ -1059,8 +1071,9 @@ func (us SqlUserStore) Count(options model.UserCountOptions) store.StoreChannel
}
if options.TeamId != "" {
query = query.LeftJoin("TeamMembers ON Users.Id = TeamMembers.UserId").Where("TeamMembers.TeamId = ? AND TeamMembers.DeleteAt = 0", options.TeamId)
query = query.LeftJoin("TeamMembers AS tm ON u.Id = tm.UserId").Where("tm.TeamId = ? AND tm.DeleteAt = 0", options.TeamId)
}
query = applyViewRestrictionsFilter(query, options.ViewRestrictions, false)
if us.DriverName() == model.DATABASE_DRIVER_POSTGRES {
query = query.PlaceholderFormat(sq.Dollar)
@@ -1285,6 +1298,8 @@ func (us SqlUserStore) performSearch(query sq.SelectBuilder, term string, option
query = generateSearchQuery(query, strings.Fields(term), searchType, isPostgreSQL)
}
query = applyViewRestrictionsFilter(query, options.ViewRestrictions, true)
queryString, args, err := query.ToSql()
if err != nil {
result.Err = model.NewAppError("SqlUserStore.Search", "store.sql_user.app_error", nil, err.Error(), http.StatusInternalServerError)
@@ -1326,7 +1341,7 @@ func (us SqlUserStore) AnalyticsGetSystemAdminCount() store.StoreChannel {
})
}
func (us SqlUserStore) GetProfilesNotInTeam(teamId string, offset int, limit int) store.StoreChannel {
func (us SqlUserStore) GetProfilesNotInTeam(teamId string, offset int, limit int, viewRestrictions *model.ViewUsersRestrictions) store.StoreChannel {
return store.Do(func(result *store.StoreResult) {
query := us.usersQuery.
LeftJoin("TeamMembers tm ON ( tm.UserId = u.Id AND tm.DeleteAt = 0 AND tm.TeamId = ? )", teamId).
@@ -1334,6 +1349,8 @@ func (us SqlUserStore) GetProfilesNotInTeam(teamId string, offset int, limit int
OrderBy("u.Username ASC").
Offset(uint64(offset)).Limit(uint64(limit))
query = applyViewRestrictionsFilter(query, viewRestrictions, true)
queryString, args, err := query.ToSql()
if err != nil {
result.Err = model.NewAppError("SqlUserStore.GetProfilesNotInTeam", "store.sql_user.app_error", nil, err.Error(), http.StatusInternalServerError)
@@ -1611,3 +1628,36 @@ func (us SqlUserStore) GetChannelGroupUsers(channelID string) store.StoreChannel
result.Data = users
})
}
func applyViewRestrictionsFilter(query sq.SelectBuilder, restrictions *model.ViewUsersRestrictions, distinct bool) sq.SelectBuilder {
if restrictions == nil {
return query
}
// If you have no access to teams or channels, return and empty result.
if restrictions.Teams != nil && len(restrictions.Teams) == 0 && restrictions.Channels != nil && len(restrictions.Channels) == 0 {
return query.Where("1 = 0")
}
teams := make([]interface{}, len(restrictions.Teams))
for i, v := range restrictions.Teams {
teams[i] = v
}
channels := make([]interface{}, len(restrictions.Channels))
for i, v := range restrictions.Channels {
channels[i] = v
}
resultQuery := query
if restrictions.Teams != nil && len(restrictions.Teams) > 0 {
resultQuery = resultQuery.Join(fmt.Sprintf("TeamMembers rtm ON ( rtm.UserId = u.Id AND rtm.DeleteAt = 0 AND rtm.TeamId IN (%s))", sq.Placeholders(len(teams))), teams...)
}
if restrictions.Channels != nil && len(restrictions.Channels) > 0 {
resultQuery = resultQuery.Join(fmt.Sprintf("ChannelMembers rcm ON ( rcm.UserId = u.Id AND rcm.ChannelId IN (%s))", sq.Placeholders(len(channels))), channels...)
}
if distinct {
return resultQuery.Distinct()
}
return resultQuery
}

Просмотреть файл

@@ -103,8 +103,8 @@ type TeamStore interface {
SaveMember(member *model.TeamMember, maxUsersPerTeam int) StoreChannel
UpdateMember(member *model.TeamMember) StoreChannel
GetMember(teamId string, userId string) StoreChannel
GetMembers(teamId string, offset int, limit int) StoreChannel
GetMembersByIds(teamId string, userIds []string) StoreChannel
GetMembers(teamId string, offset int, limit int, restrictions *model.ViewUsersRestrictions) StoreChannel
GetMembersByIds(teamId string, userIds []string, restrictions *model.ViewUsersRestrictions) StoreChannel
GetTotalMemberCount(teamId string) StoreChannel
GetActiveMemberCount(teamId string) StoreChannel
GetTeamsForUser(userId string) StoreChannel
@@ -122,6 +122,10 @@ type TeamStore interface {
AnalyticsGetTeamCountForScheme(schemeId string) StoreChannel
GetAllForExportAfter(limit int, afterId string) StoreChannel
GetTeamMembersForExport(userId string) StoreChannel
UserBelongsToTeams(userId string, teamIds []string) StoreChannel
GetUserTeamIds(userId string, allowFromCache bool) StoreChannel
InvalidateAllTeamIdsForUser(userId string)
ClearCaches()
}
type ChannelStore interface {
@@ -195,6 +199,7 @@ type ChannelStore interface {
GetChannelMembersForExport(userId string, teamId string) StoreChannel
RemoveAllDeactivatedMembers(channelId string) StoreChannel
GetChannelsBatchForIndexing(startTime, endTime int64, limit int) StoreChannel
UserBelongsToChannels(userId string, channelIds []string) StoreChannel
}
type ChannelMemberHistoryStore interface {
@@ -256,12 +261,12 @@ type UserStore interface {
GetProfilesInChannel(channelId string, offset int, limit int) StoreChannel
GetProfilesInChannelByStatus(channelId string, offset int, limit int) StoreChannel
GetAllProfilesInChannel(channelId string, allowFromCache bool) StoreChannel
GetProfilesNotInChannel(teamId string, channelId string, offset int, limit int) StoreChannel
GetProfilesWithoutTeam(offset int, limit int) StoreChannel
GetProfilesByUsernames(usernames []string, teamId string) StoreChannel
GetProfilesNotInChannel(teamId string, channelId string, offset int, limit int, viewRestrictions *model.ViewUsersRestrictions) StoreChannel
GetProfilesWithoutTeam(offset int, limit int, viewRestrictions *model.ViewUsersRestrictions) StoreChannel
GetProfilesByUsernames(usernames []string, viewRestrictions *model.ViewUsersRestrictions) StoreChannel
GetAllProfiles(options *model.UserGetOptions) StoreChannel
GetProfiles(options *model.UserGetOptions) StoreChannel
GetProfileByIds(userId []string, allowFromCache bool) StoreChannel
GetProfileByIds(userId []string, allowFromCache bool, viewRestrictions *model.ViewUsersRestrictions) StoreChannel
InvalidatProfileCacheForUser(userId string)
GetByEmail(email string) StoreChannel
GetByAuth(authData *string, authService string) StoreChannel
@@ -278,8 +283,8 @@ type UserStore interface {
GetUnreadCount(userId string) StoreChannel
GetUnreadCountForChannel(userId string, channelId string) StoreChannel
GetAnyUnreadPostCountForChannel(userId string, channelId string) StoreChannel
GetRecentlyActiveUsersForTeam(teamId string, offset, limit int) StoreChannel
GetNewUsersForTeam(teamId string, offset, limit int) StoreChannel
GetRecentlyActiveUsersForTeam(teamId string, offset, limit int, viewRestrictions *model.ViewUsersRestrictions) StoreChannel
GetNewUsersForTeam(teamId string, offset, limit int, viewRestrictions *model.ViewUsersRestrictions) StoreChannel
Search(teamId string, term string, options *model.UserSearchOptions) StoreChannel
SearchNotInTeam(notInTeamId string, term string, options *model.UserSearchOptions) StoreChannel
SearchInChannel(channelId string, term string, options *model.UserSearchOptions) StoreChannel
@@ -287,7 +292,7 @@ type UserStore interface {
SearchWithoutTeam(term string, options *model.UserSearchOptions) StoreChannel
AnalyticsGetInactiveUsersCount() StoreChannel
AnalyticsGetSystemAdminCount() StoreChannel
GetProfilesNotInTeam(teamId string, offset int, limit int) StoreChannel
GetProfilesNotInTeam(teamId string, offset int, limit int, viewRestrictions *model.ViewUsersRestrictions) StoreChannel
GetEtagForProfilesNotInTeam(teamId string) StoreChannel
ClearAllCustomRoleAssignments() StoreChannel
InferSystemInstallDate() StoreChannel

Просмотреть файл

@@ -1087,3 +1087,19 @@ func (_m *ChannelStore) UpdateMember(member *model.ChannelMember) store.StoreCha
return r0
}
// UserBelongsToChannels provides a mock function with given fields: userId, channelIds
func (_m *ChannelStore) UserBelongsToChannels(userId string, channelIds []string) store.StoreChannel {
ret := _m.Called(userId, channelIds)
var r0 store.StoreChannel
if rf, ok := ret.Get(0).(func(string, []string) store.StoreChannel); ok {
r0 = rf(userId, channelIds)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(store.StoreChannel)
}
}
return r0
}

Просмотреть файл

@@ -61,6 +61,11 @@ func (_m *TeamStore) ClearAllCustomRoleAssignments() store.StoreChannel {
return r0
}
// ClearCaches provides a mock function with given fields:
func (_m *TeamStore) ClearCaches() {
_m.Called()
}
// Get provides a mock function with given fields: id
func (_m *TeamStore) Get(id string) (*model.Team, *model.AppError) {
ret := _m.Called(id)
@@ -294,13 +299,13 @@ func (_m *TeamStore) GetMember(teamId string, userId string) store.StoreChannel
return r0
}
// GetMembers provides a mock function with given fields: teamId, offset, limit
func (_m *TeamStore) GetMembers(teamId string, offset int, limit int) store.StoreChannel {
ret := _m.Called(teamId, offset, limit)
// GetMembers provides a mock function with given fields: teamId, offset, limit, restrictions
func (_m *TeamStore) GetMembers(teamId string, offset int, limit int, restrictions *model.ViewUsersRestrictions) store.StoreChannel {
ret := _m.Called(teamId, offset, limit, restrictions)
var r0 store.StoreChannel
if rf, ok := ret.Get(0).(func(string, int, int) store.StoreChannel); ok {
r0 = rf(teamId, offset, limit)
if rf, ok := ret.Get(0).(func(string, int, int, *model.ViewUsersRestrictions) store.StoreChannel); ok {
r0 = rf(teamId, offset, limit, restrictions)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(store.StoreChannel)
@@ -310,13 +315,13 @@ func (_m *TeamStore) GetMembers(teamId string, offset int, limit int) store.Stor
return r0
}
// GetMembersByIds provides a mock function with given fields: teamId, userIds
func (_m *TeamStore) GetMembersByIds(teamId string, userIds []string) store.StoreChannel {
ret := _m.Called(teamId, userIds)
// GetMembersByIds provides a mock function with given fields: teamId, userIds, restrictions
func (_m *TeamStore) GetMembersByIds(teamId string, userIds []string, restrictions *model.ViewUsersRestrictions) store.StoreChannel {
ret := _m.Called(teamId, userIds, restrictions)
var r0 store.StoreChannel
if rf, ok := ret.Get(0).(func(string, []string) store.StoreChannel); ok {
r0 = rf(teamId, userIds)
if rf, ok := ret.Get(0).(func(string, []string, *model.ViewUsersRestrictions) store.StoreChannel); ok {
r0 = rf(teamId, userIds, restrictions)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(store.StoreChannel)
@@ -422,6 +427,27 @@ func (_m *TeamStore) GetTotalMemberCount(teamId string) store.StoreChannel {
return r0
}
// GetUserTeamIds provides a mock function with given fields: userId, allowFromCache
func (_m *TeamStore) GetUserTeamIds(userId string, allowFromCache bool) store.StoreChannel {
ret := _m.Called(userId, allowFromCache)
var r0 store.StoreChannel
if rf, ok := ret.Get(0).(func(string, bool) store.StoreChannel); ok {
r0 = rf(userId, allowFromCache)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(store.StoreChannel)
}
}
return r0
}
// InvalidateAllTeamIdsForUser provides a mock function with given fields: userId
func (_m *TeamStore) InvalidateAllTeamIdsForUser(userId string) {
_m.Called(userId)
}
// MigrateTeamMembers provides a mock function with given fields: fromTeamId, fromUserId
func (_m *TeamStore) MigrateTeamMembers(fromTeamId string, fromUserId string) store.StoreChannel {
ret := _m.Called(fromTeamId, fromUserId)
@@ -686,3 +712,19 @@ func (_m *TeamStore) UpdateMember(member *model.TeamMember) store.StoreChannel {
return r0
}
// UserBelongsToTeams provides a mock function with given fields: userId, teamIds
func (_m *TeamStore) UserBelongsToTeams(userId string, teamIds []string) store.StoreChannel {
ret := _m.Called(userId, teamIds)
var r0 store.StoreChannel
if rf, ok := ret.Get(0).(func(string, []string) store.StoreChannel); ok {
r0 = rf(userId, teamIds)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(store.StoreChannel)
}
}
return r0
}

Просмотреть файл

@@ -347,13 +347,13 @@ func (_m *UserStore) GetForLogin(loginId string, allowSignInWithUsername bool, a
return r0
}
// GetNewUsersForTeam provides a mock function with given fields: teamId, offset, limit
func (_m *UserStore) GetNewUsersForTeam(teamId string, offset int, limit int) store.StoreChannel {
ret := _m.Called(teamId, offset, limit)
// GetNewUsersForTeam provides a mock function with given fields: teamId, offset, limit, viewRestrictions
func (_m *UserStore) GetNewUsersForTeam(teamId string, offset int, limit int, viewRestrictions *model.ViewUsersRestrictions) store.StoreChannel {
ret := _m.Called(teamId, offset, limit, viewRestrictions)
var r0 store.StoreChannel
if rf, ok := ret.Get(0).(func(string, int, int) store.StoreChannel); ok {
r0 = rf(teamId, offset, limit)
if rf, ok := ret.Get(0).(func(string, int, int, *model.ViewUsersRestrictions) store.StoreChannel); ok {
r0 = rf(teamId, offset, limit, viewRestrictions)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(store.StoreChannel)
@@ -363,13 +363,13 @@ func (_m *UserStore) GetNewUsersForTeam(teamId string, offset int, limit int) st
return r0
}
// GetProfileByIds provides a mock function with given fields: userId, allowFromCache
func (_m *UserStore) GetProfileByIds(userId []string, allowFromCache bool) store.StoreChannel {
ret := _m.Called(userId, allowFromCache)
// GetProfileByIds provides a mock function with given fields: userId, allowFromCache, viewRestrictions
func (_m *UserStore) GetProfileByIds(userId []string, allowFromCache bool, viewRestrictions *model.ViewUsersRestrictions) store.StoreChannel {
ret := _m.Called(userId, allowFromCache, viewRestrictions)
var r0 store.StoreChannel
if rf, ok := ret.Get(0).(func([]string, bool) store.StoreChannel); ok {
r0 = rf(userId, allowFromCache)
if rf, ok := ret.Get(0).(func([]string, bool, *model.ViewUsersRestrictions) store.StoreChannel); ok {
r0 = rf(userId, allowFromCache, viewRestrictions)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(store.StoreChannel)
@@ -395,13 +395,13 @@ func (_m *UserStore) GetProfiles(options *model.UserGetOptions) store.StoreChann
return r0
}
// GetProfilesByUsernames provides a mock function with given fields: usernames, teamId
func (_m *UserStore) GetProfilesByUsernames(usernames []string, teamId string) store.StoreChannel {
ret := _m.Called(usernames, teamId)
// GetProfilesByUsernames provides a mock function with given fields: usernames, viewRestrictions
func (_m *UserStore) GetProfilesByUsernames(usernames []string, viewRestrictions *model.ViewUsersRestrictions) store.StoreChannel {
ret := _m.Called(usernames, viewRestrictions)
var r0 store.StoreChannel
if rf, ok := ret.Get(0).(func([]string, string) store.StoreChannel); ok {
r0 = rf(usernames, teamId)
if rf, ok := ret.Get(0).(func([]string, *model.ViewUsersRestrictions) store.StoreChannel); ok {
r0 = rf(usernames, viewRestrictions)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(store.StoreChannel)
@@ -443,13 +443,13 @@ func (_m *UserStore) GetProfilesInChannelByStatus(channelId string, offset int,
return r0
}
// GetProfilesNotInChannel provides a mock function with given fields: teamId, channelId, offset, limit
func (_m *UserStore) GetProfilesNotInChannel(teamId string, channelId string, offset int, limit int) store.StoreChannel {
ret := _m.Called(teamId, channelId, offset, limit)
// GetProfilesNotInChannel provides a mock function with given fields: teamId, channelId, offset, limit, viewRestrictions
func (_m *UserStore) GetProfilesNotInChannel(teamId string, channelId string, offset int, limit int, viewRestrictions *model.ViewUsersRestrictions) store.StoreChannel {
ret := _m.Called(teamId, channelId, offset, limit, viewRestrictions)
var r0 store.StoreChannel
if rf, ok := ret.Get(0).(func(string, string, int, int) store.StoreChannel); ok {
r0 = rf(teamId, channelId, offset, limit)
if rf, ok := ret.Get(0).(func(string, string, int, int, *model.ViewUsersRestrictions) store.StoreChannel); ok {
r0 = rf(teamId, channelId, offset, limit, viewRestrictions)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(store.StoreChannel)
@@ -459,13 +459,13 @@ func (_m *UserStore) GetProfilesNotInChannel(teamId string, channelId string, of
return r0
}
// GetProfilesNotInTeam provides a mock function with given fields: teamId, offset, limit
func (_m *UserStore) GetProfilesNotInTeam(teamId string, offset int, limit int) store.StoreChannel {
ret := _m.Called(teamId, offset, limit)
// GetProfilesNotInTeam provides a mock function with given fields: teamId, offset, limit, viewRestrictions
func (_m *UserStore) GetProfilesNotInTeam(teamId string, offset int, limit int, viewRestrictions *model.ViewUsersRestrictions) store.StoreChannel {
ret := _m.Called(teamId, offset, limit, viewRestrictions)
var r0 store.StoreChannel
if rf, ok := ret.Get(0).(func(string, int, int) store.StoreChannel); ok {
r0 = rf(teamId, offset, limit)
if rf, ok := ret.Get(0).(func(string, int, int, *model.ViewUsersRestrictions) store.StoreChannel); ok {
r0 = rf(teamId, offset, limit, viewRestrictions)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(store.StoreChannel)
@@ -475,13 +475,13 @@ func (_m *UserStore) GetProfilesNotInTeam(teamId string, offset int, limit int)
return r0
}
// GetProfilesWithoutTeam provides a mock function with given fields: offset, limit
func (_m *UserStore) GetProfilesWithoutTeam(offset int, limit int) store.StoreChannel {
ret := _m.Called(offset, limit)
// GetProfilesWithoutTeam provides a mock function with given fields: offset, limit, viewRestrictions
func (_m *UserStore) GetProfilesWithoutTeam(offset int, limit int, viewRestrictions *model.ViewUsersRestrictions) store.StoreChannel {
ret := _m.Called(offset, limit, viewRestrictions)
var r0 store.StoreChannel
if rf, ok := ret.Get(0).(func(int, int) store.StoreChannel); ok {
r0 = rf(offset, limit)
if rf, ok := ret.Get(0).(func(int, int, *model.ViewUsersRestrictions) store.StoreChannel); ok {
r0 = rf(offset, limit, viewRestrictions)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(store.StoreChannel)
@@ -491,13 +491,13 @@ func (_m *UserStore) GetProfilesWithoutTeam(offset int, limit int) store.StoreCh
return r0
}
// GetRecentlyActiveUsersForTeam provides a mock function with given fields: teamId, offset, limit
func (_m *UserStore) GetRecentlyActiveUsersForTeam(teamId string, offset int, limit int) store.StoreChannel {
ret := _m.Called(teamId, offset, limit)
// GetRecentlyActiveUsersForTeam provides a mock function with given fields: teamId, offset, limit, viewRestrictions
func (_m *UserStore) GetRecentlyActiveUsersForTeam(teamId string, offset int, limit int, viewRestrictions *model.ViewUsersRestrictions) store.StoreChannel {
ret := _m.Called(teamId, offset, limit, viewRestrictions)
var r0 store.StoreChannel
if rf, ok := ret.Get(0).(func(string, int, int) store.StoreChannel); ok {
r0 = rf(teamId, offset, limit)
if rf, ok := ret.Get(0).(func(string, int, int, *model.ViewUsersRestrictions) store.StoreChannel); ok {
r0 = rf(teamId, offset, limit, viewRestrictions)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(store.StoreChannel)

Просмотреть файл

@@ -769,14 +769,14 @@ func testTeamMembers(t *testing.T, ss store.Store) {
store.Must(ss.Team().SaveMember(m2, -1))
store.Must(ss.Team().SaveMember(m3, -1))
if r1 := <-ss.Team().GetMembers(teamId1, 0, 100); r1.Err != nil {
if r1 := <-ss.Team().GetMembers(teamId1, 0, 100, nil); r1.Err != nil {
t.Fatal(r1.Err)
} else {
ms := r1.Data.([]*model.TeamMember)
require.Len(t, ms, 2)
}
if r1 := <-ss.Team().GetMembers(teamId2, 0, 100); r1.Err != nil {
if r1 := <-ss.Team().GetMembers(teamId2, 0, 100, nil); r1.Err != nil {
t.Fatal(r1.Err)
} else {
ms := r1.Data.([]*model.TeamMember)
@@ -798,7 +798,7 @@ func testTeamMembers(t *testing.T, ss store.Store) {
t.Fatal(r1.Err)
}
if r1 := <-ss.Team().GetMembers(teamId1, 0, 100); r1.Err != nil {
if r1 := <-ss.Team().GetMembers(teamId1, 0, 100, nil); r1.Err != nil {
t.Fatal(r1.Err)
} else {
ms := r1.Data.([]*model.TeamMember)
@@ -813,7 +813,7 @@ func testTeamMembers(t *testing.T, ss store.Store) {
t.Fatal(r1.Err)
}
if r1 := <-ss.Team().GetMembers(teamId1, 0, 100); r1.Err != nil {
if r1 := <-ss.Team().GetMembers(teamId1, 0, 100, nil); r1.Err != nil {
t.Fatal(r1.Err)
} else {
ms := r1.Data.([]*model.TeamMember)
@@ -872,7 +872,7 @@ func testTeamMembersWithPagination(t *testing.T, ss store.Store) {
r1 = <-ss.Team().RemoveMember(teamId1, m1.UserId)
require.Nil(t, r1.Err)
r1 = <-ss.Team().GetMembers(teamId1, 0, 100)
r1 = <-ss.Team().GetMembers(teamId1, 0, 100, nil)
require.Nil(t, r1.Err)
ms = r1.Data.([]*model.TeamMember)
@@ -1077,7 +1077,7 @@ func testGetTeamMembersByIds(t *testing.T, ss store.Store) {
m1 := &model.TeamMember{TeamId: teamId1, UserId: model.NewId()}
store.Must(ss.Team().SaveMember(m1, -1))
if r := <-ss.Team().GetMembersByIds(m1.TeamId, []string{m1.UserId}); r.Err != nil {
if r := <-ss.Team().GetMembersByIds(m1.TeamId, []string{m1.UserId}, nil); r.Err != nil {
t.Fatal(r.Err)
} else {
rm1 := r.Data.([]*model.TeamMember)[0]
@@ -1094,7 +1094,7 @@ func testGetTeamMembersByIds(t *testing.T, ss store.Store) {
m2 := &model.TeamMember{TeamId: teamId1, UserId: model.NewId()}
store.Must(ss.Team().SaveMember(m2, -1))
if r := <-ss.Team().GetMembersByIds(m1.TeamId, []string{m1.UserId, m2.UserId, model.NewId()}); r.Err != nil {
if r := <-ss.Team().GetMembersByIds(m1.TeamId, []string{m1.UserId, m2.UserId, model.NewId()}, nil); r.Err != nil {
t.Fatal(r.Err)
} else {
rm := r.Data.([]*model.TeamMember)
@@ -1104,7 +1104,7 @@ func testGetTeamMembersByIds(t *testing.T, ss store.Store) {
}
}
if r := <-ss.Team().GetMembersByIds(m1.TeamId, []string{}); r.Err == nil {
if r := <-ss.Team().GetMembersByIds(m1.TeamId, []string{}, nil); r.Err == nil {
t.Fatal("empty user ids - should have failed")
}
}

Просмотреть файл

@@ -860,19 +860,19 @@ func testUserStoreGetProfilesWithoutTeam(t *testing.T, ss store.Store) {
defer func() { store.Must(ss.Bot().PermanentDelete(u3.Id)) }()
t.Run("get, offset 0, limit 100", func(t *testing.T) {
result := <-ss.User().GetProfilesWithoutTeam(0, 100)
result := <-ss.User().GetProfilesWithoutTeam(0, 100, nil)
require.Nil(t, result.Err)
assert.Equal(t, []*model.User{sanitized(u2), sanitized(u3)}, result.Data.([]*model.User))
})
t.Run("get, offset 1, limit 1", func(t *testing.T) {
result := <-ss.User().GetProfilesWithoutTeam(1, 1)
result := <-ss.User().GetProfilesWithoutTeam(1, 1, nil)
require.Nil(t, result.Err)
assert.Equal(t, []*model.User{sanitized(u3)}, result.Data.([]*model.User))
})
t.Run("get, offset 2, limit 1", func(t *testing.T) {
result := <-ss.User().GetProfilesWithoutTeam(2, 1)
result := <-ss.User().GetProfilesWithoutTeam(2, 1, nil)
require.Nil(t, result.Err)
assert.Equal(t, []*model.User{}, result.Data.([]*model.User))
})
@@ -1031,7 +1031,7 @@ func testUserStoreGetProfilesNotInChannel(t *testing.T, ss store.Store) {
}, -1)).(*model.Channel)
t.Run("get team 1, channel 1, offset 0, limit 100", func(t *testing.T) {
result := <-ss.User().GetProfilesNotInChannel(teamId, c1.Id, 0, 100)
result := <-ss.User().GetProfilesNotInChannel(teamId, c1.Id, 0, 100, nil)
require.Nil(t, result.Err)
assert.Equal(t, []*model.User{
sanitized(u1),
@@ -1041,7 +1041,7 @@ func testUserStoreGetProfilesNotInChannel(t *testing.T, ss store.Store) {
})
t.Run("get team 1, channel 2, offset 0, limit 100", func(t *testing.T) {
result := <-ss.User().GetProfilesNotInChannel(teamId, c2.Id, 0, 100)
result := <-ss.User().GetProfilesNotInChannel(teamId, c2.Id, 0, 100, nil)
require.Nil(t, result.Err)
assert.Equal(t, []*model.User{
sanitized(u1),
@@ -1075,13 +1075,13 @@ func testUserStoreGetProfilesNotInChannel(t *testing.T, ss store.Store) {
}))
t.Run("get team 1, channel 1, offset 0, limit 100, after update", func(t *testing.T) {
result := <-ss.User().GetProfilesNotInChannel(teamId, c1.Id, 0, 100)
result := <-ss.User().GetProfilesNotInChannel(teamId, c1.Id, 0, 100, nil)
require.Nil(t, result.Err)
assert.Equal(t, []*model.User{}, result.Data.([]*model.User))
})
t.Run("get team 1, channel 2, offset 0, limit 100, after update", func(t *testing.T) {
result := <-ss.User().GetProfilesNotInChannel(teamId, c2.Id, 0, 100)
result := <-ss.User().GetProfilesNotInChannel(teamId, c2.Id, 0, 100, nil)
require.Nil(t, result.Err)
assert.Equal(t, []*model.User{
sanitized(u2),
@@ -1122,31 +1122,31 @@ func testUserStoreGetProfilesByIds(t *testing.T, ss store.Store) {
defer func() { store.Must(ss.Bot().PermanentDelete(u3.Id)) }()
t.Run("get u1 by id, no caching", func(t *testing.T) {
result := <-ss.User().GetProfileByIds([]string{u1.Id}, false)
result := <-ss.User().GetProfileByIds([]string{u1.Id}, false, nil)
require.Nil(t, result.Err)
assert.Equal(t, []*model.User{sanitized(u1)}, result.Data.([]*model.User))
})
t.Run("get u1 by id, caching", func(t *testing.T) {
result := <-ss.User().GetProfileByIds([]string{u1.Id}, true)
result := <-ss.User().GetProfileByIds([]string{u1.Id}, true, nil)
require.Nil(t, result.Err)
assert.Equal(t, []*model.User{sanitized(u1)}, result.Data.([]*model.User))
})
t.Run("get u1, u2, u3 by id, no caching", func(t *testing.T) {
result := <-ss.User().GetProfileByIds([]string{u1.Id, u2.Id, u3.Id}, false)
result := <-ss.User().GetProfileByIds([]string{u1.Id, u2.Id, u3.Id}, false, nil)
require.Nil(t, result.Err)
assert.Equal(t, []*model.User{sanitized(u1), sanitized(u2), sanitized(u3)}, result.Data.([]*model.User))
})
t.Run("get u1, u2, u3 by id, caching", func(t *testing.T) {
result := <-ss.User().GetProfileByIds([]string{u1.Id, u2.Id, u3.Id}, true)
result := <-ss.User().GetProfileByIds([]string{u1.Id, u2.Id, u3.Id}, true, nil)
require.Nil(t, result.Err)
assert.Equal(t, []*model.User{sanitized(u1), sanitized(u2), sanitized(u3)}, result.Data.([]*model.User))
})
t.Run("get unknown id, caching", func(t *testing.T) {
result := <-ss.User().GetProfileByIds([]string{"123"}, true)
result := <-ss.User().GetProfileByIds([]string{"123"}, true, nil)
require.Nil(t, result.Err)
assert.Equal(t, []*model.User{}, result.Data.([]*model.User))
})
@@ -1185,31 +1185,31 @@ func testUserStoreGetProfilesByUsernames(t *testing.T, ss store.Store) {
defer func() { store.Must(ss.Bot().PermanentDelete(u3.Id)) }()
t.Run("get by u1 and u2 usernames, team id 1", func(t *testing.T) {
result := <-ss.User().GetProfilesByUsernames([]string{u1.Username, u2.Username}, teamId)
result := <-ss.User().GetProfilesByUsernames([]string{u1.Username, u2.Username}, &model.ViewUsersRestrictions{Teams: []string{teamId}})
require.Nil(t, result.Err)
assert.Equal(t, []*model.User{u1, u2}, result.Data.([]*model.User))
})
t.Run("get by u1 username, team id 1", func(t *testing.T) {
result := <-ss.User().GetProfilesByUsernames([]string{u1.Username}, teamId)
result := <-ss.User().GetProfilesByUsernames([]string{u1.Username}, &model.ViewUsersRestrictions{Teams: []string{teamId}})
require.Nil(t, result.Err)
assert.Equal(t, []*model.User{u1}, result.Data.([]*model.User))
})
t.Run("get by u1 and u3 usernames, no team id", func(t *testing.T) {
result := <-ss.User().GetProfilesByUsernames([]string{u1.Username, u3.Username}, "")
result := <-ss.User().GetProfilesByUsernames([]string{u1.Username, u3.Username}, nil)
require.Nil(t, result.Err)
assert.Equal(t, []*model.User{u1, u3}, result.Data.([]*model.User))
})
t.Run("get by u1 and u3 usernames, team id 1", func(t *testing.T) {
result := <-ss.User().GetProfilesByUsernames([]string{u1.Username, u3.Username}, teamId)
result := <-ss.User().GetProfilesByUsernames([]string{u1.Username, u3.Username}, &model.ViewUsersRestrictions{Teams: []string{teamId}})
require.Nil(t, result.Err)
assert.Equal(t, []*model.User{u1}, result.Data.([]*model.User))
})
t.Run("get by u1 and u3 usernames, team id 2", func(t *testing.T) {
result := <-ss.User().GetProfilesByUsernames([]string{u1.Username, u3.Username}, team2Id)
result := <-ss.User().GetProfilesByUsernames([]string{u1.Username, u3.Username}, &model.ViewUsersRestrictions{Teams: []string{team2Id}})
require.Nil(t, result.Err)
assert.Equal(t, []*model.User{u3}, result.Data.([]*model.User))
})
@@ -1778,7 +1778,7 @@ func testUserStoreGetRecentlyActiveUsersForTeam(t *testing.T, ss store.Store) {
store.Must(ss.Status().SaveOrUpdate(&model.Status{UserId: u3.Id, Status: model.STATUS_ONLINE, Manual: false, LastActivityAt: u3.LastActivityAt, ActiveChannel: ""}))
t.Run("get team 1, offset 0, limit 100", func(t *testing.T) {
result := <-ss.User().GetRecentlyActiveUsersForTeam(teamId, 0, 100)
result := <-ss.User().GetRecentlyActiveUsersForTeam(teamId, 0, 100, nil)
require.Nil(t, result.Err)
assert.Equal(t, []*model.User{
sanitized(u3),
@@ -1788,7 +1788,7 @@ func testUserStoreGetRecentlyActiveUsersForTeam(t *testing.T, ss store.Store) {
})
t.Run("get team 1, offset 0, limit 1", func(t *testing.T) {
result := <-ss.User().GetRecentlyActiveUsersForTeam(teamId, 0, 1)
result := <-ss.User().GetRecentlyActiveUsersForTeam(teamId, 0, 1, nil)
require.Nil(t, result.Err)
assert.Equal(t, []*model.User{
sanitized(u3),
@@ -1796,7 +1796,7 @@ func testUserStoreGetRecentlyActiveUsersForTeam(t *testing.T, ss store.Store) {
})
t.Run("get team 1, offset 2, limit 1", func(t *testing.T) {
result := <-ss.User().GetRecentlyActiveUsersForTeam(teamId, 2, 1)
result := <-ss.User().GetRecentlyActiveUsersForTeam(teamId, 2, 1, nil)
require.Nil(t, result.Err)
assert.Equal(t, []*model.User{
sanitized(u2),
@@ -1844,7 +1844,7 @@ func testUserStoreGetNewUsersForTeam(t *testing.T, ss store.Store) {
store.Must(ss.Team().SaveMember(&model.TeamMember{TeamId: teamId2, UserId: u4.Id}, -1))
t.Run("get team 1, offset 0, limit 100", func(t *testing.T) {
result := <-ss.User().GetNewUsersForTeam(teamId, 0, 100)
result := <-ss.User().GetNewUsersForTeam(teamId, 0, 100, nil)
require.Nil(t, result.Err)
assert.Equal(t, []*model.User{
sanitized(u3),
@@ -1854,7 +1854,7 @@ func testUserStoreGetNewUsersForTeam(t *testing.T, ss store.Store) {
})
t.Run("get team 1, offset 0, limit 1", func(t *testing.T) {
result := <-ss.User().GetNewUsersForTeam(teamId, 0, 1)
result := <-ss.User().GetNewUsersForTeam(teamId, 0, 1, nil)
require.Nil(t, result.Err)
assert.Equal(t, []*model.User{
sanitized(u3),
@@ -1862,7 +1862,7 @@ func testUserStoreGetNewUsersForTeam(t *testing.T, ss store.Store) {
})
t.Run("get team 1, offset 2, limit 1", func(t *testing.T) {
result := <-ss.User().GetNewUsersForTeam(teamId, 2, 1)
result := <-ss.User().GetNewUsersForTeam(teamId, 2, 1, nil)
require.Nil(t, result.Err)
assert.Equal(t, []*model.User{
sanitized(u1),
@@ -1870,7 +1870,7 @@ func testUserStoreGetNewUsersForTeam(t *testing.T, ss store.Store) {
})
t.Run("get team 2, offset 0, limit 100", func(t *testing.T) {
result := <-ss.User().GetNewUsersForTeam(teamId2, 0, 100)
result := <-ss.User().GetNewUsersForTeam(teamId2, 0, 100, nil)
require.Nil(t, result.Err)
assert.Equal(t, []*model.User{
sanitized(u4),
@@ -2982,6 +2982,23 @@ func testCount(t *testing.T, ss store.Store) {
require.Nil(t, result.Err)
require.Equal(t, int64(0), result.Data.(int64))
result = <-ss.User().Count(model.UserCountOptions{
IncludeBotAccounts: true,
IncludeDeleted: true,
TeamId: teamId,
ViewRestrictions: &model.ViewUsersRestrictions{Teams: []string{teamId}},
})
require.Nil(t, result.Err)
require.Equal(t, int64(1), result.Data.(int64))
result = <-ss.User().Count(model.UserCountOptions{
IncludeBotAccounts: true,
IncludeDeleted: true,
TeamId: teamId,
ViewRestrictions: &model.ViewUsersRestrictions{Teams: []string{model.NewId()}},
})
require.Nil(t, result.Err)
require.Equal(t, int64(0), result.Data.(int64))
}
func testUserStoreAnalyticsGetInactiveUsersCount(t *testing.T, ss store.Store) {
@@ -3097,7 +3114,7 @@ func testUserStoreGetProfilesNotInTeam(t *testing.T, ss store.Store) {
})
t.Run("get not in team 1, offset 0, limit 100000", func(t *testing.T) {
result := <-ss.User().GetProfilesNotInTeam(teamId, 0, 100000)
result := <-ss.User().GetProfilesNotInTeam(teamId, 0, 100000, nil)
require.Nil(t, result.Err)
assert.Equal(t, []*model.User{
sanitized(u2),
@@ -3106,7 +3123,7 @@ func testUserStoreGetProfilesNotInTeam(t *testing.T, ss store.Store) {
})
t.Run("get not in team 1, offset 1, limit 1", func(t *testing.T) {
result := <-ss.User().GetProfilesNotInTeam(teamId, 1, 1)
result := <-ss.User().GetProfilesNotInTeam(teamId, 1, 1, nil)
require.Nil(t, result.Err)
assert.Equal(t, []*model.User{
sanitized(u3),
@@ -3114,7 +3131,7 @@ func testUserStoreGetProfilesNotInTeam(t *testing.T, ss store.Store) {
})
t.Run("get not in team 2, offset 0, limit 100", func(t *testing.T) {
result := <-ss.User().GetProfilesNotInTeam(teamId2, 0, 100)
result := <-ss.User().GetProfilesNotInTeam(teamId2, 0, 100, nil)
require.Nil(t, result.Err)
assert.Equal(t, []*model.User{
sanitized(u1),
@@ -3137,7 +3154,7 @@ func testUserStoreGetProfilesNotInTeam(t *testing.T, ss store.Store) {
})
t.Run("get not in team 1, offset 0, limit 100000 after update", func(t *testing.T) {
result := <-ss.User().GetProfilesNotInTeam(teamId, 0, 100000)
result := <-ss.User().GetProfilesNotInTeam(teamId, 0, 100000, nil)
require.Nil(t, result.Err)
assert.Equal(t, []*model.User{
sanitized(u3),
@@ -3161,7 +3178,7 @@ func testUserStoreGetProfilesNotInTeam(t *testing.T, ss store.Store) {
})
t.Run("get not in team 1, offset 0, limit 100000 after second update", func(t *testing.T) {
result := <-ss.User().GetProfilesNotInTeam(teamId, 0, 100000)
result := <-ss.User().GetProfilesNotInTeam(teamId, 0, 100000, nil)
require.Nil(t, result.Err)
assert.Equal(t, []*model.User{
sanitized(u1),