// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. package storetest import ( "context" "errors" "fmt" "sort" "strings" "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/mattermost/mattermost/server/public/model" "github.com/mattermost/mattermost/server/public/shared/request" "github.com/mattermost/mattermost/server/v8/channels/app/password/hashers" "github.com/mattermost/mattermost/server/v8/channels/store" ) const ( DayMilliseconds = 24 * 60 * 60 * 1000 MonthMilliseconds = 31 * DayMilliseconds ) func cleanupStatusStore(t *testing.T, s SqlStore) { _, execerr := s.GetMaster().Exec(`DELETE FROM Status`) require.NoError(t, execerr) } func TestUserStore(t *testing.T, rctx request.CTX, ss store.Store, s SqlStore) { users, err := ss.User().GetAll() require.NoError(t, err, "failed cleaning up test users") for _, u := range users { err := ss.User().PermanentDelete(rctx, u.Id) require.NoError(t, err, "failed cleaning up test user %s", u.Username) } t.Run("IsEmpty", func(t *testing.T) { testIsEmpty(t, rctx, ss) }) t.Run("Count", func(t *testing.T) { testCount(t, rctx, ss) }) t.Run("AnalyticsActiveCount", func(t *testing.T) { testUserStoreAnalyticsActiveCount(t, rctx, ss, s) }) t.Run("AnalyticsActiveCountForPeriod", func(t *testing.T) { testUserStoreAnalyticsActiveCountForPeriod(t, rctx, ss, s) }) t.Run("AnalyticsGetInactiveUsersCount", func(t *testing.T) { testUserStoreAnalyticsGetInactiveUsersCount(t, rctx, ss) }) t.Run("AnalyticsGetInactiveUsersCountIgnoreBots", func(t *testing.T) { testUserStoreAnalyticsGetInactiveUsersCountIgnoreBots(t, rctx, ss) }) t.Run("AnalyticsGetSystemAdminCount", func(t *testing.T) { testUserStoreAnalyticsGetSystemAdminCount(t, rctx, ss) }) t.Run("AnalyticsGetGuestCount", func(t *testing.T) { testUserStoreAnalyticsGetGuestCount(t, rctx, ss) }) t.Run("AnalyticsGetExternalUsers", func(t *testing.T) { testUserStoreAnalyticsGetExternalUsers(t, rctx, ss) }) t.Run("Save", func(t *testing.T) { testUserStoreSave(t, rctx, ss) }) t.Run("Update", func(t *testing.T) { testUserStoreUpdate(t, rctx, ss) }) t.Run("UpdateUpdateAt", func(t *testing.T) { testUserStoreUpdateUpdateAt(t, rctx, ss) }) t.Run("UpdateFailedPasswordAttempts", func(t *testing.T) { testUserStoreUpdateFailedPasswordAttempts(t, rctx, ss) }) t.Run("Get", func(t *testing.T) { testUserStoreGet(t, rctx, ss) }) t.Run("GetAllUsingAuthService", func(t *testing.T) { testGetAllUsingAuthService(t, rctx, ss) }) t.Run("GetAllProfiles", func(t *testing.T) { testUserStoreGetAllProfiles(t, rctx, ss) }) t.Run("GetProfiles", func(t *testing.T) { testUserStoreGetProfiles(t, rctx, ss) }) t.Run("GetProfilesInChannel", func(t *testing.T) { testUserStoreGetProfilesInChannel(t, rctx, ss) }) t.Run("GetProfilesInChannelByStatus", func(t *testing.T) { testUserStoreGetProfilesInChannelByStatus(t, rctx, ss, s) }) t.Run("GetProfilesInChannelByAdmin", func(t *testing.T) { testUserStoreGetProfilesInChannelByAdmin(t, rctx, ss, s) }) t.Run("GetProfilesWithoutTeam", func(t *testing.T) { testUserStoreGetProfilesWithoutTeam(t, rctx, ss) }) t.Run("GetAllProfilesInChannel", func(t *testing.T) { testUserStoreGetAllProfilesInChannel(t, rctx, ss) }) t.Run("GetProfilesNotInChannel", func(t *testing.T) { testUserStoreGetProfilesNotInChannel(t, rctx, ss) }) t.Run("GetProfilesByIds", func(t *testing.T) { testUserStoreGetProfilesByIds(t, rctx, ss) }) t.Run("GetProfileByGroupChannelIdsForUser", func(t *testing.T) { testUserStoreGetProfileByGroupChannelIdsForUser(t, rctx, ss) }) t.Run("GetProfilesByUsernames", func(t *testing.T) { testUserStoreGetProfilesByUsernames(t, rctx, ss) }) t.Run("GetSystemAdminProfiles", func(t *testing.T) { testUserStoreGetSystemAdminProfiles(t, rctx, ss) }) t.Run("GetByEmail", func(t *testing.T) { testUserStoreGetByEmail(t, rctx, ss) }) t.Run("GetByAuthData", func(t *testing.T) { testUserStoreGetByAuthData(t, rctx, ss) }) t.Run("GetByUsername", func(t *testing.T) { testUserStoreGetByUsername(t, rctx, ss) }) t.Run("GetForLogin", func(t *testing.T) { testUserStoreGetForLogin(t, rctx, ss) }) t.Run("UpdatePassword", func(t *testing.T) { testUserStoreUpdatePassword(t, rctx, ss) }) t.Run("Delete", func(t *testing.T) { testUserStoreDelete(t, rctx, ss) }) t.Run("UpdateAuthData", func(t *testing.T) { testUserStoreUpdateAuthData(t, rctx, ss) }) t.Run("ResetAuthDataToEmailForUsers", func(t *testing.T) { testUserStoreResetAuthDataToEmailForUsers(t, rctx, ss) }) t.Run("UserUnreadCount", func(t *testing.T) { testUserUnreadCount(t, rctx, ss) }) t.Run("UpdateMfaSecret", func(t *testing.T) { testUserStoreUpdateMfaSecret(t, rctx, ss) }) t.Run("UpdateMfaActive", func(t *testing.T) { testUserStoreUpdateMfaActive(t, rctx, ss) }) t.Run("GetRecentlyActiveUsersForTeam", func(t *testing.T) { testUserStoreGetRecentlyActiveUsersForTeam(t, rctx, ss, s) }) t.Run("GetNewUsersForTeam", func(t *testing.T) { testUserStoreGetNewUsersForTeam(t, rctx, ss) }) t.Run("Search", func(t *testing.T) { testUserStoreSearch(t, rctx, ss) }) t.Run("SearchNotInChannel", func(t *testing.T) { testUserStoreSearchNotInChannel(t, rctx, ss) }) t.Run("SearchInChannel", func(t *testing.T) { testUserStoreSearchInChannel(t, rctx, ss) }) t.Run("SearchNotInTeam", func(t *testing.T) { testUserStoreSearchNotInTeam(t, rctx, ss) }) t.Run("SearchWithoutTeam", func(t *testing.T) { testUserStoreSearchWithoutTeam(t, rctx, ss) }) t.Run("SearchInGroup", func(t *testing.T) { testUserStoreSearchInGroup(t, rctx, ss) }) t.Run("SearchNotInGroup", func(t *testing.T) { testUserStoreSearchNotInGroup(t, rctx, ss) }) t.Run("SearchCommonContentFlaggingReviewers", func(t *testing.T) { testUserStoreSearchCommonContentFlaggingReviewers(t, rctx, ss) }) t.Run("SearchTeamContentFlaggingReviewers", func(t *testing.T) { testUserStoreSearchTeamContentFlaggingReviewers(t, rctx, ss) }) t.Run("GetProfilesNotInTeam", func(t *testing.T) { testUserStoreGetProfilesNotInTeam(t, rctx, ss) }) t.Run("ClearAllCustomRoleAssignments", func(t *testing.T) { testUserStoreClearAllCustomRoleAssignments(t, rctx, ss) }) t.Run("GetAllAfter", func(t *testing.T) { testUserStoreGetAllAfter(t, rctx, ss) }) t.Run("GetUsersBatchForIndexing", func(t *testing.T) { testUserStoreGetUsersBatchForIndexing(t, rctx, ss) }) t.Run("GetTeamGroupUsers", func(t *testing.T) { testUserStoreGetTeamGroupUsers(t, rctx, ss) }) t.Run("GetChannelGroupUsers", func(t *testing.T) { testUserStoreGetChannelGroupUsers(t, rctx, ss) }) t.Run("PromoteGuestToUser", func(t *testing.T) { testUserStorePromoteGuestToUser(t, rctx, ss) }) t.Run("DemoteUserToGuest", func(t *testing.T) { testUserStoreDemoteUserToGuest(t, rctx, ss) }) t.Run("DeactivateGuests", func(t *testing.T) { testDeactivateGuests(t, rctx, ss) }) t.Run("ResetLastPictureUpdate", func(t *testing.T) { testUserStoreResetLastPictureUpdate(t, rctx, ss) }) t.Run("GetKnownUsers", func(t *testing.T) { testGetKnownUsers(t, rctx, ss) }) t.Run("GetUsersWithInvalidEmails", func(t *testing.T) { testGetUsersWithInvalidEmails(t, rctx, ss) }) t.Run("UpdateLastLogin", func(t *testing.T) { testUpdateLastLogin(t, rctx, ss) }) t.Run("GetUserReport", func(t *testing.T) { testGetUserReport(t, rctx, ss, s) }) t.Run("MfaUsedTimestamps", func(t *testing.T) { testMfaUsedTimestamps(t, rctx, ss) }) } func testUserStoreSave(t *testing.T, rctx request.CTX, ss store.Store) { teamID := model.NewId() maxUsersPerTeam := 50 u1 := model.User{ Email: MakeEmail(), Username: model.NewUsername(), } _, err := ss.User().Save(rctx, &u1) require.NoError(t, err, "couldn't save user") defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u1.Id)) }() _, nErr := ss.Team().SaveMember(rctx, &model.TeamMember{TeamId: teamID, UserId: u1.Id}, maxUsersPerTeam) require.NoError(t, nErr) _, err = ss.User().Save(rctx, &u1) require.Error(t, err, "shouldn't be able to update user from save") u2 := model.User{ Email: u1.Email, Username: model.NewUsername(), } _, err = ss.User().Save(rctx, &u2) require.Error(t, err, "should be unique email") u2.Email = MakeEmail() u2.Username = u1.Username _, err = ss.User().Save(rctx, &u2) require.Error(t, err, "should be unique username") u2.Username = "" _, err = ss.User().Save(rctx, &u2) require.Error(t, err, "should be non-empty username") u3 := model.User{ Email: MakeEmail(), Username: model.NewUsername(), NotifyProps: make(map[string]string, 1), } maxPostSize := ss.Post().GetMaxPostSize() u3.NotifyProps[model.AutoResponderMessageNotifyProp] = strings.Repeat("a", maxPostSize+1) _, err = ss.User().Save(rctx, &u3) require.Error(t, err, "auto responder message size should not be greater than maxPostSize") for range 49 { u := model.User{ Email: MakeEmail(), Username: model.NewUsername(), } _, err = ss.User().Save(rctx, &u) require.NoError(t, err, "couldn't save item") defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u.Id)) }() _, nErr = ss.Team().SaveMember(rctx, &model.TeamMember{TeamId: teamID, UserId: u.Id}, maxUsersPerTeam) require.NoError(t, nErr) } u2.Id = "" u2.Email = MakeEmail() u2.Username = model.NewUsername() _, err = ss.User().Save(rctx, &u2) require.NoError(t, err, "couldn't save item") defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u2.Id)) }() _, nErr = ss.Team().SaveMember(rctx, &model.TeamMember{TeamId: teamID, UserId: u1.Id}, maxUsersPerTeam) require.Error(t, nErr, "should be the limit") } func testUserStoreUpdate(t *testing.T, rctx request.CTX, ss store.Store) { t.Run("missing ID", func(t *testing.T) { missing := &model.User{} _, err := ss.User().Update(rctx, missing, false) require.Error(t, err, "Update should have failed because of missing key") }) t.Run("id change", func(t *testing.T) { newID := &model.User{ Id: model.NewId(), } _, err := ss.User().Update(rctx, newID, false) require.Error(t, err, "Update should have failed because id change") }) t.Run("email/password user", func(t *testing.T) { u1 := &model.User{ AuthService: "", Email: MakeEmail(), EmailVerified: true, } _, err := ss.User().Save(rctx, u1) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u1.Id)) }() _, nErr := ss.Team().SaveMember(rctx, &model.TeamMember{TeamId: model.NewId(), UserId: u1.Id}, -1) require.NoError(t, nErr) newEmail := MakeEmail() u1.Email = newEmail userUpdate, err := ss.User().Update(rctx, u1, false) require.NoError(t, err) require.NotNil(t, userUpdate) assert.Equal(t, newEmail, userUpdate.New.Email) assert.False(t, userUpdate.New.EmailVerified, "changing the email sets it as invalid") newEmail = MakeEmail() u1.Email = newEmail u1.EmailVerified = true userUpdate, err = ss.User().Update(rctx, u1, true) require.NoError(t, err) require.NotNil(t, userUpdate) assert.Equal(t, newEmail, userUpdate.New.Email) assert.False(t, userUpdate.New.EmailVerified, "email verification must happen via dedicated method") err = ss.User().UpdateLastPictureUpdate(u1.Id) require.NoError(t, err, "Update should not have failed") t.Run("UpdateNotifyProps", func(t *testing.T) { u1, err = ss.User().Get(context.Background(), u1.Id) require.NoError(t, err) props := u1.NotifyProps props["hello"] = "world" err = ss.User().UpdateNotifyProps(u1.Id, props) require.NoError(t, err) ss.User().InvalidateProfileCacheForUser(u1.Id) uNew, err := ss.User().Get(context.Background(), u1.Id) require.NoError(t, err) assert.Equal(t, props, uNew.NotifyProps) u4 := model.User{ Email: MakeEmail(), Username: model.NewUsername(), NotifyProps: make(map[string]string, 1), } maxPostSize := ss.Post().GetMaxPostSize() u4.NotifyProps[model.AutoResponderMessageNotifyProp] = strings.Repeat("a", maxPostSize+1) _, err = ss.User().Update(rctx, &u4, false) require.Error(t, err, "auto responder message size should not be greater than maxPostSize") err = ss.User().UpdateNotifyProps(u4.Id, u4.NotifyProps) require.Error(t, err, "auto responder message size should not be greater than maxPostSize") }) }) t.Run("LDAP user", func(t *testing.T) { u2 := &model.User{ AuthService: model.UserAuthServiceLdap, Email: MakeEmail(), EmailVerified: true, } _, err := ss.User().Save(rctx, u2) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u2.Id)) }() _, err = ss.Team().SaveMember(rctx, &model.TeamMember{TeamId: model.NewId(), UserId: u2.Id}, -1) require.NoError(t, err) newEmail := MakeEmail() u2.Email = newEmail userUpdate, err := ss.User().Update(rctx, u2, false) require.Error(t, err, "Update should have failed because you can't modify AD/LDAP fields") assert.Nil(t, userUpdate) u2.Email = newEmail userUpdate, err = ss.User().Update(rctx, u2, true) require.NoError(t, err) require.NotNil(t, userUpdate) assert.Equal(t, newEmail, userUpdate.New.Email) assert.True(t, userUpdate.New.EmailVerified) }) t.Run("gitlab user", func(t *testing.T) { u3 := &model.User{ AuthService: model.UserAuthServiceGitlab, Email: MakeEmail(), EmailVerified: true, } _, err := ss.User().Save(rctx, u3) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u3.Id)) }() _, err = ss.Team().SaveMember(rctx, &model.TeamMember{TeamId: model.NewId(), UserId: u3.Id}, -1) require.NoError(t, err) oldEmail := u3.Email newEmail := MakeEmail() u3.Email = newEmail userUpdate, err := ss.User().Update(rctx, u3, false) require.NoError(t, err, "Update should not have failed") require.NotNil(t, userUpdate) assert.Equal(t, oldEmail, userUpdate.New.Email, "Email should not have been updated as the update is not trusted") assert.True(t, userUpdate.New.EmailVerified) u3.Email = newEmail userUpdate, err = ss.User().Update(rctx, u3, true) require.NoError(t, err, "Update should not have failed") require.NotNil(t, userUpdate) assert.Equal(t, newEmail, userUpdate.New.Email, "Email should have been updated as the update is trusted") assert.True(t, userUpdate.New.EmailVerified) }) } func testUserStoreUpdateUpdateAt(t *testing.T, rctx request.CTX, ss store.Store) { u1 := &model.User{} u1.Email = MakeEmail() _, err := ss.User().Save(rctx, u1) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u1.Id)) }() _, nErr := ss.Team().SaveMember(rctx, &model.TeamMember{TeamId: model.NewId(), UserId: u1.Id}, -1) require.NoError(t, nErr) // Ensure UpdateAt has a change to be different below. time.Sleep(2 * time.Millisecond) _, err = ss.User().UpdateUpdateAt(u1.Id) require.NoError(t, err) user, err := ss.User().Get(context.Background(), u1.Id) require.NoError(t, err) require.Less(t, u1.UpdateAt, user.UpdateAt, "UpdateAt not updated correctly") } func testUserStoreUpdateFailedPasswordAttempts(t *testing.T, rctx request.CTX, ss store.Store) { u1 := &model.User{} u1.Email = MakeEmail() _, err := ss.User().Save(rctx, u1) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u1.Id)) }() _, nErr := ss.Team().SaveMember(rctx, &model.TeamMember{TeamId: model.NewId(), UserId: u1.Id}, -1) require.NoError(t, nErr) err = ss.User().UpdateFailedPasswordAttempts(u1.Id, 3) require.NoError(t, err) user, err := ss.User().Get(context.Background(), u1.Id) require.NoError(t, err) require.Equal(t, 3, user.FailedAttempts, "FailedAttempts not updated correctly") } func testUserStoreGet(t *testing.T, rctx request.CTX, ss store.Store) { u1 := &model.User{ Email: MakeEmail(), } _, err := ss.User().Save(rctx, u1) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u1.Id)) }() u2, _ := ss.User().Save(rctx, &model.User{ Email: MakeEmail(), Username: model.NewUsername(), }) _, nErr := ss.Bot().Save(&model.Bot{ UserId: u2.Id, Username: u2.Username, Description: "bot description", OwnerId: u1.Id, }) require.NoError(t, nErr) u2.IsBot = true u2.BotDescription = "bot description" defer func() { require.NoError(t, ss.Bot().PermanentDelete(u2.Id)) }() defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u2.Id)) }() _, nErr = ss.Team().SaveMember(rctx, &model.TeamMember{TeamId: model.NewId(), UserId: u1.Id}, -1) require.NoError(t, nErr) t.Run("fetch empty id", func(t *testing.T) { _, err := ss.User().Get(context.Background(), "") require.Error(t, err) }) t.Run("fetch user 1", func(t *testing.T) { actual, err := ss.User().Get(context.Background(), u1.Id) require.NoError(t, err) require.Equal(t, u1, actual) require.False(t, actual.IsBot) }) t.Run("fetch user 2, also a bot", func(t *testing.T) { actual, err := ss.User().Get(context.Background(), u2.Id) require.NoError(t, err) require.Equal(t, u2, actual) require.True(t, actual.IsBot) require.Equal(t, "bot description", actual.BotDescription) }) } func testGetAllUsingAuthService(t *testing.T, rctx request.CTX, ss store.Store) { teamID := model.NewId() u1, err := ss.User().Save(rctx, &model.User{ Email: MakeEmail(), Username: "u1" + model.NewId(), AuthService: "service", }) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u1.Id)) }() _, nErr := ss.Team().SaveMember(rctx, &model.TeamMember{TeamId: teamID, UserId: u1.Id}, -1) require.NoError(t, nErr) u2, err := ss.User().Save(rctx, &model.User{ Email: MakeEmail(), Username: "u2" + model.NewId(), AuthService: "service", }) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u2.Id)) }() _, nErr = ss.Team().SaveMember(rctx, &model.TeamMember{TeamId: teamID, UserId: u2.Id}, -1) require.NoError(t, nErr) u3, err := ss.User().Save(rctx, &model.User{ Email: MakeEmail(), Username: "u3" + model.NewId(), AuthService: "service2", }) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u3.Id)) }() _, nErr = ss.Team().SaveMember(rctx, &model.TeamMember{TeamId: teamID, UserId: u3.Id}, -1) require.NoError(t, nErr) _, nErr = ss.Bot().Save(&model.Bot{ UserId: u3.Id, Username: u3.Username, OwnerId: u1.Id, }) require.NoError(t, nErr) u3.IsBot = true defer func() { require.NoError(t, ss.Bot().PermanentDelete(u3.Id)) }() defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u3.Id)) }() t.Run("get by unknown auth service", func(t *testing.T) { users, err := ss.User().GetAllUsingAuthService("unknown") require.NoError(t, err) assert.Equal(t, []*model.User{}, users) }) t.Run("get by auth service", func(t *testing.T) { users, err := ss.User().GetAllUsingAuthService("service") require.NoError(t, err) assert.Equal(t, []*model.User{u1, u2}, users) }) t.Run("get by other auth service", func(t *testing.T) { users, err := ss.User().GetAllUsingAuthService("service2") require.NoError(t, err) assert.Equal(t, []*model.User{u3}, users) }) } func sanitized(user *model.User) *model.User { clonedUser := user.DeepCopy() clonedUser.Sanitize(map[string]bool{}) return clonedUser } func testUserStoreGetAllProfiles(t *testing.T, rctx request.CTX, ss store.Store) { u1, err := ss.User().Save(rctx, &model.User{ Email: MakeEmail(), Username: "u1" + model.NewId(), Roles: model.SystemUserRoleId, }) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u1.Id)) }() u2, err := ss.User().Save(rctx, &model.User{ Email: MakeEmail(), Username: "u2" + model.NewId(), Roles: model.SystemUserRoleId, }) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u2.Id)) }() u3, err := ss.User().Save(rctx, &model.User{ Email: MakeEmail(), Username: "u3" + model.NewId(), }) require.NoError(t, err) _, nErr := ss.Bot().Save(&model.Bot{ UserId: u3.Id, Username: u3.Username, OwnerId: u1.Id, }) require.NoError(t, nErr) u3.IsBot = true defer func() { require.NoError(t, ss.Bot().PermanentDelete(u3.Id)) }() defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u3.Id)) }() u4, err := ss.User().Save(rctx, &model.User{ Email: MakeEmail(), Username: "u4" + model.NewId(), Roles: "system_user some-other-role", }) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u4.Id)) }() u5, err := ss.User().Save(rctx, &model.User{ Email: MakeEmail(), Username: "u5" + model.NewId(), Roles: "system_admin", }) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u5.Id)) }() u6, err := ss.User().Save(rctx, &model.User{ Email: MakeEmail(), Username: "u6" + model.NewId(), DeleteAt: model.GetMillis(), Roles: "system_admin", }) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u6.Id)) }() u7, err := ss.User().Save(rctx, &model.User{ Email: MakeEmail(), Username: "u7" + model.NewId(), DeleteAt: model.GetMillis(), Roles: model.SystemUserRoleId, }) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u7.Id)) }() t.Run("get offset 0, limit 100", func(t *testing.T) { options := &model.UserGetOptions{Page: 0, PerPage: 100} actual, userErr := ss.User().GetAllProfiles(options) require.NoError(t, userErr) require.Equal(t, []*model.User{ sanitized(u1), sanitized(u2), sanitized(u3), sanitized(u4), sanitized(u5), sanitized(u6), sanitized(u7), }, actual) }) t.Run("get offset 0, limit 1", func(t *testing.T) { actual, userErr := ss.User().GetAllProfiles(&model.UserGetOptions{ Page: 0, PerPage: 1, }) require.NoError(t, userErr) require.Equal(t, []*model.User{ sanitized(u1), }, actual) }) t.Run("get all", func(t *testing.T) { actual, userErr := ss.User().GetAll() require.NoError(t, userErr) require.Equal(t, []*model.User{ u1, u2, u3, u4, u5, u6, u7, }, actual) }) t.Run("etag changes for all after user creation", func(t *testing.T) { etag := ss.User().GetEtagForAllProfiles() uNew := &model.User{} uNew.Email = MakeEmail() _, userErr := ss.User().Save(rctx, uNew) require.NoError(t, userErr) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, uNew.Id)) }() updatedEtag := ss.User().GetEtagForAllProfiles() require.NotEqual(t, etag, updatedEtag) }) t.Run("filter to system_admin role", func(t *testing.T) { actual, userErr := ss.User().GetAllProfiles(&model.UserGetOptions{ Page: 0, PerPage: 10, Role: "system_admin", }) require.NoError(t, userErr) require.Equal(t, []*model.User{ sanitized(u5), sanitized(u6), }, actual) }) t.Run("filter to system_admin role, inactive", func(t *testing.T) { actual, userErr := ss.User().GetAllProfiles(&model.UserGetOptions{ Page: 0, PerPage: 10, Role: "system_admin", Inactive: true, }) require.NoError(t, userErr) require.Equal(t, []*model.User{ sanitized(u6), }, actual) }) t.Run("filter to inactive", func(t *testing.T) { actual, userErr := ss.User().GetAllProfiles(&model.UserGetOptions{ Page: 0, PerPage: 10, Inactive: true, }) require.NoError(t, userErr) require.Equal(t, []*model.User{ sanitized(u6), sanitized(u7), }, actual) }) t.Run("filter to active", func(t *testing.T) { actual, userErr := ss.User().GetAllProfiles(&model.UserGetOptions{ Page: 0, PerPage: 10, Active: true, }) require.NoError(t, userErr) require.Equal(t, []*model.User{ sanitized(u1), sanitized(u2), sanitized(u3), sanitized(u4), sanitized(u5), }, actual) }) t.Run("try to filter to active and inactive", func(t *testing.T) { actual, userErr := ss.User().GetAllProfiles(&model.UserGetOptions{ Page: 0, PerPage: 10, Inactive: true, Active: true, }) require.NoError(t, userErr) require.Equal(t, []*model.User{ sanitized(u6), sanitized(u7), }, actual) }) t.Run("filter by UpdatedAfter", func(t *testing.T) { // Update a user to ensure we have a recent update time updateTime := model.GetMillis() u2.FirstName = "Updated" _, updateErr := ss.User().Update(rctx, u2, false) require.NoError(t, updateErr) // Query with the UpdatedAfter filter actual, userErr := ss.User().GetAllProfiles(&model.UserGetOptions{ Page: 0, PerPage: 10, UpdatedAfter: updateTime - 1, // Subtract 1 to ensure we capture the update }) require.NoError(t, userErr) require.Contains(t, actual, sanitized(u2), "User updated after the specified time should be in the results") // Query with a future time, should return no results actual, userErr = ss.User().GetAllProfiles(&model.UserGetOptions{ Page: 0, PerPage: 10, UpdatedAfter: updateTime + 10000, // Future time }) require.NoError(t, userErr) require.NotContains(t, actual, sanitized(u2), "Users updated before the specified future time should not be in the results") }) u8, err := ss.User().Save(rctx, &model.User{ Email: MakeEmail(), Username: "u8" + model.NewId(), DeleteAt: model.GetMillis(), Roles: "system_user_manager system_user", }) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u8.Id)) }() u9, err := ss.User().Save(rctx, &model.User{ Email: MakeEmail(), Username: "u9" + model.NewId(), DeleteAt: model.GetMillis(), Roles: "system_manager system_user", }) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u9.Id)) }() u10, err := ss.User().Save(rctx, &model.User{ Email: MakeEmail(), Username: "u10" + model.NewId(), DeleteAt: model.GetMillis(), Roles: "system_read_only_admin system_user", }) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u10.Id)) }() t.Run("filter by system_user_manager role", func(t *testing.T) { actual, userErr := ss.User().GetAllProfiles(&model.UserGetOptions{ Page: 0, PerPage: 10, Roles: []string{"system_user_manager"}, }) require.NoError(t, userErr) require.Equal(t, []*model.User{ sanitized(u8), }, actual) }) t.Run("filter by multiple system roles", func(t *testing.T) { actual, userErr := ss.User().GetAllProfiles(&model.UserGetOptions{ Page: 0, PerPage: 10, Roles: []string{"system_manager", "system_user_manager", "system_read_only_admin", "system_admin"}, }) require.NoError(t, userErr) require.Equal(t, []*model.User{ sanitized(u10), sanitized(u5), sanitized(u6), sanitized(u8), sanitized(u9), }, actual) }) t.Run("filter by system_user only", func(t *testing.T) { actual, userErr := ss.User().GetAllProfiles(&model.UserGetOptions{ Page: 0, PerPage: 10, Roles: []string{"system_user"}, }) require.NoError(t, userErr) require.Equal(t, []*model.User{ sanitized(u1), sanitized(u2), sanitized(u7), }, actual) }) } func testUserStoreGetProfiles(t *testing.T, rctx request.CTX, ss store.Store) { teamID := model.NewId() u1, err := ss.User().Save(rctx, &model.User{ Email: MakeEmail(), Username: "u1" + model.NewId(), }) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u1.Id)) }() _, nErr := ss.Team().SaveMember(rctx, &model.TeamMember{TeamId: teamID, UserId: u1.Id}, -1) require.NoError(t, nErr) u2, err := ss.User().Save(rctx, &model.User{ Email: MakeEmail(), Username: "u2" + model.NewId(), }) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u2.Id)) }() _, nErr = ss.Team().SaveMember(rctx, &model.TeamMember{TeamId: teamID, UserId: u2.Id}, -1) require.NoError(t, nErr) u3, err := ss.User().Save(rctx, &model.User{ Email: MakeEmail(), Username: "u3" + model.NewId(), }) require.NoError(t, err) _, nErr = ss.Bot().Save(&model.Bot{ UserId: u3.Id, Username: u3.Username, OwnerId: u1.Id, }) require.NoError(t, nErr) u3.IsBot = true defer func() { require.NoError(t, ss.Bot().PermanentDelete(u3.Id)) }() defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u3.Id)) }() _, nErr = ss.Team().SaveMember(rctx, &model.TeamMember{TeamId: teamID, UserId: u3.Id}, -1) require.NoError(t, nErr) u4, err := ss.User().Save(rctx, &model.User{ Email: MakeEmail(), Username: "u4" + model.NewId(), Roles: "system_admin", }) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u4.Id)) }() _, nErr = ss.Team().SaveMember(rctx, &model.TeamMember{TeamId: teamID, UserId: u4.Id}, -1) require.NoError(t, nErr) u5, err := ss.User().Save(rctx, &model.User{ Email: MakeEmail(), Username: "u5" + model.NewId(), DeleteAt: model.GetMillis(), }) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u5.Id)) }() _, nErr = ss.Team().SaveMember(rctx, &model.TeamMember{TeamId: teamID, UserId: u5.Id}, -1) require.NoError(t, nErr) t.Run("get page 0, perPage 100", func(t *testing.T) { actual, err := ss.User().GetProfiles(&model.UserGetOptions{ InTeamId: teamID, Page: 0, PerPage: 100, }) require.NoError(t, err) require.Equal(t, []*model.User{ sanitized(u1), sanitized(u2), sanitized(u3), sanitized(u4), sanitized(u5), }, actual) }) t.Run("get page 0, perPage 1", func(t *testing.T) { actual, err := ss.User().GetProfiles(&model.UserGetOptions{ InTeamId: teamID, Page: 0, PerPage: 1, }) require.NoError(t, err) require.Equal(t, []*model.User{sanitized(u1)}, actual) }) t.Run("get unknown team id", func(t *testing.T) { actual, err := ss.User().GetProfiles(&model.UserGetOptions{ InTeamId: "123", Page: 0, PerPage: 100, }) require.NoError(t, err) require.Equal(t, []*model.User{}, actual) }) t.Run("etag changes for all after user creation", func(t *testing.T) { etag := ss.User().GetEtagForProfiles(teamID) uNew := &model.User{} uNew.Email = MakeEmail() _, err := ss.User().Save(rctx, uNew) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, uNew.Id)) }() _, nErr = ss.Team().SaveMember(rctx, &model.TeamMember{TeamId: teamID, UserId: uNew.Id}, -1) require.NoError(t, nErr) updatedEtag := ss.User().GetEtagForProfiles(teamID) require.NotEqual(t, etag, updatedEtag) }) t.Run("filter to system_admin role", func(t *testing.T) { actual, err := ss.User().GetProfiles(&model.UserGetOptions{ InTeamId: teamID, Page: 0, PerPage: 10, Role: "system_admin", }) require.NoError(t, err) require.Equal(t, []*model.User{ sanitized(u4), }, actual) }) t.Run("filter to inactive", func(t *testing.T) { actual, err := ss.User().GetProfiles(&model.UserGetOptions{ InTeamId: teamID, Page: 0, PerPage: 10, Inactive: true, }) require.NoError(t, err) require.Equal(t, []*model.User{ sanitized(u5), }, actual) }) t.Run("filter to active", func(t *testing.T) { actual, err := ss.User().GetProfiles(&model.UserGetOptions{ InTeamId: teamID, Page: 0, PerPage: 10, Active: true, }) require.NoError(t, err) require.Equal(t, []*model.User{ sanitized(u1), sanitized(u2), sanitized(u3), sanitized(u4), }, actual) }) t.Run("try to filter to active and inactive", func(t *testing.T) { actual, err := ss.User().GetProfiles(&model.UserGetOptions{ InTeamId: teamID, Page: 0, PerPage: 10, Inactive: true, Active: true, }) require.NoError(t, err) require.Equal(t, []*model.User{ sanitized(u5), }, actual) }) } func testUserStoreGetProfilesInChannel(t *testing.T, rctx request.CTX, ss store.Store) { teamID := model.NewId() u1, err := ss.User().Save(rctx, &model.User{ Email: MakeEmail(), Username: "u1" + model.NewId(), }) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u1.Id)) }() _, nErr := ss.Team().SaveMember(rctx, &model.TeamMember{TeamId: teamID, UserId: u1.Id}, -1) require.NoError(t, nErr) u2, err := ss.User().Save(rctx, &model.User{ Email: MakeEmail(), Username: "u2" + model.NewId(), }) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u2.Id)) }() _, nErr = ss.Team().SaveMember(rctx, &model.TeamMember{TeamId: teamID, UserId: u2.Id}, -1) require.NoError(t, nErr) u3, err := ss.User().Save(rctx, &model.User{ Email: MakeEmail(), Username: "u3" + model.NewId(), }) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u3.Id)) }() _, nErr = ss.Team().SaveMember(rctx, &model.TeamMember{TeamId: teamID, UserId: u3.Id}, -1) require.NoError(t, nErr) _, nErr = ss.Bot().Save(&model.Bot{ UserId: u3.Id, Username: u3.Username, OwnerId: u1.Id, }) require.NoError(t, nErr) u3.IsBot = true defer func() { require.NoError(t, ss.Bot().PermanentDelete(u3.Id)) }() u4, err := ss.User().Save(rctx, &model.User{ Email: MakeEmail(), Username: "u4" + model.NewId(), }) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u4.Id)) }() _, nErr = ss.Team().SaveMember(rctx, &model.TeamMember{TeamId: teamID, UserId: u4.Id}, -1) require.NoError(t, nErr) ch1 := &model.Channel{ TeamId: teamID, DisplayName: "Profiles in channel", Name: "profiles-" + model.NewId(), Type: model.ChannelTypeOpen, } c1, nErr := ss.Channel().Save(rctx, ch1, -1) require.NoError(t, nErr) ch2 := &model.Channel{ TeamId: teamID, DisplayName: "Profiles in private", Name: "profiles-" + model.NewId(), Type: model.ChannelTypePrivate, } c2, nErr := ss.Channel().Save(rctx, ch2, -1) require.NoError(t, nErr) _, nErr = ss.Channel().SaveMember(rctx, &model.ChannelMember{ ChannelId: c1.Id, UserId: u1.Id, NotifyProps: model.GetDefaultChannelNotifyProps(), }) require.NoError(t, nErr) _, nErr = ss.Channel().SaveMember(rctx, &model.ChannelMember{ ChannelId: c1.Id, UserId: u2.Id, NotifyProps: model.GetDefaultChannelNotifyProps(), }) require.NoError(t, nErr) _, nErr = ss.Channel().SaveMember(rctx, &model.ChannelMember{ ChannelId: c1.Id, UserId: u3.Id, NotifyProps: model.GetDefaultChannelNotifyProps(), }) require.NoError(t, nErr) _, nErr = ss.Channel().SaveMember(rctx, &model.ChannelMember{ ChannelId: c1.Id, UserId: u4.Id, NotifyProps: model.GetDefaultChannelNotifyProps(), }) require.NoError(t, nErr) u4.DeleteAt = 1 _, err = ss.User().Update(rctx, u4, true) require.NoError(t, err) _, nErr = ss.Channel().SaveMember(rctx, &model.ChannelMember{ ChannelId: c2.Id, UserId: u1.Id, NotifyProps: model.GetDefaultChannelNotifyProps(), }) require.NoError(t, nErr) t.Run("get all users in channel 1, offset 0, limit 100", func(t *testing.T) { users, err := ss.User().GetProfilesInChannel(&model.UserGetOptions{ InChannelId: c1.Id, Page: 0, PerPage: 100, }) require.NoError(t, err) assert.Equal(t, []*model.User{sanitized(u1), sanitized(u2), sanitized(u3), sanitized(u4)}, users) }) t.Run("get only active users in channel 1, offset 0, limit 100", func(t *testing.T) { users, err := ss.User().GetProfilesInChannel(&model.UserGetOptions{ InChannelId: c1.Id, Page: 0, PerPage: 100, Active: true, }) require.NoError(t, err) assert.Equal(t, []*model.User{sanitized(u1), sanitized(u2), sanitized(u3)}, users) }) t.Run("get inactive users in channel 1, offset 0, limit 100", func(t *testing.T) { users, err := ss.User().GetProfilesInChannel(&model.UserGetOptions{ InChannelId: c1.Id, Page: 0, PerPage: 100, Inactive: true, }) require.NoError(t, err) assert.Equal(t, []*model.User{sanitized(u4)}, users) }) t.Run("get in channel 1, offset 1, limit 2", func(t *testing.T) { users, err := ss.User().GetProfilesInChannel(&model.UserGetOptions{ InChannelId: c1.Id, Page: 1, PerPage: 1, }) require.NoError(t, err) usersP2, err2 := ss.User().GetProfilesInChannel(&model.UserGetOptions{ InChannelId: c1.Id, Page: 2, PerPage: 1, }) require.NoError(t, err2) users = append(users, usersP2...) assert.Equal(t, []*model.User{sanitized(u2), sanitized(u3)}, users) }) t.Run("get in channel 2, offset 0, limit 1", func(t *testing.T) { users, err := ss.User().GetProfilesInChannel(&model.UserGetOptions{ InChannelId: c2.Id, Page: 0, PerPage: 1, }) require.NoError(t, err) assert.Equal(t, []*model.User{sanitized(u1)}, users) }) t.Run("Filter by channel members and channel admins", func(t *testing.T) { // save admin for c1 user2Admin, err := ss.User().Save(rctx, &model.User{ Email: MakeEmail(), Username: "bbb" + model.NewId(), }) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, user2Admin.Id)) }() _, nErr = ss.Team().SaveMember(rctx, &model.TeamMember{TeamId: teamID, UserId: user2Admin.Id}, -1) require.NoError(t, nErr) _, nErr = ss.Channel().SaveMember(rctx, &model.ChannelMember{ ChannelId: c1.Id, UserId: user2Admin.Id, NotifyProps: model.GetDefaultChannelNotifyProps(), ExplicitRoles: "channel_admin", }) require.NoError(t, nErr) ss.Channel().UpdateMembersRole(c1.Id, []string{user2Admin.Id}) users, err := ss.User().GetProfilesInChannel(&model.UserGetOptions{ InChannelId: c1.Id, ChannelRoles: []string{model.ChannelAdminRoleId}, Page: 0, PerPage: 5, }) require.NoError(t, err) assert.Equal(t, user2Admin.Id, users[0].Id) }) } func testUserStoreGetProfilesInChannelByAdmin(t *testing.T, rctx request.CTX, ss store.Store, s SqlStore) { cleanupStatusStore(t, s) teamID := model.NewId() user1, err := ss.User().Save(rctx, &model.User{ Email: MakeEmail(), Username: "aaa" + model.NewId(), }) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, user1.Id)) }() _, nErr := ss.Team().SaveMember(rctx, &model.TeamMember{TeamId: teamID, UserId: user1.Id}, -1) require.NoError(t, nErr) user2Admin, err := ss.User().Save(rctx, &model.User{ Email: MakeEmail(), Username: "bbb" + model.NewId(), }) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, user2Admin.Id)) }() _, nErr = ss.Team().SaveMember(rctx, &model.TeamMember{TeamId: teamID, UserId: user2Admin.Id}, -1) require.NoError(t, nErr) user3, err := ss.User().Save(rctx, &model.User{ Email: MakeEmail(), Username: "ccc" + model.NewId(), }) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, user3.Id)) }() _, nErr = ss.Team().SaveMember(rctx, &model.TeamMember{TeamId: teamID, UserId: user3.Id}, -1) require.NoError(t, nErr) ch1 := &model.Channel{ TeamId: teamID, DisplayName: "Profiles in channel by admin", Name: "profiles-" + model.NewId(), Type: model.ChannelTypeOpen, } c1, nErr := ss.Channel().Save(rctx, ch1, -1) require.NoError(t, nErr) _, nErr = ss.Channel().SaveMember(rctx, &model.ChannelMember{ ChannelId: c1.Id, UserId: user1.Id, NotifyProps: model.GetDefaultChannelNotifyProps(), }) require.NoError(t, nErr) _, nErr = ss.Channel().SaveMember(rctx, &model.ChannelMember{ ChannelId: c1.Id, UserId: user2Admin.Id, NotifyProps: model.GetDefaultChannelNotifyProps(), ExplicitRoles: "channel_admin", }) require.NoError(t, nErr) ss.Channel().UpdateMembersRole(c1.Id, []string{user2Admin.Id}) _, nErr = ss.Channel().SaveMember(rctx, &model.ChannelMember{ ChannelId: c1.Id, UserId: user3.Id, NotifyProps: model.GetDefaultChannelNotifyProps(), }) require.NoError(t, nErr) t.Run("get users in admin, offset 0, limit 100", func(t *testing.T) { users, err := ss.User().GetProfilesInChannelByAdmin(&model.UserGetOptions{ InChannelId: c1.Id, Page: 0, PerPage: 100, }) require.NoError(t, err) require.Len(t, users, 3) require.Equal(t, user2Admin.Username, users[0].Username) require.Equal(t, user1.Username, users[1].Username) require.Equal(t, user3.Username, users[2].Username) }) } func testUserStoreGetProfilesInChannelByStatus(t *testing.T, rctx request.CTX, ss store.Store, s SqlStore) { cleanupStatusStore(t, s) teamID := model.NewId() u1, err := ss.User().Save(rctx, &model.User{ Email: MakeEmail(), Username: "u1" + model.NewId(), }) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u1.Id)) }() _, nErr := ss.Team().SaveMember(rctx, &model.TeamMember{TeamId: teamID, UserId: u1.Id}, -1) require.NoError(t, nErr) u2, err := ss.User().Save(rctx, &model.User{ Email: MakeEmail(), Username: "u2" + model.NewId(), }) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u2.Id)) }() _, nErr = ss.Team().SaveMember(rctx, &model.TeamMember{TeamId: teamID, UserId: u2.Id}, -1) require.NoError(t, nErr) u3, err := ss.User().Save(rctx, &model.User{ Email: MakeEmail(), Username: "u3" + model.NewId(), }) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u3.Id)) }() _, nErr = ss.Team().SaveMember(rctx, &model.TeamMember{TeamId: teamID, UserId: u3.Id}, -1) require.NoError(t, nErr) _, nErr = ss.Bot().Save(&model.Bot{ UserId: u3.Id, Username: u3.Username, OwnerId: u1.Id, }) require.NoError(t, nErr) u3.IsBot = true defer func() { require.NoError(t, ss.Bot().PermanentDelete(u3.Id)) }() u4, err := ss.User().Save(rctx, &model.User{ Email: MakeEmail(), Username: "u4" + model.NewId(), }) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u4.Id)) }() _, nErr = ss.Team().SaveMember(rctx, &model.TeamMember{TeamId: teamID, UserId: u4.Id}, -1) require.NoError(t, nErr) ch1 := &model.Channel{ TeamId: teamID, DisplayName: "Profiles in channel", Name: "profiles-" + model.NewId(), Type: model.ChannelTypeOpen, } c1, nErr := ss.Channel().Save(rctx, ch1, -1) require.NoError(t, nErr) ch2 := &model.Channel{ TeamId: teamID, DisplayName: "Profiles in private", Name: "profiles-" + model.NewId(), Type: model.ChannelTypePrivate, } c2, nErr := ss.Channel().Save(rctx, ch2, -1) require.NoError(t, nErr) _, nErr = ss.Channel().SaveMember(rctx, &model.ChannelMember{ ChannelId: c1.Id, UserId: u1.Id, NotifyProps: model.GetDefaultChannelNotifyProps(), }) require.NoError(t, nErr) _, nErr = ss.Channel().SaveMember(rctx, &model.ChannelMember{ ChannelId: c1.Id, UserId: u2.Id, NotifyProps: model.GetDefaultChannelNotifyProps(), }) require.NoError(t, nErr) _, nErr = ss.Channel().SaveMember(rctx, &model.ChannelMember{ ChannelId: c1.Id, UserId: u3.Id, NotifyProps: model.GetDefaultChannelNotifyProps(), }) require.NoError(t, nErr) _, nErr = ss.Channel().SaveMember(rctx, &model.ChannelMember{ ChannelId: c1.Id, UserId: u4.Id, NotifyProps: model.GetDefaultChannelNotifyProps(), }) require.NoError(t, nErr) u4.DeleteAt = 1 _, err = ss.User().Update(rctx, u4, true) require.NoError(t, err) _, nErr = ss.Channel().SaveMember(rctx, &model.ChannelMember{ ChannelId: c2.Id, UserId: u1.Id, NotifyProps: model.GetDefaultChannelNotifyProps(), }) require.NoError(t, nErr) require.NoError(t, ss.Status().SaveOrUpdate(&model.Status{ UserId: u1.Id, Status: model.StatusDnd, })) require.NoError(t, ss.Status().SaveOrUpdate(&model.Status{ UserId: u2.Id, Status: model.StatusAway, })) require.NoError(t, ss.Status().SaveOrUpdate(&model.Status{ UserId: u3.Id, Status: model.StatusOnline, })) t.Run("get all users in channel 1, offset 0, limit 100", func(t *testing.T) { users, err := ss.User().GetProfilesInChannel(&model.UserGetOptions{ InChannelId: c1.Id, Page: 0, PerPage: 100, }) require.NoError(t, err) assert.Equal(t, []*model.User{sanitized(u1), sanitized(u2), sanitized(u3), sanitized(u4)}, users) }) t.Run("get active in channel 1 by status, offset 0, limit 100", func(t *testing.T) { users, err := ss.User().GetProfilesInChannelByStatus(&model.UserGetOptions{ InChannelId: c1.Id, Page: 0, PerPage: 100, Active: true, }) require.NoError(t, err) assert.Equal(t, []*model.User{sanitized(u3), sanitized(u2), sanitized(u1)}, users) }) t.Run("get inactive users in channel 1, offset 0, limit 100", func(t *testing.T) { users, err := ss.User().GetProfilesInChannel(&model.UserGetOptions{ InChannelId: c1.Id, Page: 0, PerPage: 100, Inactive: true, }) require.NoError(t, err) assert.Equal(t, []*model.User{sanitized(u4)}, users) }) t.Run("get in channel 2 by status, offset 0, limit 1", func(t *testing.T) { users, err := ss.User().GetProfilesInChannelByStatus(&model.UserGetOptions{ InChannelId: c2.Id, Page: 0, PerPage: 1, }) require.NoError(t, err) assert.Equal(t, []*model.User{sanitized(u1)}, users) }) } func testUserStoreGetProfilesWithoutTeam(t *testing.T, rctx request.CTX, ss store.Store) { teamID := model.NewId() u1, err := ss.User().Save(rctx, &model.User{ Email: MakeEmail(), Username: "u1" + model.NewId(), }) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u1.Id)) }() _, nErr := ss.Team().SaveMember(rctx, &model.TeamMember{TeamId: teamID, UserId: u1.Id}, -1) require.NoError(t, nErr) u2, err := ss.User().Save(rctx, &model.User{ Email: MakeEmail(), Username: "u2" + model.NewId(), }) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u2.Id)) }() u3, err := ss.User().Save(rctx, &model.User{ Email: MakeEmail(), Username: "u3" + model.NewId(), DeleteAt: 1, Roles: "system_admin", }) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u3.Id)) }() _, nErr = ss.Bot().Save(&model.Bot{ UserId: u3.Id, Username: u3.Username, OwnerId: u1.Id, }) require.NoError(t, nErr) u3.IsBot = true defer func() { require.NoError(t, ss.Bot().PermanentDelete(u3.Id)) }() t.Run("get, page 0, per_page 100", func(t *testing.T) { users, err := ss.User().GetProfilesWithoutTeam(&model.UserGetOptions{Page: 0, PerPage: 100}) require.NoError(t, err) assert.Equal(t, []*model.User{sanitized(u2), sanitized(u3)}, users) }) t.Run("get, page 1, per_page 1", func(t *testing.T) { users, err := ss.User().GetProfilesWithoutTeam(&model.UserGetOptions{Page: 1, PerPage: 1}) require.NoError(t, err) assert.Equal(t, []*model.User{sanitized(u3)}, users) }) t.Run("get, page 2, per_page 1", func(t *testing.T) { users, err := ss.User().GetProfilesWithoutTeam(&model.UserGetOptions{Page: 2, PerPage: 1}) require.NoError(t, err) assert.Equal(t, []*model.User{}, users) }) t.Run("get, page 0, per_page 100, inactive", func(t *testing.T) { users, err := ss.User().GetProfilesWithoutTeam(&model.UserGetOptions{Page: 0, PerPage: 100, Inactive: true}) require.NoError(t, err) assert.Equal(t, []*model.User{sanitized(u3)}, users) }) t.Run("get, page 0, per_page 100, role", func(t *testing.T) { users, err := ss.User().GetProfilesWithoutTeam(&model.UserGetOptions{Page: 0, PerPage: 100, Role: "system_admin"}) require.NoError(t, err) assert.Equal(t, []*model.User{sanitized(u3)}, users) }) } func testUserStoreGetAllProfilesInChannel(t *testing.T, rctx request.CTX, ss store.Store) { teamID := model.NewId() u1, err := ss.User().Save(rctx, &model.User{ Email: MakeEmail(), Username: "u1" + model.NewId(), }) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u1.Id)) }() _, nErr := ss.Team().SaveMember(rctx, &model.TeamMember{TeamId: teamID, UserId: u1.Id}, -1) require.NoError(t, nErr) u2, err := ss.User().Save(rctx, &model.User{ Email: MakeEmail(), Username: "u2" + model.NewId(), }) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u2.Id)) }() _, nErr = ss.Team().SaveMember(rctx, &model.TeamMember{TeamId: teamID, UserId: u2.Id}, -1) require.NoError(t, nErr) u3, err := ss.User().Save(rctx, &model.User{ Email: MakeEmail(), Username: "u3" + model.NewId(), }) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u3.Id)) }() _, nErr = ss.Team().SaveMember(rctx, &model.TeamMember{TeamId: teamID, UserId: u3.Id}, -1) require.NoError(t, nErr) _, nErr = ss.Bot().Save(&model.Bot{ UserId: u3.Id, Username: u3.Username, OwnerId: u1.Id, }) require.NoError(t, nErr) u3.IsBot = true defer func() { require.NoError(t, ss.Bot().PermanentDelete(u3.Id)) }() ch1 := &model.Channel{ TeamId: teamID, DisplayName: "Profiles in channel", Name: "profiles-" + model.NewId(), Type: model.ChannelTypeOpen, } c1, nErr := ss.Channel().Save(rctx, ch1, -1) require.NoError(t, nErr) ch2 := &model.Channel{ TeamId: teamID, DisplayName: "Profiles in private", Name: "profiles-" + model.NewId(), Type: model.ChannelTypePrivate, } c2, nErr := ss.Channel().Save(rctx, ch2, -1) require.NoError(t, nErr) _, nErr = ss.Channel().SaveMember(rctx, &model.ChannelMember{ ChannelId: c1.Id, UserId: u1.Id, NotifyProps: model.GetDefaultChannelNotifyProps(), }) require.NoError(t, nErr) _, nErr = ss.Channel().SaveMember(rctx, &model.ChannelMember{ ChannelId: c1.Id, UserId: u2.Id, NotifyProps: model.GetDefaultChannelNotifyProps(), }) require.NoError(t, nErr) _, nErr = ss.Channel().SaveMember(rctx, &model.ChannelMember{ ChannelId: c1.Id, UserId: u3.Id, NotifyProps: model.GetDefaultChannelNotifyProps(), }) require.NoError(t, nErr) _, nErr = ss.Channel().SaveMember(rctx, &model.ChannelMember{ ChannelId: c2.Id, UserId: u1.Id, NotifyProps: model.GetDefaultChannelNotifyProps(), }) require.NoError(t, nErr) t.Run("all profiles in channel 1, no caching", func(t *testing.T) { var profiles map[string]*model.User profiles, err = ss.User().GetAllProfilesInChannel(context.Background(), c1.Id, false) require.NoError(t, err) assert.Equal(t, map[string]*model.User{ u1.Id: sanitized(u1), u2.Id: sanitized(u2), u3.Id: sanitized(u3), }, profiles) }) t.Run("all profiles in channel 2, no caching", func(t *testing.T) { var profiles map[string]*model.User profiles, err = ss.User().GetAllProfilesInChannel(context.Background(), c2.Id, false) require.NoError(t, err) assert.Equal(t, map[string]*model.User{ u1.Id: sanitized(u1), }, profiles) }) t.Run("all profiles in channel 2, caching", func(t *testing.T) { var profiles map[string]*model.User profiles, err = ss.User().GetAllProfilesInChannel(context.Background(), c2.Id, true) require.NoError(t, err) assert.Equal(t, map[string]*model.User{ u1.Id: sanitized(u1), }, profiles) }) t.Run("all profiles in channel 2, caching [repeated]", func(t *testing.T) { var profiles map[string]*model.User profiles, err = ss.User().GetAllProfilesInChannel(context.Background(), c2.Id, true) require.NoError(t, err) assert.Equal(t, map[string]*model.User{ u1.Id: sanitized(u1), }, profiles) }) ss.User().InvalidateProfilesInChannelCacheByUser(u1.Id) ss.User().InvalidateProfilesInChannelCache(c2.Id) } func testUserStoreGetProfilesNotInChannel(t *testing.T, rctx request.CTX, ss store.Store) { teamID := model.NewId() u1, err := ss.User().Save(rctx, &model.User{ Email: MakeEmail(), Username: "u1" + model.NewId(), }) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u1.Id)) }() _, nErr := ss.Team().SaveMember(rctx, &model.TeamMember{TeamId: teamID, UserId: u1.Id}, -1) require.NoError(t, nErr) u2, err := ss.User().Save(rctx, &model.User{ Email: MakeEmail(), Username: "u2" + model.NewId(), }) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u2.Id)) }() _, nErr = ss.Team().SaveMember(rctx, &model.TeamMember{TeamId: teamID, UserId: u2.Id}, -1) require.NoError(t, nErr) u3, err := ss.User().Save(rctx, &model.User{ Email: MakeEmail(), Username: "u3" + model.NewId(), }) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u3.Id)) }() _, nErr = ss.Team().SaveMember(rctx, &model.TeamMember{TeamId: teamID, UserId: u3.Id}, -1) require.NoError(t, nErr) _, nErr = ss.Bot().Save(&model.Bot{ UserId: u3.Id, Username: u3.Username, OwnerId: u1.Id, }) require.NoError(t, nErr) u3.IsBot = true defer func() { require.NoError(t, ss.Bot().PermanentDelete(u3.Id)) }() ch1 := &model.Channel{ TeamId: teamID, DisplayName: "Profiles in channel", Name: "profiles-" + model.NewId(), Type: model.ChannelTypeOpen, } c1, nErr := ss.Channel().Save(rctx, ch1, -1) require.NoError(t, nErr) ch2 := &model.Channel{ TeamId: teamID, DisplayName: "Profiles in private", Name: "profiles-" + model.NewId(), Type: model.ChannelTypePrivate, } c2, nErr := ss.Channel().Save(rctx, ch2, -1) require.NoError(t, nErr) t.Run("get team 1, channel 1, offset 0, limit 100", func(t *testing.T) { var profiles []*model.User profiles, err = ss.User().GetProfilesNotInChannel(teamID, c1.Id, false, 0, 100, nil) require.NoError(t, err) assert.Equal(t, []*model.User{ sanitized(u1), sanitized(u2), sanitized(u3), }, profiles) }) t.Run("get team 1, channel 2, offset 0, limit 100", func(t *testing.T) { var profiles []*model.User profiles, err = ss.User().GetProfilesNotInChannel(teamID, c2.Id, false, 0, 100, nil) require.NoError(t, err) assert.Equal(t, []*model.User{ sanitized(u1), sanitized(u2), sanitized(u3), }, profiles) }) _, nErr = ss.Channel().SaveMember(rctx, &model.ChannelMember{ ChannelId: c1.Id, UserId: u1.Id, NotifyProps: model.GetDefaultChannelNotifyProps(), }) require.NoError(t, nErr) _, nErr = ss.Channel().SaveMember(rctx, &model.ChannelMember{ ChannelId: c1.Id, UserId: u2.Id, NotifyProps: model.GetDefaultChannelNotifyProps(), }) require.NoError(t, nErr) _, nErr = ss.Channel().SaveMember(rctx, &model.ChannelMember{ ChannelId: c1.Id, UserId: u3.Id, NotifyProps: model.GetDefaultChannelNotifyProps(), }) require.NoError(t, nErr) _, nErr = ss.Channel().SaveMember(rctx, &model.ChannelMember{ ChannelId: c2.Id, UserId: u1.Id, NotifyProps: model.GetDefaultChannelNotifyProps(), }) require.NoError(t, nErr) t.Run("get team 1, channel 1, offset 0, limit 100, after update", func(t *testing.T) { var profiles []*model.User profiles, err = ss.User().GetProfilesNotInChannel(teamID, c1.Id, false, 0, 100, nil) require.NoError(t, err) assert.Equal(t, []*model.User{}, profiles) }) t.Run("get team 1, channel 2, offset 0, limit 100, after update", func(t *testing.T) { var profiles []*model.User profiles, err = ss.User().GetProfilesNotInChannel(teamID, c2.Id, false, 0, 100, nil) require.NoError(t, err) assert.Equal(t, []*model.User{ sanitized(u2), sanitized(u3), }, profiles) }) t.Run("get team 1, channel 2, offset 0, limit 0, setting group constrained when it's not", func(t *testing.T) { var profiles []*model.User profiles, err = ss.User().GetProfilesNotInChannel(teamID, c2.Id, true, 0, 100, nil) require.NoError(t, err) assert.Empty(t, profiles) }) // create a group group, err := ss.Group().Create(&model.Group{ Name: model.NewPointer("n_" + model.NewId()), DisplayName: "dn_" + model.NewId(), Source: model.GroupSourceLdap, RemoteId: model.NewPointer("ri_" + model.NewId()), }) require.NoError(t, err) // add two members to the group for _, u := range []*model.User{u1, u2} { _, err = ss.Group().UpsertMember(group.Id, u.Id) require.NoError(t, err) } // associate the group with the channel _, err = ss.Group().CreateGroupSyncable(&model.GroupSyncable{ GroupId: group.Id, SyncableId: c2.Id, Type: model.GroupSyncableTypeChannel, }) require.NoError(t, err) t.Run("get team 1, channel 2, offset 0, limit 0, setting group constrained", func(t *testing.T) { profiles, err := ss.User().GetProfilesNotInChannel(teamID, c2.Id, true, 0, 100, nil) require.NoError(t, err) assert.Equal(t, []*model.User{ sanitized(u2), }, profiles) }) } func testUserStoreGetProfilesByIds(t *testing.T, rctx request.CTX, ss store.Store) { teamID := model.NewId() u1, err := ss.User().Save(rctx, &model.User{ Email: MakeEmail(), Username: "u1" + model.NewId(), }) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u1.Id)) }() _, nErr := ss.Team().SaveMember(rctx, &model.TeamMember{TeamId: teamID, UserId: u1.Id}, -1) require.NoError(t, nErr) u2, err := ss.User().Save(rctx, &model.User{ Email: MakeEmail(), Username: "u2" + model.NewId(), }) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u2.Id)) }() _, nErr = ss.Team().SaveMember(rctx, &model.TeamMember{TeamId: teamID, UserId: u2.Id}, -1) require.NoError(t, nErr) time.Sleep(time.Millisecond) u3, err := ss.User().Save(rctx, &model.User{ Email: MakeEmail(), Username: "u3" + model.NewId(), }) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u3.Id)) }() _, nErr = ss.Team().SaveMember(rctx, &model.TeamMember{TeamId: teamID, UserId: u3.Id}, -1) require.NoError(t, nErr) _, nErr = ss.Bot().Save(&model.Bot{ UserId: u3.Id, Username: u3.Username, OwnerId: u1.Id, }) require.NoError(t, nErr) u3.IsBot = true defer func() { require.NoError(t, ss.Bot().PermanentDelete(u3.Id)) }() u4, err := ss.User().Save(rctx, &model.User{ Email: MakeEmail(), Username: "u4" + model.NewId(), }) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u4.Id)) }() t.Run("get u1 by id, no caching", func(t *testing.T) { users, err := ss.User().GetProfileByIds(rctx, []string{u1.Id}, nil, false) require.NoError(t, err) assert.Equal(t, []*model.User{u1}, users) }) t.Run("get u1 by id, caching", func(t *testing.T) { users, err := ss.User().GetProfileByIds(rctx, []string{u1.Id}, nil, true) require.NoError(t, err) assert.Equal(t, []*model.User{u1}, users) }) t.Run("get u1, u2, u3 by id, no caching", func(t *testing.T) { users, err := ss.User().GetProfileByIds(rctx, []string{u1.Id, u2.Id, u3.Id}, nil, false) require.NoError(t, err) assert.Equal(t, []*model.User{u1, u2, u3}, users) }) t.Run("get u1, u2, u3 by id, caching", func(t *testing.T) { users, err := ss.User().GetProfileByIds(rctx, []string{u1.Id, u2.Id, u3.Id}, nil, true) require.NoError(t, err) assert.Equal(t, []*model.User{u1, u2, u3}, users) }) t.Run("get unknown id, caching", func(t *testing.T) { users, err := ss.User().GetProfileByIds(rctx, []string{"123"}, nil, true) require.NoError(t, err) assert.Equal(t, []*model.User{}, users) }) t.Run("should only return users with UpdateAt greater than the since time", func(t *testing.T) { users, err := ss.User().GetProfileByIds(rctx, []string{u1.Id, u2.Id, u3.Id, u4.Id}, &store.UserGetByIdsOpts{ Since: u2.CreateAt, }, true) require.NoError(t, err) // u3 comes from the cache, and u4 does not assert.Equal(t, []*model.User{u3, u4}, users) }) } func testUserStoreGetProfileByGroupChannelIdsForUser(t *testing.T, rctx request.CTX, ss store.Store) { u1, err := ss.User().Save(rctx, &model.User{ Email: MakeEmail(), Username: "u1" + model.NewId(), }) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u1.Id)) }() u2, err := ss.User().Save(rctx, &model.User{ Email: MakeEmail(), Username: "u2" + model.NewId(), }) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u2.Id)) }() u3, err := ss.User().Save(rctx, &model.User{ Email: MakeEmail(), Username: "u3" + model.NewId(), }) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u3.Id)) }() u4, err := ss.User().Save(rctx, &model.User{ Email: MakeEmail(), Username: "u4" + model.NewId(), }) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u4.Id)) }() gc1, nErr := ss.Channel().Save(rctx, &model.Channel{ DisplayName: "Profiles in private", Name: "profiles-" + model.NewId(), Type: model.ChannelTypeGroup, }, -1) require.NoError(t, nErr) for _, uID := range []string{u1.Id, u2.Id, u3.Id} { _, nErr = ss.Channel().SaveMember(rctx, &model.ChannelMember{ ChannelId: gc1.Id, UserId: uID, NotifyProps: model.GetDefaultChannelNotifyProps(), }) require.NoError(t, nErr) } gc2, nErr := ss.Channel().Save(rctx, &model.Channel{ DisplayName: "Profiles in private", Name: "profiles-" + model.NewId(), Type: model.ChannelTypeGroup, }, -1) require.NoError(t, nErr) for _, uID := range []string{u1.Id, u3.Id, u4.Id} { _, nErr = ss.Channel().SaveMember(rctx, &model.ChannelMember{ ChannelId: gc2.Id, UserId: uID, NotifyProps: model.GetDefaultChannelNotifyProps(), }) require.NoError(t, nErr) } testCases := []struct { Name string UserID string ChannelIds []string ExpectedUserIdsByChannel map[string][]string EnsureChannelsNotInResults []string }{ { Name: "Get group 1 as user 1", UserID: u1.Id, ChannelIds: []string{gc1.Id}, ExpectedUserIdsByChannel: map[string][]string{ gc1.Id: {u2.Id, u3.Id}, }, EnsureChannelsNotInResults: []string{}, }, { Name: "Get groups 1 and 2 as user 1", UserID: u1.Id, ChannelIds: []string{gc1.Id, gc2.Id}, ExpectedUserIdsByChannel: map[string][]string{ gc1.Id: {u2.Id, u3.Id}, gc2.Id: {u3.Id, u4.Id}, }, EnsureChannelsNotInResults: []string{}, }, { Name: "Get groups 1 and 2 as user 2", UserID: u2.Id, ChannelIds: []string{gc1.Id, gc2.Id}, ExpectedUserIdsByChannel: map[string][]string{ gc1.Id: {u1.Id, u3.Id}, }, EnsureChannelsNotInResults: []string{gc2.Id}, }, } for _, tc := range testCases { t.Run(tc.Name, func(t *testing.T) { res, err := ss.User().GetProfileByGroupChannelIdsForUser(tc.UserID, tc.ChannelIds) require.NoError(t, err) for channelID, expectedUsers := range tc.ExpectedUserIdsByChannel { users, ok := res[channelID] require.True(t, ok) var userIds []string for _, user := range users { userIds = append(userIds, user.Id) } require.ElementsMatch(t, expectedUsers, userIds) } for _, channelID := range tc.EnsureChannelsNotInResults { _, ok := res[channelID] require.False(t, ok) } }) } } func testUserStoreGetProfilesByUsernames(t *testing.T, rctx request.CTX, ss store.Store) { teamID := model.NewId() team2Id := model.NewId() u1, err := ss.User().Save(rctx, &model.User{ Email: MakeEmail(), Username: "u1" + model.NewId(), }) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u1.Id)) }() _, nErr := ss.Team().SaveMember(rctx, &model.TeamMember{TeamId: teamID, UserId: u1.Id}, -1) require.NoError(t, nErr) u2, err := ss.User().Save(rctx, &model.User{ Email: MakeEmail(), Username: "u2" + model.NewId(), }) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u2.Id)) }() _, nErr = ss.Team().SaveMember(rctx, &model.TeamMember{TeamId: teamID, UserId: u2.Id}, -1) require.NoError(t, nErr) u3, err := ss.User().Save(rctx, &model.User{ Email: MakeEmail(), Username: "u3" + model.NewId(), }) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u3.Id)) }() _, nErr = ss.Team().SaveMember(rctx, &model.TeamMember{TeamId: team2Id, UserId: u3.Id}, -1) require.NoError(t, nErr) _, nErr = ss.Bot().Save(&model.Bot{ UserId: u3.Id, Username: u3.Username, OwnerId: u1.Id, }) require.NoError(t, nErr) u3.IsBot = true defer func() { require.NoError(t, ss.Bot().PermanentDelete(u3.Id)) }() t.Run("get by u1 and u2 usernames, team id 1", func(t *testing.T) { users, err := ss.User().GetProfilesByUsernames([]string{u1.Username, u2.Username}, &model.ViewUsersRestrictions{Teams: []string{teamID}}) require.NoError(t, err) assert.Equal(t, []*model.User{u1, u2}, users) }) t.Run("get by u1 username, team id 1", func(t *testing.T) { users, err := ss.User().GetProfilesByUsernames([]string{u1.Username}, &model.ViewUsersRestrictions{Teams: []string{teamID}}) require.NoError(t, err) assert.Equal(t, []*model.User{u1}, users) }) t.Run("get by u1 and u3 usernames, no team id", func(t *testing.T) { users, err := ss.User().GetProfilesByUsernames([]string{u1.Username, u3.Username}, nil) require.NoError(t, err) assert.Equal(t, []*model.User{u1, u3}, users) }) t.Run("get by u1 and u3 usernames, team id 1", func(t *testing.T) { users, err := ss.User().GetProfilesByUsernames([]string{u1.Username, u3.Username}, &model.ViewUsersRestrictions{Teams: []string{teamID}}) require.NoError(t, err) assert.Equal(t, []*model.User{u1}, users) }) t.Run("get by u1 and u3 usernames, team id 2", func(t *testing.T) { users, err := ss.User().GetProfilesByUsernames([]string{u1.Username, u3.Username}, &model.ViewUsersRestrictions{Teams: []string{team2Id}}) require.NoError(t, err) assert.Equal(t, []*model.User{u3}, users) }) } func testUserStoreGetSystemAdminProfiles(t *testing.T, rctx request.CTX, ss store.Store) { teamID := model.NewId() u1, err := ss.User().Save(rctx, &model.User{ Email: MakeEmail(), Roles: model.SystemUserRoleId + " " + model.SystemAdminRoleId, Username: "u1" + model.NewId(), }) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u1.Id)) }() _, nErr := ss.Team().SaveMember(rctx, &model.TeamMember{TeamId: teamID, UserId: u1.Id}, -1) require.NoError(t, nErr) u2, err := ss.User().Save(rctx, &model.User{ Email: MakeEmail(), Username: "u2" + model.NewId(), }) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u2.Id)) }() _, nErr = ss.Team().SaveMember(rctx, &model.TeamMember{TeamId: teamID, UserId: u2.Id}, -1) require.NoError(t, nErr) u3, err := ss.User().Save(rctx, &model.User{ Email: MakeEmail(), Roles: model.SystemUserRoleId + " " + model.SystemAdminRoleId, Username: "u3" + model.NewId(), }) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u3.Id)) }() _, nErr = ss.Team().SaveMember(rctx, &model.TeamMember{TeamId: teamID, UserId: u3.Id}, -1) require.NoError(t, nErr) _, nErr = ss.Bot().Save(&model.Bot{ UserId: u3.Id, Username: u3.Username, OwnerId: u1.Id, }) require.NoError(t, nErr) u3.IsBot = true defer func() { require.NoError(t, ss.Bot().PermanentDelete(u3.Id)) }() t.Run("all system admin profiles", func(t *testing.T) { result, userError := ss.User().GetSystemAdminProfiles() require.NoError(t, userError) assert.Equal(t, map[string]*model.User{ u1.Id: sanitized(u1), u3.Id: sanitized(u3), }, result) }) } func testUserStoreGetByEmail(t *testing.T, rctx request.CTX, ss store.Store) { teamID := model.NewId() u1, err := ss.User().Save(rctx, &model.User{ Email: MakeEmail(), Username: "u1" + model.NewId(), }) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u1.Id)) }() _, nErr := ss.Team().SaveMember(rctx, &model.TeamMember{TeamId: teamID, UserId: u1.Id}, -1) require.NoError(t, nErr) u2, err := ss.User().Save(rctx, &model.User{ Email: MakeEmail(), Username: "u2" + model.NewId(), }) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u2.Id)) }() _, nErr = ss.Team().SaveMember(rctx, &model.TeamMember{TeamId: teamID, UserId: u2.Id}, -1) require.NoError(t, nErr) u3, err := ss.User().Save(rctx, &model.User{ Email: MakeEmail(), Username: "u3" + model.NewId(), }) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u3.Id)) }() _, nErr = ss.Team().SaveMember(rctx, &model.TeamMember{TeamId: teamID, UserId: u3.Id}, -1) require.NoError(t, nErr) _, nErr = ss.Bot().Save(&model.Bot{ UserId: u3.Id, Username: u3.Username, OwnerId: u1.Id, }) require.NoError(t, nErr) u3.IsBot = true defer func() { require.NoError(t, ss.Bot().PermanentDelete(u3.Id)) }() t.Run("get u1 by email", func(t *testing.T) { u, err := ss.User().GetByEmail(u1.Email) require.NoError(t, err) assert.Equal(t, u1, u) }) t.Run("get u2 by email", func(t *testing.T) { u, err := ss.User().GetByEmail(u2.Email) require.NoError(t, err) assert.Equal(t, u2, u) }) t.Run("get u3 by email", func(t *testing.T) { u, err := ss.User().GetByEmail(u3.Email) require.NoError(t, err) assert.Equal(t, u3, u) }) t.Run("get by empty email", func(t *testing.T) { _, err := ss.User().GetByEmail("") require.Error(t, err) }) t.Run("get by unknown", func(t *testing.T) { _, err := ss.User().GetByEmail("unknown") require.Error(t, err) }) } func testUserStoreGetByAuthData(t *testing.T, rctx request.CTX, ss store.Store) { teamID := model.NewId() auth1 := model.NewId() auth3 := model.NewId() u1, err := ss.User().Save(rctx, &model.User{ Email: MakeEmail(), Username: "u1" + model.NewId(), AuthData: &auth1, AuthService: "service", }) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u1.Id)) }() _, nErr := ss.Team().SaveMember(rctx, &model.TeamMember{TeamId: teamID, UserId: u1.Id}, -1) require.NoError(t, nErr) u2, err := ss.User().Save(rctx, &model.User{ Email: MakeEmail(), Username: "u2" + model.NewId(), }) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u2.Id)) }() _, nErr = ss.Team().SaveMember(rctx, &model.TeamMember{TeamId: teamID, UserId: u2.Id}, -1) require.NoError(t, nErr) u3, err := ss.User().Save(rctx, &model.User{ Email: MakeEmail(), Username: "u3" + model.NewId(), AuthData: &auth3, AuthService: "service2", }) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u3.Id)) }() _, nErr = ss.Team().SaveMember(rctx, &model.TeamMember{TeamId: teamID, UserId: u3.Id}, -1) require.NoError(t, nErr) _, nErr = ss.Bot().Save(&model.Bot{ UserId: u3.Id, Username: u3.Username, OwnerId: u1.Id, }) require.NoError(t, nErr) u3.IsBot = true defer func() { require.NoError(t, ss.Bot().PermanentDelete(u3.Id)) }() t.Run("get by u1 auth", func(t *testing.T) { u, err := ss.User().GetByAuth(u1.AuthData, u1.AuthService) require.NoError(t, err) assert.Equal(t, u1, u) }) t.Run("get by u3 auth", func(t *testing.T) { u, err := ss.User().GetByAuth(u3.AuthData, u3.AuthService) require.NoError(t, err) assert.Equal(t, u3, u) }) t.Run("get by u1 auth, unknown service", func(t *testing.T) { _, err := ss.User().GetByAuth(u1.AuthData, "unknown") require.Error(t, err) var nfErr *store.ErrNotFound require.True(t, errors.As(err, &nfErr)) }) t.Run("get by unknown auth, u1 service", func(t *testing.T) { unknownAuth := "" _, err := ss.User().GetByAuth(&unknownAuth, u1.AuthService) require.Error(t, err) var invErr *store.ErrInvalidInput require.True(t, errors.As(err, &invErr)) }) t.Run("get by unknown auth, unknown service", func(t *testing.T) { unknownAuth := "" _, err := ss.User().GetByAuth(&unknownAuth, "unknown") require.Error(t, err) var invErr *store.ErrInvalidInput require.True(t, errors.As(err, &invErr)) }) } func testUserStoreGetByUsername(t *testing.T, rctx request.CTX, ss store.Store) { teamID := model.NewId() u1, err := ss.User().Save(rctx, &model.User{ Email: MakeEmail(), Username: "u1" + model.NewId(), }) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u1.Id)) }() _, nErr := ss.Team().SaveMember(rctx, &model.TeamMember{TeamId: teamID, UserId: u1.Id}, -1) require.NoError(t, nErr) u2, err := ss.User().Save(rctx, &model.User{ Email: MakeEmail(), Username: "u2" + model.NewId(), }) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u2.Id)) }() _, nErr = ss.Team().SaveMember(rctx, &model.TeamMember{TeamId: teamID, UserId: u2.Id}, -1) require.NoError(t, nErr) u3, err := ss.User().Save(rctx, &model.User{ Email: MakeEmail(), Username: "u3" + model.NewId(), }) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u3.Id)) }() _, nErr = ss.Team().SaveMember(rctx, &model.TeamMember{TeamId: teamID, UserId: u3.Id}, -1) require.NoError(t, nErr) _, nErr = ss.Bot().Save(&model.Bot{ UserId: u3.Id, Username: u3.Username, OwnerId: u1.Id, }) require.NoError(t, nErr) u3.IsBot = true defer func() { require.NoError(t, ss.Bot().PermanentDelete(u3.Id)) }() t.Run("get u1 by username", func(t *testing.T) { result, err := ss.User().GetByUsername(u1.Username) require.NoError(t, err) assert.Equal(t, u1, result) }) t.Run("get u2 by username", func(t *testing.T) { result, err := ss.User().GetByUsername(u2.Username) require.NoError(t, err) assert.Equal(t, u2, result) }) t.Run("get u3 by username", func(t *testing.T) { result, err := ss.User().GetByUsername(u3.Username) require.NoError(t, err) assert.Equal(t, u3, result) }) t.Run("get by empty username", func(t *testing.T) { _, err := ss.User().GetByUsername("") require.Error(t, err) var nfErr *store.ErrNotFound require.True(t, errors.As(err, &nfErr)) }) t.Run("get by unknown", func(t *testing.T) { _, err := ss.User().GetByUsername("unknown") require.Error(t, err) var nfErr *store.ErrNotFound require.True(t, errors.As(err, &nfErr)) }) } func testUserStoreGetForLogin(t *testing.T, rctx request.CTX, ss store.Store) { teamID := model.NewId() auth := model.NewId() auth2 := model.NewId() auth3 := model.NewId() u1, err := ss.User().Save(rctx, &model.User{ Email: MakeEmail(), Username: "u1" + model.NewId(), AuthService: model.UserAuthServiceGitlab, AuthData: &auth, }) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u1.Id)) }() _, nErr := ss.Team().SaveMember(rctx, &model.TeamMember{TeamId: teamID, UserId: u1.Id}, -1) require.NoError(t, nErr) u2, err := ss.User().Save(rctx, &model.User{ Email: MakeEmail(), Username: "u2" + model.NewId(), AuthService: model.UserAuthServiceLdap, AuthData: &auth2, }) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u2.Id)) }() _, nErr = ss.Team().SaveMember(rctx, &model.TeamMember{TeamId: teamID, UserId: u2.Id}, -1) require.NoError(t, nErr) u3, err := ss.User().Save(rctx, &model.User{ Email: MakeEmail(), Username: "u3" + model.NewId(), AuthService: model.UserAuthServiceLdap, AuthData: &auth3, }) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u3.Id)) }() _, nErr = ss.Team().SaveMember(rctx, &model.TeamMember{TeamId: teamID, UserId: u3.Id}, -1) require.NoError(t, nErr) _, nErr = ss.Bot().Save(&model.Bot{ UserId: u3.Id, Username: u3.Username, OwnerId: u1.Id, }) require.NoError(t, nErr) u3.IsBot = true defer func() { require.NoError(t, ss.Bot().PermanentDelete(u3.Id)) }() t.Run("get u1 by username, allow both", func(t *testing.T) { user, err := ss.User().GetForLogin(u1.Username, true, true) require.NoError(t, err) assert.Equal(t, u1, user) }) t.Run("get u1 by username, check for case issues", func(t *testing.T) { user, err := ss.User().GetForLogin(strings.ToUpper(u1.Username), true, true) require.NoError(t, err) assert.Equal(t, u1, user) }) t.Run("get u1 by username, allow only email", func(t *testing.T) { _, err := ss.User().GetForLogin(u1.Username, false, true) require.Error(t, err) require.Equal(t, "user not found", err.Error()) }) t.Run("get u1 by email, allow both", func(t *testing.T) { user, err := ss.User().GetForLogin(u1.Email, true, true) require.NoError(t, err) assert.Equal(t, u1, user) }) t.Run("get u1 by email, check for case issues", func(t *testing.T) { user, err := ss.User().GetForLogin(strings.ToUpper(u1.Email), true, true) require.NoError(t, err) assert.Equal(t, u1, user) }) t.Run("get u1 by email, allow only username", func(t *testing.T) { _, err := ss.User().GetForLogin(u1.Email, true, false) require.Error(t, err) require.Equal(t, "user not found", err.Error()) }) t.Run("get u2 by username, allow both", func(t *testing.T) { user, err := ss.User().GetForLogin(u2.Username, true, true) require.NoError(t, err) assert.Equal(t, u2, user) }) t.Run("get u2 by email, allow both", func(t *testing.T) { user, err := ss.User().GetForLogin(u2.Email, true, true) require.NoError(t, err) assert.Equal(t, u2, user) }) t.Run("get u2 by username, allow neither", func(t *testing.T) { _, err := ss.User().GetForLogin(u2.Username, false, false) require.Error(t, err) require.Equal(t, "sign in with username and email are disabled", err.Error()) }) } func testUserStoreUpdatePassword(t *testing.T, rctx request.CTX, ss store.Store) { teamID := model.NewId() u1 := &model.User{} u1.Email = MakeEmail() _, err := ss.User().Save(rctx, u1) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u1.Id)) }() _, nErr := ss.Team().SaveMember(rctx, &model.TeamMember{TeamId: teamID, UserId: u1.Id}, -1) require.NoError(t, nErr) _, err = hashers.Hash(strings.Repeat("1234567890", 8)) require.ErrorIs(t, err, hashers.ErrPasswordTooLong) hashedPassword, err := hashers.Hash("newpwd") require.NoError(t, err) err = ss.User().UpdatePassword(u1.Id, hashedPassword) require.NoError(t, err) user, err := ss.User().GetByEmail(u1.Email) require.NoError(t, err) require.Equal(t, user.Password, hashedPassword, "Password was not updated correctly") } func testUserStoreDelete(t *testing.T, rctx request.CTX, ss store.Store) { u1 := &model.User{} u1.Email = MakeEmail() _, err := ss.User().Save(rctx, u1) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u1.Id)) }() _, nErr := ss.Team().SaveMember(rctx, &model.TeamMember{TeamId: model.NewId(), UserId: u1.Id}, -1) require.NoError(t, nErr) err = ss.User().PermanentDelete(rctx, u1.Id) require.NoError(t, err) } func testUserStoreUpdateAuthData(t *testing.T, rctx request.CTX, ss store.Store) { teamID := model.NewId() u1 := &model.User{} u1.Email = MakeEmail() _, err := ss.User().Save(rctx, u1) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u1.Id)) }() _, nErr := ss.Team().SaveMember(rctx, &model.TeamMember{TeamId: teamID, UserId: u1.Id}, -1) require.NoError(t, nErr) service := "someservice" authData := model.NewId() _, err = ss.User().UpdateAuthData(u1.Id, service, &authData, "", true) require.NoError(t, err) user, err := ss.User().GetByEmail(u1.Email) require.NoError(t, err) require.Equal(t, service, user.AuthService, "AuthService was not updated correctly") require.Equal(t, authData, *user.AuthData, "AuthData was not updated correctly") require.Equal(t, "", user.Password, "Password was not cleared properly") } func testUserStoreResetAuthDataToEmailForUsers(t *testing.T, rctx request.CTX, ss store.Store) { user := &model.User{} user.Username = "user1" + model.NewId() user.Email = MakeEmail() _, err := ss.User().Save(rctx, user) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, user.Id)) }() resetAuthDataToID := func() { _, err = ss.User().UpdateAuthData( user.Id, model.UserAuthServiceSaml, model.NewPointer("some-id"), "", false) require.NoError(t, err) } resetAuthDataToID() // dry run numAffected, err := ss.User().ResetAuthDataToEmailForUsers(model.UserAuthServiceSaml, nil, false, true) require.NoError(t, err) require.Equal(t, 1, numAffected) // real run numAffected, err = ss.User().ResetAuthDataToEmailForUsers(model.UserAuthServiceSaml, nil, false, false) require.NoError(t, err) require.Equal(t, 1, numAffected) user, appErr := ss.User().Get(context.Background(), user.Id) require.NoError(t, appErr) require.Equal(t, *user.AuthData, user.Email) resetAuthDataToID() // with specific user IDs numAffected, err = ss.User().ResetAuthDataToEmailForUsers(model.UserAuthServiceSaml, []string{model.NewId()}, false, true) require.NoError(t, err) require.Equal(t, 0, numAffected) numAffected, err = ss.User().ResetAuthDataToEmailForUsers(model.UserAuthServiceSaml, []string{user.Id}, false, true) require.NoError(t, err) require.Equal(t, 1, numAffected) // delete user user.DeleteAt = model.GetMillisForTime(time.Now()) ss.User().Update(rctx, user, true) // without deleted user numAffected, err = ss.User().ResetAuthDataToEmailForUsers(model.UserAuthServiceSaml, nil, false, true) require.NoError(t, err) require.Equal(t, 0, numAffected) // with deleted user numAffected, err = ss.User().ResetAuthDataToEmailForUsers(model.UserAuthServiceSaml, nil, true, true) require.NoError(t, err) require.Equal(t, 1, numAffected) } func testUserUnreadCount(t *testing.T, rctx request.CTX, ss store.Store) { teamID := model.NewId() c1 := model.Channel{} c1.TeamId = teamID c1.DisplayName = "Unread Messages" c1.Name = "unread-messages-" + model.NewId() c1.Type = model.ChannelTypeOpen c2 := model.Channel{} c2.TeamId = teamID c2.DisplayName = "Unread Direct" c2.Name = model.GetDMNameFromIds(NewTestID(), NewTestID()) c2.Type = model.ChannelTypeDirect u1 := &model.User{} u1.Username = "user1" + model.NewId() u1.Email = MakeEmail() _, err := ss.User().Save(rctx, u1) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u1.Id)) }() _, nErr := ss.Team().SaveMember(rctx, &model.TeamMember{TeamId: teamID, UserId: u1.Id}, -1) require.NoError(t, nErr) u2 := &model.User{} u2.Email = MakeEmail() u2.Username = "user2" + model.NewId() _, err = ss.User().Save(rctx, u2) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u2.Id)) }() _, nErr = ss.Team().SaveMember(rctx, &model.TeamMember{TeamId: teamID, UserId: u2.Id}, -1) require.NoError(t, nErr) u3 := &model.User{} u3.Email = MakeEmail() u3.Username = "user3" + model.NewId() _, err = ss.User().Save(rctx, u3) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u3.Id)) }() _, nErr = ss.Team().SaveMember(rctx, &model.TeamMember{TeamId: teamID, UserId: u3.Id}, -1) require.NoError(t, nErr) _, nErr = ss.Channel().Save(rctx, &c1, -1) require.NoError(t, nErr, "couldn't save item") m1 := model.ChannelMember{} m1.ChannelId = c1.Id m1.UserId = u1.Id m1.NotifyProps = model.GetDefaultChannelNotifyProps() m2 := model.ChannelMember{} m2.ChannelId = c1.Id m2.UserId = u2.Id m2.NotifyProps = model.GetDefaultChannelNotifyProps() _, nErr = ss.Channel().SaveMember(rctx, &m2) require.NoError(t, nErr) m3 := model.ChannelMember{} m3.ChannelId = c1.Id m3.UserId = u3.Id m3.NotifyProps = model.GetDefaultChannelNotifyProps() _, nErr = ss.Channel().SaveMember(rctx, &m3) require.NoError(t, nErr) m1.ChannelId = c2.Id m2.ChannelId = c2.Id _, nErr = ss.Channel().SaveDirectChannel(rctx, &c2, &m1, &m2) require.NoError(t, nErr, "couldn't save direct channel") p1 := model.Post{} p1.ChannelId = c1.Id p1.UserId = u1.Id p1.Message = "this is a message for @" + u2.Username + " and " + "@" + u3.Username // Post one message with mention to open channel _, nErr = ss.Post().Save(rctx, &p1) require.NoError(t, nErr) nErr = ss.Channel().IncrementMentionCount(c1.Id, []string{u2.Id, u3.Id}, false, false) require.NoError(t, nErr) // Post 2 messages without mention to direct channel p2 := model.Post{} p2.ChannelId = c2.Id p2.UserId = u1.Id p2.Message = "first message" _, nErr = ss.Post().Save(rctx, &p2) require.NoError(t, nErr) nErr = ss.Channel().IncrementMentionCount(c2.Id, []string{u2.Id}, false, false) require.NoError(t, nErr) p3 := model.Post{} p3.ChannelId = c2.Id p3.UserId = u1.Id p3.Message = "second message" _, nErr = ss.Post().Save(rctx, &p3) require.NoError(t, nErr) nErr = ss.Channel().IncrementMentionCount(c2.Id, []string{u2.Id}, false, false) require.NoError(t, nErr) badge, unreadCountErr := ss.User().GetUnreadCount(u2.Id, false) require.NoError(t, unreadCountErr) require.Equal(t, int64(3), badge, "should have 3 unread messages") badge, unreadCountErr = ss.User().GetUnreadCount(u3.Id, false) require.NoError(t, unreadCountErr) require.Equal(t, int64(1), badge, "should have 1 unread message") // Increment root mentions by 1 nErr = ss.Channel().IncrementMentionCount(c1.Id, []string{u3.Id}, true, false) require.NoError(t, nErr) // CRT is enabled, only root mentions are counted badge, unreadCountErr = ss.User().GetUnreadCount(u3.Id, true) require.NoError(t, unreadCountErr) require.Equal(t, int64(1), badge, "should have 1 unread message with CRT") badge, unreadCountErr = ss.User().GetUnreadCountForChannel(u2.Id, c1.Id) require.NoError(t, unreadCountErr) require.Equal(t, int64(1), badge, "should have 1 unread messages for that channel") badge, unreadCountErr = ss.User().GetUnreadCountForChannel(u2.Id, c2.Id) require.NoError(t, unreadCountErr) require.Equal(t, int64(2), badge, "should have 2 unread messages for that channel") } func testUserStoreUpdateMfaSecret(t *testing.T, rctx request.CTX, ss store.Store) { u1 := model.User{} u1.Email = MakeEmail() _, err := ss.User().Save(rctx, &u1) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u1.Id)) }() err = ss.User().UpdateMfaSecret(u1.Id, "12345") require.NoError(t, err) // should pass, no update will occur though err = ss.User().UpdateMfaSecret("junk", "12345") require.NoError(t, err) } func testUserStoreUpdateMfaActive(t *testing.T, rctx request.CTX, ss store.Store) { u1 := model.User{} u1.Email = MakeEmail() _, err := ss.User().Save(rctx, &u1) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u1.Id)) }() time.Sleep(time.Millisecond) err = ss.User().UpdateMfaActive(u1.Id, true) require.NoError(t, err) err = ss.User().UpdateMfaActive(u1.Id, false) require.NoError(t, err) // should pass, no update will occur though err = ss.User().UpdateMfaActive("junk", true) require.NoError(t, err) } func testUserStoreGetRecentlyActiveUsersForTeam(t *testing.T, rctx request.CTX, ss store.Store, s SqlStore) { cleanupStatusStore(t, s) teamID := model.NewId() u1, err := ss.User().Save(rctx, &model.User{ Email: MakeEmail(), Username: "u1" + model.NewId(), }) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u1.Id)) }() _, nErr := ss.Team().SaveMember(rctx, &model.TeamMember{TeamId: teamID, UserId: u1.Id}, -1) require.NoError(t, nErr) u2, err := ss.User().Save(rctx, &model.User{ Email: MakeEmail(), Username: "u2" + model.NewId(), }) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u2.Id)) }() _, nErr = ss.Team().SaveMember(rctx, &model.TeamMember{TeamId: teamID, UserId: u2.Id}, -1) require.NoError(t, nErr) u3, err := ss.User().Save(rctx, &model.User{ Email: MakeEmail(), Username: "u3" + model.NewId(), }) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u3.Id)) }() _, nErr = ss.Team().SaveMember(rctx, &model.TeamMember{TeamId: teamID, UserId: u3.Id}, -1) require.NoError(t, nErr) _, nErr = ss.Bot().Save(&model.Bot{ UserId: u3.Id, Username: u3.Username, OwnerId: u1.Id, }) require.NoError(t, nErr) u3.IsBot = true defer func() { require.NoError(t, ss.Bot().PermanentDelete(u3.Id)) }() millis := model.GetMillis() u3.LastActivityAt = millis u2.LastActivityAt = millis - 1 u1.LastActivityAt = millis - 1 require.NoError(t, ss.Status().SaveOrUpdate(&model.Status{UserId: u1.Id, Status: model.StatusOnline, Manual: false, LastActivityAt: u1.LastActivityAt, ActiveChannel: ""})) require.NoError(t, ss.Status().SaveOrUpdate(&model.Status{UserId: u2.Id, Status: model.StatusOnline, Manual: false, LastActivityAt: u2.LastActivityAt, ActiveChannel: ""})) require.NoError(t, ss.Status().SaveOrUpdate(&model.Status{UserId: u3.Id, Status: model.StatusOnline, Manual: false, LastActivityAt: u3.LastActivityAt, ActiveChannel: ""})) t.Run("get team 1, offset 0, limit 100", func(t *testing.T) { users, err := ss.User().GetRecentlyActiveUsersForTeam(teamID, 0, 100, nil) require.NoError(t, err) assert.Equal(t, []*model.User{ sanitized(u3), sanitized(u1), sanitized(u2), }, users) }) t.Run("get team 1, offset 0, limit 1", func(t *testing.T) { users, err := ss.User().GetRecentlyActiveUsersForTeam(teamID, 0, 1, nil) require.NoError(t, err) assert.Equal(t, []*model.User{ sanitized(u3), }, users) }) t.Run("get team 1, offset 2, limit 1", func(t *testing.T) { users, err := ss.User().GetRecentlyActiveUsersForTeam(teamID, 2, 1, nil) require.NoError(t, err) assert.Equal(t, []*model.User{ sanitized(u2), }, users) }) } func testUserStoreGetNewUsersForTeam(t *testing.T, rctx request.CTX, ss store.Store) { teamID := model.NewId() teamID2 := model.NewId() u1, err := ss.User().Save(rctx, &model.User{ Email: MakeEmail(), Username: "Yuka", }) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u1.Id)) }() _, nErr := ss.Team().SaveMember(rctx, &model.TeamMember{TeamId: teamID, UserId: u1.Id}, -1) require.NoError(t, nErr) u2, err := ss.User().Save(rctx, &model.User{ Email: MakeEmail(), Username: "Leia", }) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u2.Id)) }() _, nErr = ss.Team().SaveMember(rctx, &model.TeamMember{TeamId: teamID, UserId: u2.Id}, -1) require.NoError(t, nErr) u3, err := ss.User().Save(rctx, &model.User{ Email: MakeEmail(), Username: "Ali", }) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u3.Id)) }() _, nErr = ss.Team().SaveMember(rctx, &model.TeamMember{TeamId: teamID, UserId: u3.Id}, -1) require.NoError(t, nErr) _, nErr = ss.Bot().Save(&model.Bot{ UserId: u3.Id, Username: u3.Username, OwnerId: u1.Id, }) require.NoError(t, nErr) u3.IsBot = true defer func() { require.NoError(t, ss.Bot().PermanentDelete(u3.Id)) }() u4, err := ss.User().Save(rctx, &model.User{ Email: MakeEmail(), Username: "u4" + model.NewId(), }) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u4.Id)) }() _, nErr = ss.Team().SaveMember(rctx, &model.TeamMember{TeamId: teamID2, UserId: u4.Id}, -1) require.NoError(t, nErr) t.Run("get team 1, offset 0, limit 100", func(t *testing.T) { result, err := ss.User().GetNewUsersForTeam(teamID, 0, 100, nil) require.NoError(t, err) assert.Equal(t, []*model.User{ sanitized(u3), sanitized(u2), sanitized(u1), }, result) }) t.Run("get team 1, offset 0, limit 1", func(t *testing.T) { result, err := ss.User().GetNewUsersForTeam(teamID, 0, 1, nil) require.NoError(t, err) assert.Equal(t, []*model.User{ sanitized(u3), }, result) }) t.Run("get team 1, offset 2, limit 1", func(t *testing.T) { result, err := ss.User().GetNewUsersForTeam(teamID, 2, 1, nil) require.NoError(t, err) assert.Equal(t, []*model.User{ sanitized(u1), }, result) }) t.Run("get team 2, offset 0, limit 100", func(t *testing.T) { result, err := ss.User().GetNewUsersForTeam(teamID2, 0, 100, nil) require.NoError(t, err) assert.Equal(t, []*model.User{ sanitized(u4), }, result) }) } func assertUsers(t *testing.T, expected, actual []*model.User) { expectedUsernames := make([]string, 0, len(expected)) for _, user := range expected { expectedUsernames = append(expectedUsernames, user.Username) } actualUsernames := make([]string, 0, len(actual)) for _, user := range actual { actualUsernames = append(actualUsernames, user.Username) } if assert.Equal(t, expectedUsernames, actualUsernames) { assert.Equal(t, expected, actual) } } func testUserStoreSearch(t *testing.T, rctx request.CTX, ss store.Store) { u1 := &model.User{ Username: "jimbo1" + NewTestID(), FirstName: "Tim", LastName: "Bill", Nickname: "Rob", Email: "harold" + NewTestID() + "@simulator.amazonses.com", Roles: "system_user system_admin", } _, err := ss.User().Save(rctx, u1) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u1.Id)) }() u2 := &model.User{ Username: "jim2-bobby" + NewTestID(), Email: MakeEmail(), Roles: "system_user system_user_manager", } _, err = ss.User().Save(rctx, u2) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u2.Id)) }() u3 := &model.User{ Username: "jimbo3" + NewTestID(), Email: MakeEmail(), Roles: "system_guest", } _, err = ss.User().Save(rctx, u3) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u3.Id)) }() t1id := model.NewId() _, nErr := ss.Team().SaveMember(rctx, &model.TeamMember{TeamId: t1id, UserId: u1.Id, SchemeAdmin: true, SchemeUser: true}, -1) require.NoError(t, nErr) _, nErr = ss.Team().SaveMember(rctx, &model.TeamMember{TeamId: t1id, UserId: u2.Id, SchemeAdmin: true, SchemeUser: true}, -1) require.NoError(t, nErr) _, nErr = ss.Team().SaveMember(rctx, &model.TeamMember{TeamId: t1id, UserId: u3.Id, SchemeAdmin: false, SchemeUser: false, SchemeGuest: true}, -1) require.NoError(t, nErr) testCases := []struct { Description string TeamID string Term string Options *model.UserSearchOptions Expected []*model.User }{ { "search jimb, team 1", t1id, "jimb", &model.UserSearchOptions{ AllowFullNames: true, Limit: model.UserSearchDefaultLimit, }, []*model.User{u1, u3}, }, { "search jimb, team 1 with team guest and team admin filters without sys admin filter", t1id, "jimb", &model.UserSearchOptions{ AllowFullNames: true, Limit: model.UserSearchDefaultLimit, TeamRoles: []string{model.TeamGuestRoleId, model.TeamAdminRoleId}, }, []*model.User{u3}, }, { "search jimb, team 1 with team admin filter and sys admin filter", t1id, "jimb", &model.UserSearchOptions{ AllowFullNames: true, Limit: model.UserSearchDefaultLimit, Roles: []string{model.SystemAdminRoleId}, TeamRoles: []string{model.TeamAdminRoleId}, }, []*model.User{u1}, }, { "search jim, team 1 with team admin filter", t1id, "jim", &model.UserSearchOptions{ AllowFullNames: true, Limit: model.UserSearchDefaultLimit, TeamRoles: []string{model.TeamAdminRoleId}, }, []*model.User{u2}, }, { "search jim, team 1 with team admin and team guest filter", t1id, "jim", &model.UserSearchOptions{ AllowFullNames: true, Limit: model.UserSearchDefaultLimit, TeamRoles: []string{model.TeamAdminRoleId, model.TeamGuestRoleId}, }, []*model.User{u2, u3}, }, { "search jim, team 1 with team admin and system admin filters", t1id, "jim", &model.UserSearchOptions{ AllowFullNames: true, Limit: model.UserSearchDefaultLimit, Roles: []string{model.SystemAdminRoleId}, TeamRoles: []string{model.TeamAdminRoleId}, }, []*model.User{u2, u1}, }, { "search jim, team 1 with system guest filter", t1id, "jim", &model.UserSearchOptions{ AllowFullNames: true, Limit: model.UserSearchDefaultLimit, Roles: []string{model.SystemGuestRoleId}, TeamRoles: []string{}, }, []*model.User{u3}, }, { "search for Id of u1", t1id, u1.Id, &model.UserSearchOptions{ AllowFullNames: true, Limit: model.UserSearchDefaultLimit, Roles: []string{}, TeamRoles: []string{}, }, []*model.User{u1}, }, { "search for partial Id of u1", t1id, u1.Id[:len(u1.Id)-1], &model.UserSearchOptions{ AllowFullNames: true, Limit: model.UserSearchDefaultLimit, Roles: []string{}, TeamRoles: []string{}, }, []*model.User{}, }, } for _, testCase := range testCases { t.Run(testCase.Description, func(t *testing.T) { users, err := ss.User().Search( rctx, testCase.TeamID, testCase.Term, testCase.Options, ) require.NoError(t, err) assertUsers(t, testCase.Expected, users) }) } } func testUserStoreSearchNotInChannel(t *testing.T, rctx request.CTX, ss store.Store) { u1 := &model.User{ Username: "jimbo1" + NewTestID(), FirstName: "Tim", LastName: "Bill", Nickname: "Rob", Email: "harold" + NewTestID() + "@simulator.amazonses.com", } _, err := ss.User().Save(rctx, u1) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u1.Id)) }() u2 := &model.User{ Username: "jim2-bobby" + NewTestID(), Email: MakeEmail(), } _, err = ss.User().Save(rctx, u2) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u2.Id)) }() u3 := &model.User{ Username: "jimbo3" + NewTestID(), Email: MakeEmail(), DeleteAt: 1, } _, err = ss.User().Save(rctx, u3) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u3.Id)) }() _, nErr := ss.Bot().Save(&model.Bot{ UserId: u3.Id, Username: u3.Username, OwnerId: u1.Id, }) require.NoError(t, nErr) u3.IsBot = true defer func() { require.NoError(t, ss.Bot().PermanentDelete(u3.Id)) }() tid := model.NewId() _, nErr = ss.Team().SaveMember(rctx, &model.TeamMember{TeamId: tid, UserId: u1.Id}, -1) require.NoError(t, nErr) _, nErr = ss.Team().SaveMember(rctx, &model.TeamMember{TeamId: tid, UserId: u2.Id}, -1) require.NoError(t, nErr) _, nErr = ss.Team().SaveMember(rctx, &model.TeamMember{TeamId: tid, UserId: u3.Id}, -1) require.NoError(t, nErr) ch1 := model.Channel{ TeamId: tid, DisplayName: "NameName", Name: NewTestID(), Type: model.ChannelTypeOpen, } c1, nErr := ss.Channel().Save(rctx, &ch1, -1) require.NoError(t, nErr) ch2 := model.Channel{ TeamId: tid, DisplayName: "NameName", Name: NewTestID(), Type: model.ChannelTypeOpen, } c2, nErr := ss.Channel().Save(rctx, &ch2, -1) require.NoError(t, nErr) _, nErr = ss.Channel().SaveMember(rctx, &model.ChannelMember{ ChannelId: c2.Id, UserId: u1.Id, NotifyProps: model.GetDefaultChannelNotifyProps(), }) require.NoError(t, nErr) _, nErr = ss.Channel().SaveMember(rctx, &model.ChannelMember{ ChannelId: c1.Id, UserId: u3.Id, NotifyProps: model.GetDefaultChannelNotifyProps(), }) require.NoError(t, nErr) _, nErr = ss.Channel().SaveMember(rctx, &model.ChannelMember{ ChannelId: c2.Id, UserId: u2.Id, NotifyProps: model.GetDefaultChannelNotifyProps(), }) require.NoError(t, nErr) testCases := []struct { Description string TeamID string ChannelID string Term string Options *model.UserSearchOptions Expected []*model.User }{ { "search jimb, channel 1", tid, c1.Id, "jimb", &model.UserSearchOptions{ AllowFullNames: true, Limit: model.UserSearchDefaultLimit, }, []*model.User{u1}, }, { "search jimb, allow inactive, channel 1", tid, c1.Id, "jimb", &model.UserSearchOptions{ AllowFullNames: true, AllowInactive: true, Limit: model.UserSearchDefaultLimit, }, []*model.User{u1}, }, { "search jimb, channel 1, no team id", "", c1.Id, "jimb", &model.UserSearchOptions{ AllowFullNames: true, Limit: model.UserSearchDefaultLimit, }, []*model.User{u1}, }, { "search jimb, channel 1, junk team id", "junk", c1.Id, "jimb", &model.UserSearchOptions{ AllowFullNames: true, Limit: model.UserSearchDefaultLimit, }, []*model.User{}, }, { "search jimb, channel 2", tid, c2.Id, "jimb", &model.UserSearchOptions{ AllowFullNames: true, Limit: model.UserSearchDefaultLimit, }, []*model.User{}, }, { "search jimb, allow inactive, channel 2", tid, c2.Id, "jimb", &model.UserSearchOptions{ AllowFullNames: true, AllowInactive: true, Limit: model.UserSearchDefaultLimit, }, []*model.User{u3}, }, { "search jimb, channel 2, no team id", "", c2.Id, "jimb", &model.UserSearchOptions{ AllowFullNames: true, Limit: model.UserSearchDefaultLimit, }, []*model.User{}, }, { "search jimb, channel 2, junk team id", "junk", c2.Id, "jimb", &model.UserSearchOptions{ AllowFullNames: true, Limit: model.UserSearchDefaultLimit, }, []*model.User{}, }, { "search jim, channel 1", tid, c1.Id, "jim", &model.UserSearchOptions{ AllowFullNames: true, Limit: model.UserSearchDefaultLimit, }, []*model.User{u2, u1}, }, { "search jim, channel 1, limit 1", tid, c1.Id, "jim", &model.UserSearchOptions{ AllowFullNames: true, Limit: 1, }, []*model.User{u2}, }, } for _, testCase := range testCases { t.Run(testCase.Description, func(t *testing.T) { users, err := ss.User().SearchNotInChannel( testCase.TeamID, testCase.ChannelID, testCase.Term, testCase.Options, ) require.NoError(t, err) assertUsers(t, testCase.Expected, users) }) } } func testUserStoreSearchInChannel(t *testing.T, rctx request.CTX, ss store.Store) { u1 := &model.User{ Username: "jimbo1" + NewTestID(), FirstName: "Tim", LastName: "Bill", Nickname: "Rob", Email: "harold" + NewTestID() + "@simulator.amazonses.com", Roles: "system_user system_admin", } _, err := ss.User().Save(rctx, u1) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u1.Id)) }() u2 := &model.User{ Username: "jim-bobby" + NewTestID(), Email: MakeEmail(), Roles: "system_user", } _, err = ss.User().Save(rctx, u2) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u2.Id)) }() u3 := &model.User{ Username: "jimbo3" + NewTestID(), Email: MakeEmail(), DeleteAt: 1, Roles: "system_user", } _, err = ss.User().Save(rctx, u3) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u3.Id)) }() _, nErr := ss.Bot().Save(&model.Bot{ UserId: u3.Id, Username: u3.Username, OwnerId: u1.Id, }) require.NoError(t, nErr) u3.IsBot = true defer func() { require.NoError(t, ss.Bot().PermanentDelete(u3.Id)) }() tid := model.NewId() _, nErr = ss.Team().SaveMember(rctx, &model.TeamMember{TeamId: tid, UserId: u1.Id}, -1) require.NoError(t, nErr) _, nErr = ss.Team().SaveMember(rctx, &model.TeamMember{TeamId: tid, UserId: u2.Id}, -1) require.NoError(t, nErr) _, nErr = ss.Team().SaveMember(rctx, &model.TeamMember{TeamId: tid, UserId: u3.Id}, -1) require.NoError(t, nErr) ch1 := model.Channel{ TeamId: tid, DisplayName: "NameName", Name: NewTestID(), Type: model.ChannelTypeOpen, } c1, nErr := ss.Channel().Save(rctx, &ch1, -1) require.NoError(t, nErr) ch2 := model.Channel{ TeamId: tid, DisplayName: "NameName", Name: NewTestID(), Type: model.ChannelTypeOpen, } c2, nErr := ss.Channel().Save(rctx, &ch2, -1) require.NoError(t, nErr) _, nErr = ss.Channel().SaveMember(rctx, &model.ChannelMember{ ChannelId: c1.Id, UserId: u1.Id, NotifyProps: model.GetDefaultChannelNotifyProps(), SchemeAdmin: true, SchemeUser: true, }) require.NoError(t, nErr) _, nErr = ss.Channel().SaveMember(rctx, &model.ChannelMember{ ChannelId: c2.Id, UserId: u2.Id, NotifyProps: model.GetDefaultChannelNotifyProps(), SchemeAdmin: false, SchemeUser: true, }) require.NoError(t, nErr) _, nErr = ss.Channel().SaveMember(rctx, &model.ChannelMember{ ChannelId: c1.Id, UserId: u3.Id, NotifyProps: model.GetDefaultChannelNotifyProps(), SchemeAdmin: false, SchemeUser: true, }) require.NoError(t, nErr) testCases := []struct { Description string ChannelID string Term string Options *model.UserSearchOptions Expected []*model.User }{ { "search jimb, channel 1", c1.Id, "jimb", &model.UserSearchOptions{ AllowFullNames: true, Limit: model.UserSearchDefaultLimit, }, []*model.User{u1}, }, { "search jimb, allow inactive, channel 1", c1.Id, "jimb", &model.UserSearchOptions{ AllowFullNames: true, AllowInactive: true, Limit: model.UserSearchDefaultLimit, }, []*model.User{u1, u3}, }, { "search jimb, allow inactive, channel 1, limit 1", c1.Id, "jimb", &model.UserSearchOptions{ AllowFullNames: true, AllowInactive: true, Limit: 1, }, []*model.User{u1}, }, { "search jimb, channel 2", c2.Id, "jimb", &model.UserSearchOptions{ AllowFullNames: true, Limit: model.UserSearchDefaultLimit, }, []*model.User{}, }, { "search jimb, allow inactive, channel 2", c2.Id, "jimb", &model.UserSearchOptions{ AllowFullNames: true, AllowInactive: true, Limit: model.UserSearchDefaultLimit, }, []*model.User{}, }, { "search jim, allow inactive, channel 1 with system admin filter", c1.Id, "jim", &model.UserSearchOptions{ AllowFullNames: true, AllowInactive: true, Limit: model.UserSearchDefaultLimit, Roles: []string{model.SystemAdminRoleId}, }, []*model.User{u1}, }, { "search jim, allow inactive, channel 1 with system admin and system user filter", c1.Id, "jim", &model.UserSearchOptions{ AllowFullNames: true, AllowInactive: true, Limit: model.UserSearchDefaultLimit, Roles: []string{model.SystemAdminRoleId, model.SystemUserRoleId}, }, []*model.User{u1, u3}, }, { "search jim, allow inactive, channel 1 with channel user filter", c1.Id, "jim", &model.UserSearchOptions{ AllowFullNames: true, AllowInactive: true, Limit: model.UserSearchDefaultLimit, ChannelRoles: []string{model.ChannelUserRoleId}, }, []*model.User{u3}, }, { "search jim, allow inactive, channel 1 with channel user and channel admin filter", c1.Id, "jim", &model.UserSearchOptions{ AllowFullNames: true, AllowInactive: true, Limit: model.UserSearchDefaultLimit, ChannelRoles: []string{model.ChannelUserRoleId, model.ChannelAdminRoleId}, }, []*model.User{u3}, }, { "search jim, allow inactive, channel 2 with channel user filter", c2.Id, "jim", &model.UserSearchOptions{ AllowFullNames: true, AllowInactive: true, Limit: model.UserSearchDefaultLimit, ChannelRoles: []string{model.ChannelUserRoleId}, }, []*model.User{u2}, }, } for _, testCase := range testCases { t.Run(testCase.Description, func(t *testing.T) { users, err := ss.User().SearchInChannel( testCase.ChannelID, testCase.Term, testCase.Options, ) require.NoError(t, err) assertUsers(t, testCase.Expected, users) }) } } func testUserStoreSearchNotInTeam(t *testing.T, rctx request.CTX, ss store.Store) { u1 := &model.User{ Username: "jimbo1" + NewTestID(), FirstName: "Tim", LastName: "Bill", Nickname: "Rob", Email: "harold" + NewTestID() + "@simulator.amazonses.com", } _, err := ss.User().Save(rctx, u1) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u1.Id)) }() u2 := &model.User{ Username: "jim-bobby" + NewTestID(), Email: MakeEmail(), } _, err = ss.User().Save(rctx, u2) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u2.Id)) }() u3 := &model.User{ Username: "jimbo3" + NewTestID(), Email: MakeEmail(), DeleteAt: 1, } _, err = ss.User().Save(rctx, u3) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u3.Id)) }() _, nErr := ss.Bot().Save(&model.Bot{ UserId: u3.Id, Username: u3.Username, OwnerId: u1.Id, }) require.NoError(t, nErr) u3.IsBot = true defer func() { require.NoError(t, ss.Bot().PermanentDelete(u3.Id)) }() u4 := &model.User{ Username: "simon" + NewTestID(), Email: MakeEmail(), DeleteAt: 0, } _, err = ss.User().Save(rctx, u4) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u4.Id)) }() u5 := &model.User{ Username: "yu" + NewTestID(), FirstName: "En", LastName: "Yu", Nickname: "enyu", Email: MakeEmail(), } _, err = ss.User().Save(rctx, u5) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u5.Id)) }() u6 := &model.User{ Username: "underscore" + NewTestID(), FirstName: "Du_", LastName: "_DE", Nickname: "lodash", Email: MakeEmail(), } _, err = ss.User().Save(rctx, u6) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u6.Id)) }() teamID1 := model.NewId() _, nErr = ss.Team().SaveMember(rctx, &model.TeamMember{TeamId: teamID1, UserId: u1.Id}, -1) require.NoError(t, nErr) _, nErr = ss.Team().SaveMember(rctx, &model.TeamMember{TeamId: teamID1, UserId: u2.Id}, -1) require.NoError(t, nErr) _, nErr = ss.Team().SaveMember(rctx, &model.TeamMember{TeamId: teamID1, UserId: u3.Id}, -1) require.NoError(t, nErr) // u4 is not in team 1 _, nErr = ss.Team().SaveMember(rctx, &model.TeamMember{TeamId: teamID1, UserId: u5.Id}, -1) require.NoError(t, nErr) _, nErr = ss.Team().SaveMember(rctx, &model.TeamMember{TeamId: teamID1, UserId: u6.Id}, -1) require.NoError(t, nErr) teamID2 := model.NewId() _, nErr = ss.Team().SaveMember(rctx, &model.TeamMember{TeamId: teamID2, UserId: u4.Id}, -1) require.NoError(t, nErr) testCases := []struct { Description string TeamID string Term string Options *model.UserSearchOptions Expected []*model.User }{ { "search simo, team 1", teamID1, "simo", &model.UserSearchOptions{ AllowFullNames: true, Limit: model.UserSearchDefaultLimit, }, []*model.User{u4}, }, { "search jimb, team 1", teamID1, "jimb", &model.UserSearchOptions{ AllowFullNames: true, Limit: model.UserSearchDefaultLimit, }, []*model.User{}, }, { "search jimb, allow inactive, team 1", teamID1, "jimb", &model.UserSearchOptions{ AllowFullNames: true, AllowInactive: true, Limit: model.UserSearchDefaultLimit, }, []*model.User{}, }, { "search simo, team 2", teamID2, "simo", &model.UserSearchOptions{ AllowFullNames: true, Limit: model.UserSearchDefaultLimit, }, []*model.User{}, }, { "search jimb, team2", teamID2, "jimb", &model.UserSearchOptions{ AllowFullNames: true, Limit: model.UserSearchDefaultLimit, }, []*model.User{u1}, }, { "search jimb, allow inactive, team 2", teamID2, "jimb", &model.UserSearchOptions{ AllowFullNames: true, AllowInactive: true, Limit: model.UserSearchDefaultLimit, }, []*model.User{u1, u3}, }, { "search jimb, allow inactive, team 2, limit 1", teamID2, "jimb", &model.UserSearchOptions{ AllowFullNames: true, AllowInactive: true, Limit: 1, }, []*model.User{u1}, }, } for _, testCase := range testCases { t.Run(testCase.Description, func(t *testing.T) { users, err := ss.User().SearchNotInTeam( testCase.TeamID, testCase.Term, testCase.Options, ) require.NoError(t, err) assertUsers(t, testCase.Expected, users) }) } } func testUserStoreSearchWithoutTeam(t *testing.T, rctx request.CTX, ss store.Store) { u1 := &model.User{ Username: "jimbo1" + NewTestID(), FirstName: "Tim", LastName: "Bill", Nickname: "Rob", Email: "harold" + NewTestID() + "@simulator.amazonses.com", } _, err := ss.User().Save(rctx, u1) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u1.Id)) }() u2 := &model.User{ Username: "jim2-bobby" + NewTestID(), Email: MakeEmail(), } _, err = ss.User().Save(rctx, u2) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u2.Id)) }() u3 := &model.User{ Username: "jimbo3" + NewTestID(), Email: MakeEmail(), DeleteAt: 1, } _, err = ss.User().Save(rctx, u3) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u3.Id)) }() _, nErr := ss.Bot().Save(&model.Bot{ UserId: u3.Id, Username: u3.Username, OwnerId: u1.Id, }) require.NoError(t, nErr) u3.IsBot = true defer func() { require.NoError(t, ss.Bot().PermanentDelete(u3.Id)) }() tid := model.NewId() _, nErr = ss.Team().SaveMember(rctx, &model.TeamMember{TeamId: tid, UserId: u3.Id}, -1) require.NoError(t, nErr) testCases := []struct { Description string Term string Options *model.UserSearchOptions Expected []*model.User }{ { "empty string", "", &model.UserSearchOptions{ AllowFullNames: true, Limit: model.UserSearchDefaultLimit, }, []*model.User{u2, u1}, }, { "jim", "jim", &model.UserSearchOptions{ AllowFullNames: true, Limit: model.UserSearchDefaultLimit, }, []*model.User{u2, u1}, }, { "PLT-8354", "* ", &model.UserSearchOptions{ AllowFullNames: true, Limit: model.UserSearchDefaultLimit, }, []*model.User{u2, u1}, }, { "jim, limit 1", "jim", &model.UserSearchOptions{ AllowFullNames: true, Limit: 1, }, []*model.User{u2}, }, } for _, testCase := range testCases { t.Run(testCase.Description, func(t *testing.T) { users, err := ss.User().SearchWithoutTeam( testCase.Term, testCase.Options, ) require.NoError(t, err) assertUsers(t, testCase.Expected, users) }) } } func testUserStoreSearchInGroup(t *testing.T, rctx request.CTX, ss store.Store) { u1 := &model.User{ Username: "jimbo1" + NewTestID(), FirstName: "Tim", LastName: "Bill", Nickname: "Rob", Email: "harold" + NewTestID() + "@simulator.amazonses.com", } _, err := ss.User().Save(rctx, u1) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u1.Id)) }() u2 := &model.User{ Username: "jim-bobby" + NewTestID(), Email: MakeEmail(), } _, err = ss.User().Save(rctx, u2) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u2.Id)) }() u3 := &model.User{ Username: "jimbo3" + NewTestID(), Email: MakeEmail(), } _, err = ss.User().Save(rctx, u3) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u3.Id)) }() g1 := &model.Group{ Name: model.NewPointer(NewTestID()), DisplayName: NewTestID(), Description: NewTestID(), Source: model.GroupSourceLdap, RemoteId: model.NewPointer(NewTestID()), } _, err = ss.Group().Create(g1) require.NoError(t, err) g2 := &model.Group{ Name: model.NewPointer(NewTestID()), DisplayName: NewTestID(), Description: NewTestID(), Source: model.GroupSourceLdap, RemoteId: model.NewPointer(NewTestID()), } _, err = ss.Group().Create(g2) require.NoError(t, err) _, err = ss.Group().UpsertMember(g1.Id, u1.Id) require.NoError(t, err) _, err = ss.Group().UpsertMember(g2.Id, u2.Id) require.NoError(t, err) _, err = ss.Group().UpsertMember(g1.Id, u3.Id) require.NoError(t, err) u3.DeleteAt = 1 _, err = ss.User().Update(rctx, u3, true) require.NoError(t, err) testCases := []struct { Description string GroupID string Term string Options *model.UserSearchOptions Expected []*model.User }{ { "search jimb, group 1", g1.Id, "jimb", &model.UserSearchOptions{ AllowFullNames: true, Limit: model.UserSearchDefaultLimit, }, []*model.User{u1}, }, { "search jimb, group 1, allow inactive", g1.Id, "jimb", &model.UserSearchOptions{ AllowFullNames: true, AllowInactive: true, Limit: model.UserSearchDefaultLimit, }, []*model.User{u1, u3}, }, { "search jimb, group 1, limit 1", g1.Id, "jimb", &model.UserSearchOptions{ AllowFullNames: true, AllowInactive: true, Limit: 1, }, []*model.User{u1}, }, { "search jimb, group 2", g2.Id, "jimb", &model.UserSearchOptions{ AllowFullNames: true, Limit: model.UserSearchDefaultLimit, }, []*model.User{}, }, { "search jimb, allow inactive, group 2", g2.Id, "jimb", &model.UserSearchOptions{ AllowFullNames: true, AllowInactive: true, Limit: model.UserSearchDefaultLimit, }, []*model.User{}, }, } for _, testCase := range testCases { t.Run(testCase.Description, func(t *testing.T) { users, err := ss.User().SearchInGroup( testCase.GroupID, testCase.Term, testCase.Options, ) require.NoError(t, err) assertUsers(t, testCase.Expected, users) }) } } func testUserStoreSearchNotInGroup(t *testing.T, rctx request.CTX, ss store.Store) { u1 := &model.User{ Username: "jimbo1" + NewTestID(), FirstName: "Tim", LastName: "Bill", Nickname: "Rob", Email: "harold" + NewTestID() + "@simulator.amazonses.com", } _, err := ss.User().Save(rctx, u1) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u1.Id)) }() u2 := &model.User{ Username: "jim-bobby" + NewTestID(), Email: MakeEmail(), } _, err = ss.User().Save(rctx, u2) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u2.Id)) }() u3 := &model.User{ Username: "jimbo3" + NewTestID(), Email: MakeEmail(), } _, err = ss.User().Save(rctx, u3) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u3.Id)) }() g1 := &model.Group{ Name: model.NewPointer(NewTestID()), DisplayName: NewTestID(), Description: NewTestID(), Source: model.GroupSourceCustom, RemoteId: model.NewPointer(NewTestID()), } _, err = ss.Group().Create(g1) require.NoError(t, err) g2 := &model.Group{ Name: model.NewPointer(NewTestID()), DisplayName: NewTestID(), Description: NewTestID(), Source: model.GroupSourceCustom, RemoteId: model.NewPointer(NewTestID()), } _, err = ss.Group().Create(g2) require.NoError(t, err) _, err = ss.Group().UpsertMember(g1.Id, u1.Id) require.NoError(t, err) _, err = ss.Group().UpsertMember(g2.Id, u2.Id) require.NoError(t, err) _, err = ss.Group().UpsertMember(g1.Id, u3.Id) require.NoError(t, err) u3.DeleteAt = 1 _, err = ss.User().Update(rctx, u3, true) require.NoError(t, err) testCases := []struct { Description string GroupID string Term string Options *model.UserSearchOptions Expected []*model.User }{ { "search jimb, not in group 1", g1.Id, "jimb", &model.UserSearchOptions{ AllowFullNames: true, Limit: model.UserSearchDefaultLimit, }, []*model.User{}, }, { "search jim, not in group 1", g1.Id, "jim", &model.UserSearchOptions{ AllowFullNames: true, Limit: model.UserSearchDefaultLimit, }, []*model.User{u2}, }, { "search jimb, not in group 3, allow inactive", g2.Id, "jimb", &model.UserSearchOptions{ AllowFullNames: true, AllowInactive: true, Limit: model.UserSearchDefaultLimit, }, []*model.User{u1, u3}, }, { "search jim, not in group 2", g2.Id, "jimb", &model.UserSearchOptions{ AllowFullNames: true, AllowInactive: true, Limit: model.UserSearchDefaultLimit, }, []*model.User{u1, u3}, }, } for _, testCase := range testCases { t.Run(testCase.Description, func(t *testing.T) { users, err := ss.User().SearchNotInGroup( testCase.GroupID, testCase.Term, testCase.Options, ) require.NoError(t, err) assertUsers(t, testCase.Expected, users) }) } } func testCount(t *testing.T, rctx request.CTX, ss store.Store) { // Regular teamID := model.NewId() channelID := model.NewId() regularUser := &model.User{} regularUser.Email = MakeEmail() regularUser.Roles = model.SystemUserRoleId _, err := ss.User().Save(rctx, regularUser) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, regularUser.Id)) }() _, nErr := ss.Team().SaveMember(rctx, &model.TeamMember{TeamId: teamID, UserId: regularUser.Id, SchemeAdmin: false, SchemeUser: true}, -1) require.NoError(t, nErr) _, nErr = ss.Channel().SaveMember(rctx, &model.ChannelMember{UserId: regularUser.Id, ChannelId: channelID, SchemeAdmin: false, SchemeUser: true, NotifyProps: model.GetDefaultChannelNotifyProps()}) require.NoError(t, nErr) guestUser := &model.User{} guestUser.Email = MakeEmail() guestUser.Roles = model.SystemGuestRoleId _, err = ss.User().Save(rctx, guestUser) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, guestUser.Id)) }() _, nErr = ss.Team().SaveMember(rctx, &model.TeamMember{TeamId: teamID, UserId: guestUser.Id, SchemeAdmin: false, SchemeUser: false, SchemeGuest: true}, -1) require.NoError(t, nErr) _, nErr = ss.Channel().SaveMember(rctx, &model.ChannelMember{UserId: guestUser.Id, ChannelId: channelID, SchemeAdmin: false, SchemeUser: false, SchemeGuest: true, NotifyProps: model.GetDefaultChannelNotifyProps()}) require.NoError(t, nErr) teamAdmin := &model.User{} teamAdmin.Email = MakeEmail() teamAdmin.Roles = model.SystemUserRoleId _, err = ss.User().Save(rctx, teamAdmin) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, teamAdmin.Id)) }() _, nErr = ss.Team().SaveMember(rctx, &model.TeamMember{TeamId: teamID, UserId: teamAdmin.Id, SchemeAdmin: true, SchemeUser: true}, -1) require.NoError(t, nErr) _, nErr = ss.Channel().SaveMember(rctx, &model.ChannelMember{UserId: teamAdmin.Id, ChannelId: channelID, SchemeAdmin: true, SchemeUser: true, NotifyProps: model.GetDefaultChannelNotifyProps()}) require.NoError(t, nErr) sysAdmin := &model.User{} sysAdmin.Email = MakeEmail() sysAdmin.Roles = model.SystemAdminRoleId + " " + model.SystemUserRoleId _, err = ss.User().Save(rctx, sysAdmin) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, sysAdmin.Id)) }() _, nErr = ss.Team().SaveMember(rctx, &model.TeamMember{TeamId: teamID, UserId: sysAdmin.Id, SchemeAdmin: false, SchemeUser: true}, -1) require.NoError(t, nErr) _, nErr = ss.Channel().SaveMember(rctx, &model.ChannelMember{UserId: sysAdmin.Id, ChannelId: channelID, SchemeAdmin: true, SchemeUser: true, NotifyProps: model.GetDefaultChannelNotifyProps()}) require.NoError(t, nErr) // Deleted deletedUser := &model.User{} deletedUser.Email = MakeEmail() deletedUser.DeleteAt = model.GetMillis() _, err = ss.User().Save(rctx, deletedUser) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, deletedUser.Id)) }() // Remote User remoteID := "remote-id" remoteUser, err := ss.User().Save(rctx, &model.User{ Email: MakeEmail(), RemoteId: &remoteID, }) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, remoteUser.Id)) }() // Bot botUser, err := ss.User().Save(rctx, &model.User{ Email: MakeEmail(), }) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, botUser.Id)) }() _, nErr = ss.Bot().Save(&model.Bot{ UserId: botUser.Id, Username: botUser.Username, OwnerId: regularUser.Id, }) require.NoError(t, nErr) botUser.IsBot = true defer func() { require.NoError(t, ss.Bot().PermanentDelete(botUser.Id)) }() testCases := []struct { Description string Options model.UserCountOptions Expected int64 }{ { "No bot accounts no deleted accounts and no team id", model.UserCountOptions{ IncludeBotAccounts: false, IncludeDeleted: false, TeamId: "", }, 4, }, { "Include bot accounts no deleted accounts and no team id", model.UserCountOptions{ IncludeBotAccounts: true, IncludeDeleted: false, TeamId: "", }, 5, }, { "Include delete accounts no bots and no team id", model.UserCountOptions{ IncludeBotAccounts: false, IncludeDeleted: true, TeamId: "", }, 5, }, { "Include bot accounts and deleted accounts and no team id", model.UserCountOptions{ IncludeBotAccounts: true, IncludeDeleted: true, TeamId: "", }, 6, }, { "Include bot accounts, deleted accounts, exclude regular users with no team id", model.UserCountOptions{ IncludeBotAccounts: true, IncludeDeleted: true, ExcludeRegularUsers: true, TeamId: "", }, 1, }, { "Include bot accounts and deleted accounts with existing team id", model.UserCountOptions{ IncludeBotAccounts: true, IncludeDeleted: true, TeamId: teamID, }, 4, }, { "Include bot accounts and deleted accounts with fake team id", model.UserCountOptions{ IncludeBotAccounts: true, IncludeDeleted: true, TeamId: model.NewId(), }, 0, }, { "Include bot accounts and deleted accounts with existing team id and view restrictions allowing team", model.UserCountOptions{ IncludeBotAccounts: true, IncludeDeleted: true, TeamId: teamID, ViewRestrictions: &model.ViewUsersRestrictions{Teams: []string{teamID}}, }, 4, }, { "Include bot accounts and deleted accounts with existing team id and view restrictions not allowing current team", model.UserCountOptions{ IncludeBotAccounts: true, IncludeDeleted: true, TeamId: teamID, ViewRestrictions: &model.ViewUsersRestrictions{Teams: []string{model.NewId()}}, }, 0, }, { "Include remote accounts no deleted accounts and no team id", model.UserCountOptions{ IncludeRemoteUsers: true, IncludeDeleted: false, TeamId: "", }, 5, }, { "Include delete accounts no remote accounts and no team id", model.UserCountOptions{ IncludeRemoteUsers: false, IncludeDeleted: true, TeamId: "", }, 5, }, { "Include remote accounts and deleted accounts and no team id", model.UserCountOptions{ IncludeRemoteUsers: true, IncludeDeleted: true, TeamId: "", }, 6, }, { "Include remote accounts and deleted accounts with existing team id", model.UserCountOptions{ IncludeRemoteUsers: true, IncludeDeleted: true, TeamId: teamID, }, 4, }, { "Include remote accounts and deleted accounts with fake team id", model.UserCountOptions{ IncludeRemoteUsers: true, IncludeDeleted: true, TeamId: model.NewId(), }, 0, }, { "Include remote accounts and deleted accounts with existing team id and view restrictions allowing team", model.UserCountOptions{ IncludeRemoteUsers: true, IncludeDeleted: true, TeamId: teamID, ViewRestrictions: &model.ViewUsersRestrictions{Teams: []string{teamID}}, }, 4, }, { "Include remote accounts and deleted accounts with existing team id and view restrictions not allowing current team", model.UserCountOptions{ IncludeRemoteUsers: true, IncludeDeleted: true, TeamId: teamID, ViewRestrictions: &model.ViewUsersRestrictions{Teams: []string{model.NewId()}}, }, 0, }, { "Filter by system admins only", model.UserCountOptions{ TeamId: teamID, Roles: []string{model.SystemAdminRoleId}, }, 1, }, { "Filter by system users only", model.UserCountOptions{ TeamId: teamID, Roles: []string{model.SystemUserRoleId}, }, 2, }, { "Filter by system guests only", model.UserCountOptions{ TeamId: teamID, Roles: []string{model.SystemGuestRoleId}, }, 1, }, { "Filter by system admins and system users", model.UserCountOptions{ TeamId: teamID, Roles: []string{model.SystemAdminRoleId, model.SystemUserRoleId}, }, 3, }, { "Filter by system admins, system user and system guests", model.UserCountOptions{ TeamId: teamID, Roles: []string{model.SystemAdminRoleId, model.SystemUserRoleId, model.SystemGuestRoleId}, }, 4, }, { "Filter by team admins", model.UserCountOptions{ TeamId: teamID, TeamRoles: []string{model.TeamAdminRoleId}, }, 1, }, { "Filter by team members", model.UserCountOptions{ TeamId: teamID, TeamRoles: []string{model.TeamUserRoleId}, }, 1, }, { "Filter by team guests", model.UserCountOptions{ TeamId: teamID, TeamRoles: []string{model.TeamGuestRoleId}, }, 1, }, { "Filter by team guests and any system role", model.UserCountOptions{ TeamId: teamID, TeamRoles: []string{model.TeamGuestRoleId}, Roles: []string{model.SystemAdminRoleId}, }, 2, }, { "Filter by channel members", model.UserCountOptions{ ChannelId: channelID, ChannelRoles: []string{model.ChannelUserRoleId}, }, 1, }, { "Filter by channel members and system admins", model.UserCountOptions{ ChannelId: channelID, Roles: []string{model.SystemAdminRoleId}, ChannelRoles: []string{model.ChannelUserRoleId}, }, 2, }, { "Filter by channel members and system admins and channel admins", model.UserCountOptions{ ChannelId: channelID, Roles: []string{model.SystemAdminRoleId}, ChannelRoles: []string{model.ChannelUserRoleId, model.ChannelAdminRoleId}, }, 3, }, { "Filter by channel guests", model.UserCountOptions{ ChannelId: channelID, ChannelRoles: []string{model.ChannelGuestRoleId}, }, 1, }, { "Filter by channel guests and any system role", model.UserCountOptions{ ChannelId: channelID, ChannelRoles: []string{model.ChannelGuestRoleId}, Roles: []string{model.SystemAdminRoleId}, }, 2, }, } for _, testCase := range testCases { t.Run(testCase.Description, func(t *testing.T) { count, err := ss.User().Count(testCase.Options) require.NoError(t, err) require.Equal(t, testCase.Expected, count) }) } } func testUserStoreAnalyticsActiveCount(t *testing.T, rctx request.CTX, ss store.Store, s SqlStore) { cleanupStatusStore(t, s) // Create 5 users statuses u0, u1, u2, u3, u4. // u4 is also a bot u0, err := ss.User().Save(rctx, &model.User{ Email: MakeEmail(), Username: "u0" + model.NewId(), }) require.NoError(t, err) u1, err := ss.User().Save(rctx, &model.User{ Email: MakeEmail(), Username: "u1" + model.NewId(), }) require.NoError(t, err) u2, err := ss.User().Save(rctx, &model.User{ Email: MakeEmail(), Username: "u2" + model.NewId(), }) require.NoError(t, err) u3, err := ss.User().Save(rctx, &model.User{ Email: MakeEmail(), Username: "u3" + model.NewId(), }) require.NoError(t, err) u4, err := ss.User().Save(rctx, &model.User{ Email: MakeEmail(), Username: "u4" + model.NewId(), }) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u0.Id)) require.NoError(t, ss.User().PermanentDelete(rctx, u1.Id)) require.NoError(t, ss.User().PermanentDelete(rctx, u2.Id)) require.NoError(t, ss.User().PermanentDelete(rctx, u3.Id)) require.NoError(t, ss.User().PermanentDelete(rctx, u4.Id)) }() _, nErr := ss.Bot().Save(&model.Bot{ UserId: u4.Id, Username: u4.Username, OwnerId: u1.Id, }) require.NoError(t, nErr) millis := model.GetMillis() millisTwoDaysAgo := model.GetMillis() - (2 * DayMilliseconds) millisTwoMonthsAgo := model.GetMillis() - (2 * MonthMilliseconds) // u0 last activity status is two months ago. // u1 last activity status is two days ago. // u2, u3, u4 last activity is within last day require.NoError(t, ss.Status().SaveOrUpdate(&model.Status{UserId: u0.Id, Status: model.StatusOffline, LastActivityAt: millisTwoMonthsAgo})) require.NoError(t, ss.Status().SaveOrUpdate(&model.Status{UserId: u1.Id, Status: model.StatusOffline, LastActivityAt: millisTwoDaysAgo})) require.NoError(t, ss.Status().SaveOrUpdate(&model.Status{UserId: u2.Id, Status: model.StatusOffline, LastActivityAt: millis})) require.NoError(t, ss.Status().SaveOrUpdate(&model.Status{UserId: u3.Id, Status: model.StatusOffline, LastActivityAt: millis})) require.NoError(t, ss.Status().SaveOrUpdate(&model.Status{UserId: u4.Id, Status: model.StatusOffline, LastActivityAt: millis})) // Daily counts (without bots) count, err := ss.User().AnalyticsActiveCount(DayMilliseconds, model.UserCountOptions{IncludeBotAccounts: false, IncludeDeleted: true}) require.NoError(t, err) assert.Equal(t, int64(2), count) // Daily counts (with bots) count, err = ss.User().AnalyticsActiveCount(DayMilliseconds, model.UserCountOptions{IncludeBotAccounts: true, IncludeDeleted: true}) require.NoError(t, err) assert.Equal(t, int64(3), count) // Monthly counts (without bots) count, err = ss.User().AnalyticsActiveCount(MonthMilliseconds, model.UserCountOptions{IncludeBotAccounts: false, IncludeDeleted: true}) require.NoError(t, err) assert.Equal(t, int64(3), count) // Monthly counts - (with bots) count, err = ss.User().AnalyticsActiveCount(MonthMilliseconds, model.UserCountOptions{IncludeBotAccounts: true, IncludeDeleted: true}) require.NoError(t, err) assert.Equal(t, int64(4), count) // Monthly counts - (with bots, excluding deleted) count, err = ss.User().AnalyticsActiveCount(MonthMilliseconds, model.UserCountOptions{IncludeBotAccounts: true, IncludeDeleted: false}) require.NoError(t, err) assert.Equal(t, int64(4), count) } func testUserStoreAnalyticsActiveCountForPeriod(t *testing.T, rctx request.CTX, ss store.Store, s SqlStore) { cleanupStatusStore(t, s) // Create 5 users statuses u0, u1, u2, u3, u4. // u4 is also a bot u0, err := ss.User().Save(rctx, &model.User{ Email: MakeEmail(), Username: "u0" + model.NewId(), }) require.NoError(t, err) u1, err := ss.User().Save(rctx, &model.User{ Email: MakeEmail(), Username: "u1" + model.NewId(), }) require.NoError(t, err) u2, err := ss.User().Save(rctx, &model.User{ Email: MakeEmail(), Username: "u2" + model.NewId(), }) require.NoError(t, err) u3, err := ss.User().Save(rctx, &model.User{ Email: MakeEmail(), Username: "u3" + model.NewId(), }) require.NoError(t, err) u4, err := ss.User().Save(rctx, &model.User{ Email: MakeEmail(), Username: "u4" + model.NewId(), }) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u0.Id)) require.NoError(t, ss.User().PermanentDelete(rctx, u1.Id)) require.NoError(t, ss.User().PermanentDelete(rctx, u2.Id)) require.NoError(t, ss.User().PermanentDelete(rctx, u3.Id)) require.NoError(t, ss.User().PermanentDelete(rctx, u4.Id)) }() _, nErr := ss.Bot().Save(&model.Bot{ UserId: u4.Id, Username: u4.Username, OwnerId: u1.Id, }) require.NoError(t, nErr) millis := model.GetMillis() millisTwoDaysAgo := model.GetMillis() - (2 * DayMilliseconds) millisTwoMonthsAgo := model.GetMillis() - (2 * MonthMilliseconds) // u0 last activity status is two months ago. // u1 last activity status is one month ago // u2 last activity is two days ago // u2 last activity is one day ago // u3 last activity is within last day // u4 last activity is within last day require.NoError(t, ss.Status().SaveOrUpdate(&model.Status{UserId: u0.Id, Status: model.StatusOffline, LastActivityAt: millisTwoMonthsAgo})) require.NoError(t, ss.Status().SaveOrUpdate(&model.Status{UserId: u1.Id, Status: model.StatusOffline, LastActivityAt: millisTwoMonthsAgo + MonthMilliseconds})) require.NoError(t, ss.Status().SaveOrUpdate(&model.Status{UserId: u2.Id, Status: model.StatusOffline, LastActivityAt: millisTwoDaysAgo})) require.NoError(t, ss.Status().SaveOrUpdate(&model.Status{UserId: u3.Id, Status: model.StatusOffline, LastActivityAt: millisTwoDaysAgo + DayMilliseconds})) require.NoError(t, ss.Status().SaveOrUpdate(&model.Status{UserId: u4.Id, Status: model.StatusOffline, LastActivityAt: millis})) // Two months to two days (without bots) count, nerr := ss.User().AnalyticsActiveCountForPeriod(millisTwoMonthsAgo, millisTwoDaysAgo, model.UserCountOptions{IncludeBotAccounts: false, IncludeDeleted: false}) require.NoError(t, nerr) assert.Equal(t, int64(2), count) // Two months to two days (without bots) count, nerr = ss.User().AnalyticsActiveCountForPeriod(millisTwoMonthsAgo, millisTwoDaysAgo, model.UserCountOptions{IncludeBotAccounts: false, IncludeDeleted: true}) require.NoError(t, nerr) assert.Equal(t, int64(2), count) // Two days to present - (with bots) count, nerr = ss.User().AnalyticsActiveCountForPeriod(millisTwoDaysAgo, millis, model.UserCountOptions{IncludeBotAccounts: true, IncludeDeleted: false}) require.NoError(t, nerr) assert.Equal(t, int64(2), count) // Two days to present - (with bots, excluding deleted) count, nerr = ss.User().AnalyticsActiveCountForPeriod(millisTwoDaysAgo, millis, model.UserCountOptions{IncludeBotAccounts: true, IncludeDeleted: true}) require.NoError(t, nerr) assert.Equal(t, int64(2), count) } func testUserStoreAnalyticsGetInactiveUsersCount(t *testing.T, rctx request.CTX, ss store.Store) { u1 := &model.User{} u1.Email = MakeEmail() _, err := ss.User().Save(rctx, u1) require.NoError(t, err) t.Cleanup(func() { require.NoError(t, ss.User().PermanentDelete(rctx, u1.Id)) }) count, err := ss.User().AnalyticsGetInactiveUsersCount() require.NoError(t, err) require.Equal(t, count, int64(0), "No users should have been inactive yet") u2 := &model.User{} u2.Email = MakeEmail() u2.DeleteAt = model.GetMillis() _, err = ss.User().Save(rctx, u2) require.NoError(t, err) t.Cleanup(func() { require.NoError(t, ss.User().PermanentDelete(rctx, u2.Id)) }) newCount, err := ss.User().AnalyticsGetInactiveUsersCount() require.NoError(t, err) require.Equal(t, count, newCount-1, "Expected 1 more inactive users but found otherwise.") } func testUserStoreAnalyticsGetInactiveUsersCountIgnoreBots(t *testing.T, rctx request.CTX, ss store.Store) { u1 := &model.User{} u1.Email = MakeEmail() _, err := ss.User().Save(rctx, u1) require.NoError(t, err) t.Cleanup(func() { require.NoError(t, ss.User().PermanentDelete(rctx, u1.Id)) }) count, err := ss.User().AnalyticsGetInactiveUsersCount() require.NoError(t, err) u2 := &model.User{} u2.Email = MakeEmail() u2.DeleteAt = model.GetMillis() _, err = ss.User().Save(rctx, u2) require.NoError(t, err) t.Cleanup(func() { require.NoError(t, ss.User().PermanentDelete(rctx, u2.Id)) }) _, nErr := ss.Bot().Save(&model.Bot{ UserId: u2.Id, Username: u2.Username, OwnerId: u2.Id, }) require.NoError(t, nErr) u2.IsBot = true t.Cleanup(func() { require.NoError(t, ss.Bot().PermanentDelete(u2.Id)) }) newCount, err := ss.User().AnalyticsGetInactiveUsersCount() require.NoError(t, err) require.Equal(t, count, newCount, "Expected same inactive users but found otherwise.") } func testUserStoreAnalyticsGetSystemAdminCount(t *testing.T, rctx request.CTX, ss store.Store) { countBefore, err := ss.User().AnalyticsGetSystemAdminCount() require.NoError(t, err) u1 := model.User{} u1.Email = MakeEmail() u1.Username = model.NewUsername() u1.Roles = "system_user system_admin" u2 := model.User{} u2.Email = MakeEmail() u2.Username = model.NewUsername() _, nErr := ss.User().Save(rctx, &u1) require.NoError(t, nErr, "couldn't save user") defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u1.Id)) }() _, nErr = ss.User().Save(rctx, &u2) require.NoError(t, nErr, "couldn't save user") defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u2.Id)) }() result, err := ss.User().AnalyticsGetSystemAdminCount() require.NoError(t, err) require.Equal(t, countBefore+1, result, "Did not get the expected number of system admins.") } func testUserStoreAnalyticsGetGuestCount(t *testing.T, rctx request.CTX, ss store.Store) { countBefore, err := ss.User().AnalyticsGetGuestCount() require.NoError(t, err) u1 := model.User{} u1.Email = MakeEmail() u1.Username = model.NewUsername() u1.Roles = "system_user system_admin" u2 := model.User{} u2.Email = MakeEmail() u2.Username = model.NewUsername() u2.Roles = "system_user" u3 := model.User{} u3.Email = MakeEmail() u3.Username = model.NewUsername() u3.Roles = "system_guest" _, nErr := ss.User().Save(rctx, &u1) require.NoError(t, nErr, "couldn't save user") defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u1.Id)) }() _, nErr = ss.User().Save(rctx, &u2) require.NoError(t, nErr, "couldn't save user") defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u2.Id)) }() _, nErr = ss.User().Save(rctx, &u3) require.NoError(t, nErr, "couldn't save user") defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u3.Id)) }() result, err := ss.User().AnalyticsGetGuestCount() require.NoError(t, err) require.Equal(t, countBefore+1, result, "Did not get the expected number of guests.") } func testUserStoreAnalyticsGetExternalUsers(t *testing.T, rctx request.CTX, ss store.Store) { localHostDomain := "mattermost.com" result, err := ss.User().AnalyticsGetExternalUsers(localHostDomain) require.NoError(t, err) assert.False(t, result) u1 := model.User{} u1.Email = "a@mattermost.com" u1.Username = model.NewUsername() u1.Roles = "system_user system_admin" u2 := model.User{} u2.Email = "b@example.com" u2.Username = model.NewUsername() u2.Roles = "system_user" u3 := model.User{} u3.Email = "c@test.com" u3.Username = model.NewUsername() u3.Roles = "system_guest" _, err = ss.User().Save(rctx, &u1) require.NoError(t, err, "couldn't save user") defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u1.Id)) }() _, err = ss.User().Save(rctx, &u2) require.NoError(t, err, "couldn't save user") defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u2.Id)) }() _, err = ss.User().Save(rctx, &u3) require.NoError(t, err, "couldn't save user") defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u3.Id)) }() result, err = ss.User().AnalyticsGetExternalUsers(localHostDomain) require.NoError(t, err) assert.True(t, result) } func testUserStoreGetProfilesNotInTeam(t *testing.T, rctx request.CTX, ss store.Store) { team, err := ss.Team().Save(&model.Team{ DisplayName: "Team", Name: NewTestID(), Type: model.TeamOpen, }) require.NoError(t, err) teamID := team.Id teamID2 := model.NewId() u1, err := ss.User().Save(rctx, &model.User{ Email: MakeEmail(), Username: "u1" + model.NewId(), }) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u1.Id)) }() _, nErr := ss.Team().SaveMember(rctx, &model.TeamMember{TeamId: teamID, UserId: u1.Id}, -1) require.NoError(t, nErr) // Ensure update at timestamp changes time.Sleep(time.Millisecond) u2, err := ss.User().Save(rctx, &model.User{ Email: MakeEmail(), Username: "u2" + model.NewId(), }) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u2.Id)) }() _, nErr = ss.Team().SaveMember(rctx, &model.TeamMember{TeamId: teamID2, UserId: u2.Id}, -1) require.NoError(t, nErr) // Ensure update at timestamp changes time.Sleep(time.Millisecond) u3, err := ss.User().Save(rctx, &model.User{ Email: MakeEmail(), Username: "u3" + model.NewId(), }) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u3.Id)) }() _, nErr = ss.Bot().Save(&model.Bot{ UserId: u3.Id, Username: u3.Username, OwnerId: u1.Id, }) require.NoError(t, nErr) u3.IsBot = true defer func() { require.NoError(t, ss.Bot().PermanentDelete(u3.Id)) }() var etag1, etag2, etag3 string t.Run("etag for profiles not in team 1", func(t *testing.T) { etag1 = ss.User().GetEtagForProfilesNotInTeam(teamID) }) t.Run("get not in team 1, offset 0, limit 100000", func(t *testing.T) { users, userErr := ss.User().GetProfilesNotInTeam(teamID, false, 0, 100000, nil) require.NoError(t, userErr) assert.Equal(t, []*model.User{ sanitized(u2), sanitized(u3), }, users) }) t.Run("get not in team 1, offset 1, limit 1", func(t *testing.T) { users, userErr := ss.User().GetProfilesNotInTeam(teamID, false, 1, 1, nil) require.NoError(t, userErr) assert.Equal(t, []*model.User{ sanitized(u3), }, users) }) t.Run("get not in team 2, offset 0, limit 100", func(t *testing.T) { users, userErr := ss.User().GetProfilesNotInTeam(teamID2, false, 0, 100, nil) require.NoError(t, userErr) assert.Equal(t, []*model.User{ sanitized(u1), sanitized(u3), }, users) }) // Ensure update at timestamp changes time.Sleep(time.Millisecond) // Add u2 to team 1 _, nErr = ss.Team().SaveMember(rctx, &model.TeamMember{TeamId: teamID, UserId: u2.Id}, -1) require.NoError(t, nErr) u2.UpdateAt, err = ss.User().UpdateUpdateAt(u2.Id) require.NoError(t, err) t.Run("etag for profiles not in team 1 after update", func(t *testing.T) { etag2 = ss.User().GetEtagForProfilesNotInTeam(teamID) require.NotEqual(t, etag2, etag1, "etag should have changed") }) t.Run("get not in team 1, offset 0, limit 100000 after update", func(t *testing.T) { users, userErr := ss.User().GetProfilesNotInTeam(teamID, false, 0, 100000, nil) require.NoError(t, userErr) assert.Equal(t, []*model.User{ sanitized(u3), }, users) }) // Ensure update at timestamp changes time.Sleep(time.Millisecond) e := ss.Team().RemoveMember(rctx, teamID, u1.Id) require.NoError(t, e) e = ss.Team().RemoveMember(rctx, teamID, u2.Id) require.NoError(t, e) u1.UpdateAt, err = ss.User().UpdateUpdateAt(u1.Id) require.NoError(t, err) u2.UpdateAt, err = ss.User().UpdateUpdateAt(u2.Id) require.NoError(t, err) t.Run("etag for profiles not in team 1 after second update", func(t *testing.T) { etag3 = ss.User().GetEtagForProfilesNotInTeam(teamID) require.NotEqual(t, etag1, etag3, "etag should have changed") require.NotEqual(t, etag2, etag3, "etag should have changed") }) t.Run("get not in team 1, offset 0, limit 100000 after second update", func(t *testing.T) { users, userErr := ss.User().GetProfilesNotInTeam(teamID, false, 0, 100000, nil) require.NoError(t, userErr) assert.Equal(t, []*model.User{ sanitized(u1), sanitized(u2), sanitized(u3), }, users) }) // Ensure update at timestamp changes time.Sleep(time.Millisecond) u4, err := ss.User().Save(rctx, &model.User{ Email: MakeEmail(), Username: "u4" + model.NewId(), }) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u4.Id)) }() _, nErr = ss.Team().SaveMember(rctx, &model.TeamMember{TeamId: teamID, UserId: u4.Id}, -1) require.NoError(t, nErr) t.Run("etag for profiles not in team 1 after addition to team", func(t *testing.T) { etag4 := ss.User().GetEtagForProfilesNotInTeam(teamID) require.Equal(t, etag3, etag4, "etag should not have changed") }) // Add u3 to team 2 _, nErr = ss.Team().SaveMember(rctx, &model.TeamMember{TeamId: teamID2, UserId: u3.Id}, -1) require.NoError(t, nErr) u3.UpdateAt, err = ss.User().UpdateUpdateAt(u3.Id) require.NoError(t, err) // GetEtagForProfilesNotInTeam produces a new etag every time a member, not // in the team, gets a new UpdateAt value. In the case that an older member // in the set joins a different team, their UpdateAt value changes, thus // creating a new etag (even though the user set doesn't change). A hashing // solution, which only uses UserIds, would solve this issue. t.Run("etag for profiles not in team 1 after u3 added to team 2", func(t *testing.T) { t.Skip() etag4 := ss.User().GetEtagForProfilesNotInTeam(teamID) require.Equal(t, etag3, etag4, "etag should not have changed") }) t.Run("get not in team 1, offset 0, limit 100000 after second update, setting group constrained when it's not", func(t *testing.T) { users, userErr := ss.User().GetProfilesNotInTeam(teamID, true, 0, 100000, nil) require.NoError(t, userErr) assert.Empty(t, users) }) // create a group group, err := ss.Group().Create(&model.Group{ Name: model.NewPointer("n_" + model.NewId()), DisplayName: "dn_" + model.NewId(), Source: model.GroupSourceLdap, RemoteId: model.NewPointer("ri_" + model.NewId()), }) require.NoError(t, err) // add two members to the group for _, u := range []*model.User{u1, u2} { _, err = ss.Group().UpsertMember(group.Id, u.Id) require.NoError(t, err) } // associate the group with the team _, err = ss.Group().CreateGroupSyncable(&model.GroupSyncable{ GroupId: group.Id, SyncableId: teamID, Type: model.GroupSyncableTypeTeam, }) require.NoError(t, err) t.Run("get not in team 1, offset 0, limit 100000 after second update, setting group constrained", func(t *testing.T) { users, userErr := ss.User().GetProfilesNotInTeam(teamID, true, 0, 100000, nil) require.NoError(t, userErr) assert.Equal(t, []*model.User{ sanitized(u1), sanitized(u2), }, users) }) } func testUserStoreClearAllCustomRoleAssignments(t *testing.T, rctx request.CTX, ss store.Store) { u1 := model.User{ Email: MakeEmail(), Username: model.NewUsername(), Roles: "system_user system_admin system_post_all", } u2 := model.User{ Email: MakeEmail(), Username: model.NewUsername(), Roles: "system_user custom_role system_admin another_custom_role", } u3 := model.User{ Email: MakeEmail(), Username: model.NewUsername(), Roles: "system_user", } u4 := model.User{ Email: MakeEmail(), Username: model.NewUsername(), Roles: "custom_only", } _, err := ss.User().Save(rctx, &u1) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u1.Id)) }() _, err = ss.User().Save(rctx, &u2) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u2.Id)) }() _, err = ss.User().Save(rctx, &u3) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u3.Id)) }() _, err = ss.User().Save(rctx, &u4) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u4.Id)) }() require.NoError(t, ss.User().ClearAllCustomRoleAssignments()) r1, err := ss.User().GetByUsername(u1.Username) require.NoError(t, err) assert.Equal(t, u1.Roles, r1.Roles) r2, err1 := ss.User().GetByUsername(u2.Username) require.NoError(t, err1) assert.Equal(t, "system_user system_admin", r2.Roles) r3, err2 := ss.User().GetByUsername(u3.Username) require.NoError(t, err2) assert.Equal(t, u3.Roles, r3.Roles) r4, err3 := ss.User().GetByUsername(u4.Username) require.NoError(t, err3) assert.Equal(t, "", r4.Roles) } func testUserStoreGetAllAfter(t *testing.T, rctx request.CTX, ss store.Store) { u1, err := ss.User().Save(rctx, &model.User{ Email: MakeEmail(), Username: model.NewUsername(), Roles: "system_user system_admin system_post_all", }) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u1.Id)) }() u2, err := ss.User().Save(rctx, &model.User{ Email: MakeEmail(), Username: "u2" + model.NewId(), }) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u2.Id)) }() _, nErr := ss.Bot().Save(&model.Bot{ UserId: u2.Id, Username: u2.Username, OwnerId: u1.Id, }) require.NoError(t, nErr) u2.IsBot = true defer func() { require.NoError(t, ss.Bot().PermanentDelete(u2.Id)) }() expected := []*model.User{u1, u2} if strings.Compare(u2.Id, u1.Id) < 0 { expected = []*model.User{u2, u1} } t.Run("get after lowest possible id", func(t *testing.T) { actual, err := ss.User().GetAllAfter(10000, strings.Repeat("0", 26)) require.NoError(t, err) assert.Equal(t, expected, actual) }) t.Run("get after first user", func(t *testing.T) { actual, err := ss.User().GetAllAfter(10000, expected[0].Id) require.NoError(t, err) assert.Equal(t, []*model.User{expected[1]}, actual) }) t.Run("get after second user", func(t *testing.T) { actual, err := ss.User().GetAllAfter(10000, expected[1].Id) require.NoError(t, err) assert.Equal(t, []*model.User{}, actual) }) } func testUserStoreGetUsersBatchForIndexing(t *testing.T, rctx request.CTX, ss store.Store) { // Set up all the objects needed t1, err := ss.Team().Save(&model.Team{ DisplayName: "Team1", Name: NewTestID(), Type: model.TeamOpen, }) require.NoError(t, err) ch1 := &model.Channel{ Name: model.NewId(), Type: model.ChannelTypeOpen, } cPub1, nErr := ss.Channel().Save(rctx, ch1, -1) require.NoError(t, nErr) ch2 := &model.Channel{ Name: model.NewId(), Type: model.ChannelTypeOpen, } cPub2, nErr := ss.Channel().Save(rctx, ch2, -1) require.NoError(t, nErr) ch3 := &model.Channel{ Name: model.NewId(), Type: model.ChannelTypePrivate, } cPriv, nErr := ss.Channel().Save(rctx, ch3, -1) require.NoError(t, nErr) u1, err := ss.User().Save(rctx, &model.User{ Email: MakeEmail(), Username: model.NewUsername(), CreateAt: model.GetMillis(), }) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u1.Id)) }() time.Sleep(time.Millisecond) u2, err := ss.User().Save(rctx, &model.User{ Email: MakeEmail(), Username: model.NewUsername(), CreateAt: model.GetMillis(), }) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u2.Id)) }() _, nErr = ss.Team().SaveMember(rctx, &model.TeamMember{ UserId: u2.Id, TeamId: t1.Id, }, 100) require.NoError(t, nErr) _, err = ss.Channel().SaveMember(rctx, &model.ChannelMember{ UserId: u2.Id, ChannelId: cPub1.Id, NotifyProps: model.GetDefaultChannelNotifyProps(), }) require.NoError(t, err) _, err = ss.Channel().SaveMember(rctx, &model.ChannelMember{ UserId: u2.Id, ChannelId: cPub2.Id, NotifyProps: model.GetDefaultChannelNotifyProps(), }) require.NoError(t, err) time.Sleep(time.Millisecond) u3, err := ss.User().Save(rctx, &model.User{ Email: MakeEmail(), Username: model.NewUsername(), CreateAt: model.GetMillis(), }) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u3.Id)) }() _, nErr = ss.Team().SaveMember(rctx, &model.TeamMember{ UserId: u3.Id, TeamId: t1.Id, DeleteAt: model.GetMillis(), }, 100) require.NoError(t, nErr) _, err = ss.Channel().SaveMember(rctx, &model.ChannelMember{ UserId: u3.Id, ChannelId: cPub2.Id, NotifyProps: model.GetDefaultChannelNotifyProps(), }) require.NoError(t, err) _, err = ss.Channel().SaveMember(rctx, &model.ChannelMember{ UserId: u3.Id, ChannelId: cPriv.Id, NotifyProps: model.GetDefaultChannelNotifyProps(), }) require.NoError(t, err) cDM := &model.Channel{ Name: model.NewId() + "__" + model.NewId(), Type: model.ChannelTypeDirect, } cm1 := &model.ChannelMember{ UserId: u3.Id, ChannelId: cDM.Id, NotifyProps: model.GetDefaultChannelNotifyProps(), } cm2 := &model.ChannelMember{ UserId: u2.Id, ChannelId: cDM.Id, NotifyProps: model.GetDefaultChannelNotifyProps(), } cDM, nErr = ss.Channel().SaveDirectChannel(rctx, cDM, cm1, cm2) require.NoError(t, nErr) // Getting all users res1List, err := ss.User().GetUsersBatchForIndexing(u1.CreateAt-1, "", 100) require.NoError(t, err) assert.Len(t, res1List, 3) for _, user := range res1List { switch user.Id { case u2.Id: assert.ElementsMatch(t, user.ChannelsIds, []string{cPub1.Id, cPub2.Id, cDM.Id}) case u3.Id: assert.ElementsMatch(t, user.ChannelsIds, []string{cPub2.Id, cDM.Id}) } } // Testing pagination res2List, err := ss.User().GetUsersBatchForIndexing(u1.CreateAt-1, "", 1) require.NoError(t, err) assert.Len(t, res2List, 1) res2List, err = ss.User().GetUsersBatchForIndexing(res2List[0].CreateAt, res2List[0].Id, 2) require.NoError(t, err) assert.Len(t, res2List, 2) res2List, err = ss.User().GetUsersBatchForIndexing(res2List[1].CreateAt, res2List[1].Id, 2) require.NoError(t, err) assert.Len(t, res2List, 0) } func testUserStoreGetTeamGroupUsers(t *testing.T, rctx request.CTX, ss store.Store) { // create team id := model.NewId() team, err := ss.Team().Save(&model.Team{ DisplayName: "dn_" + id, Name: "n-" + id, Email: id + "@test.com", Type: model.TeamInvite, }) require.NoError(t, err) require.NotNil(t, team) // create users var testUsers []*model.User for range 3 { id = model.NewId() user, userErr := ss.User().Save(rctx, &model.User{ Email: id + "@test.com", Username: "un_" + id, Nickname: "nn_" + id, FirstName: "f_" + id, LastName: "l_" + id, Password: "Password1", }) require.NoError(t, userErr) require.NotNil(t, user) testUsers = append(testUsers, user) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, user.Id)) }() } require.Len(t, testUsers, 3, "testUsers length doesn't meet required length") userGroupA, userGroupB, userNoGroup := testUsers[0], testUsers[1], testUsers[2] // add non-group-member to the team (to prove that the query isn't just returning all members) _, nErr := ss.Team().SaveMember(rctx, &model.TeamMember{ TeamId: team.Id, UserId: userNoGroup.Id, }, 999) require.NoError(t, nErr) // create groups var testGroups []*model.Group for range 2 { id = model.NewId() var group *model.Group group, err = ss.Group().Create(&model.Group{ Name: model.NewPointer("n_" + id), DisplayName: "dn_" + id, Source: model.GroupSourceLdap, RemoteId: model.NewPointer("ri_" + id), }) require.NoError(t, err) require.NotNil(t, group) testGroups = append(testGroups, group) } require.Len(t, testGroups, 2, "testGroups length doesn't meet required length") groupA, groupB := testGroups[0], testGroups[1] // add members to groups _, err = ss.Group().UpsertMember(groupA.Id, userGroupA.Id) require.NoError(t, err) _, err = ss.Group().UpsertMember(groupB.Id, userGroupB.Id) require.NoError(t, err) // association one group to team _, err = ss.Group().CreateGroupSyncable(&model.GroupSyncable{ GroupId: groupA.Id, SyncableId: team.Id, Type: model.GroupSyncableTypeTeam, }) require.NoError(t, err) var users []*model.User requireNUsers := func(n int) { users, err = ss.User().GetTeamGroupUsers(team.Id) require.NoError(t, err) require.NotNil(t, users) require.Len(t, users, n) } // team not group constrained returns users requireNUsers(1) // update team to be group-constrained team.GroupConstrained = model.NewPointer(true) team, err = ss.Team().Update(team) require.NoError(t, err) // still returns user (being group-constrained has no effect) requireNUsers(1) // associate other group to team _, err = ss.Group().CreateGroupSyncable(&model.GroupSyncable{ GroupId: groupB.Id, SyncableId: team.Id, Type: model.GroupSyncableTypeTeam, }) require.NoError(t, err) // should return users from all groups // 2 users now that both groups have been associated to the team requireNUsers(2) // add team membership of allowed user _, nErr = ss.Team().SaveMember(rctx, &model.TeamMember{ TeamId: team.Id, UserId: userGroupA.Id, }, 999) require.NoError(t, nErr) // ensure allowed member still returned by query requireNUsers(2) // delete team membership of allowed user err = ss.Team().RemoveMember(rctx, team.Id, userGroupA.Id) require.NoError(t, err) // ensure removed allowed member still returned by query requireNUsers(2) } func testUserStoreGetChannelGroupUsers(t *testing.T, rctx request.CTX, ss store.Store) { // create channel id := model.NewId() channel, nErr := ss.Channel().Save(rctx, &model.Channel{ DisplayName: "dn_" + id, Name: "n-" + id, Type: model.ChannelTypePrivate, }, 999) require.NoError(t, nErr) require.NotNil(t, channel) // create users var testUsers []*model.User for range 3 { id = model.NewId() user, userErr := ss.User().Save(rctx, &model.User{ Email: id + "@test.com", Username: "un_" + id, Nickname: "nn_" + id, FirstName: "f_" + id, LastName: "l_" + id, Password: "Password1", }) require.NoError(t, userErr) require.NotNil(t, user) testUsers = append(testUsers, user) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, user.Id)) }() } require.Len(t, testUsers, 3, "testUsers length doesn't meet required length") userGroupA, userGroupB, userNoGroup := testUsers[0], testUsers[1], testUsers[2] // add non-group-member to the channel (to prove that the query isn't just returning all members) _, err := ss.Channel().SaveMember(rctx, &model.ChannelMember{ ChannelId: channel.Id, UserId: userNoGroup.Id, NotifyProps: model.GetDefaultChannelNotifyProps(), }) require.NoError(t, err) // create groups var testGroups []*model.Group for range 2 { id = model.NewId() var group *model.Group group, err = ss.Group().Create(&model.Group{ Name: model.NewPointer("n_" + id), DisplayName: "dn_" + id, Source: model.GroupSourceLdap, RemoteId: model.NewPointer("ri_" + id), }) require.NoError(t, err) require.NotNil(t, group) testGroups = append(testGroups, group) } require.Len(t, testGroups, 2, "testGroups length doesn't meet required length") groupA, groupB := testGroups[0], testGroups[1] // add members to groups _, err = ss.Group().UpsertMember(groupA.Id, userGroupA.Id) require.NoError(t, err) _, err = ss.Group().UpsertMember(groupB.Id, userGroupB.Id) require.NoError(t, err) // association one group to channel _, err = ss.Group().CreateGroupSyncable(&model.GroupSyncable{ GroupId: groupA.Id, SyncableId: channel.Id, Type: model.GroupSyncableTypeChannel, }) require.NoError(t, err) var users []*model.User requireNUsers := func(n int) { users, err = ss.User().GetChannelGroupUsers(channel.Id) require.NoError(t, err) require.NotNil(t, users) require.Len(t, users, n) } // channel not group constrained returns users requireNUsers(1) // update team to be group-constrained channel.GroupConstrained = model.NewPointer(true) _, nErr = ss.Channel().Update(rctx, channel) require.NoError(t, nErr) // still returns user (being group-constrained has no effect) requireNUsers(1) // associate other group to team _, err = ss.Group().CreateGroupSyncable(&model.GroupSyncable{ GroupId: groupB.Id, SyncableId: channel.Id, Type: model.GroupSyncableTypeChannel, }) require.NoError(t, err) // should return users from all groups // 2 users now that both groups have been associated to the team requireNUsers(2) // add team membership of allowed user _, err = ss.Channel().SaveMember(rctx, &model.ChannelMember{ ChannelId: channel.Id, UserId: userGroupA.Id, NotifyProps: model.GetDefaultChannelNotifyProps(), }) require.NoError(t, err) // ensure allowed member still returned by query requireNUsers(2) // delete team membership of allowed user err = ss.Channel().RemoveMember(rctx, channel.Id, userGroupA.Id) require.NoError(t, err) // ensure removed allowed member still returned by query requireNUsers(2) } func testUserStorePromoteGuestToUser(t *testing.T, rctx request.CTX, ss store.Store) { // create users t.Run("Must do nothing with regular user", func(t *testing.T) { id := model.NewId() user, err := ss.User().Save(rctx, &model.User{ Email: id + "@test.com", Username: "un_" + id, Nickname: "nn_" + id, FirstName: "f_" + id, LastName: "l_" + id, Password: "Password1", Roles: "system_user", }) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, user.Id)) }() teamID := model.NewId() _, nErr := ss.Team().SaveMember(rctx, &model.TeamMember{TeamId: teamID, UserId: user.Id, SchemeGuest: true, SchemeUser: false}, 999) require.NoError(t, nErr) channel, nErr := ss.Channel().Save(rctx, &model.Channel{ TeamId: teamID, DisplayName: "Channel name", Name: "channel-" + model.NewId(), Type: model.ChannelTypeOpen, }, -1) require.NoError(t, nErr) _, nErr = ss.Channel().SaveMember(rctx, &model.ChannelMember{ChannelId: channel.Id, UserId: user.Id, SchemeGuest: true, SchemeUser: false, NotifyProps: model.GetDefaultChannelNotifyProps()}) require.NoError(t, nErr) err = ss.User().PromoteGuestToUser(user.Id) require.NoError(t, err) updatedUser, err := ss.User().Get(context.Background(), user.Id) require.NoError(t, err) require.Equal(t, "system_user", updatedUser.Roles) require.True(t, user.UpdateAt < updatedUser.UpdateAt) updatedTeamMember, nErr := ss.Team().GetMember(rctx, teamID, user.Id) require.NoError(t, nErr) require.False(t, updatedTeamMember.SchemeGuest) require.True(t, updatedTeamMember.SchemeUser) updatedChannelMember, nErr := ss.Channel().GetMember(rctx, channel.Id, user.Id) require.NoError(t, nErr) require.False(t, updatedChannelMember.SchemeGuest) require.True(t, updatedChannelMember.SchemeUser) }) t.Run("Must do nothing with admin user", func(t *testing.T) { id := model.NewId() user, err := ss.User().Save(rctx, &model.User{ Email: id + "@test.com", Username: "un_" + id, Nickname: "nn_" + id, FirstName: "f_" + id, LastName: "l_" + id, Password: "Password1", Roles: "system_user system_admin", }) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, user.Id)) }() teamID := model.NewId() _, nErr := ss.Team().SaveMember(rctx, &model.TeamMember{TeamId: teamID, UserId: user.Id, SchemeGuest: true, SchemeUser: false}, 999) require.NoError(t, nErr) channel, nErr := ss.Channel().Save(rctx, &model.Channel{ TeamId: teamID, DisplayName: "Channel name", Name: "channel-" + model.NewId(), Type: model.ChannelTypeOpen, }, -1) require.NoError(t, nErr) _, nErr = ss.Channel().SaveMember(rctx, &model.ChannelMember{ChannelId: channel.Id, UserId: user.Id, SchemeGuest: true, SchemeUser: false, NotifyProps: model.GetDefaultChannelNotifyProps()}) require.NoError(t, nErr) err = ss.User().PromoteGuestToUser(user.Id) require.NoError(t, err) updatedUser, err := ss.User().Get(context.Background(), user.Id) require.NoError(t, err) require.Equal(t, "system_user system_admin", updatedUser.Roles) updatedTeamMember, nErr := ss.Team().GetMember(rctx, teamID, user.Id) require.NoError(t, nErr) require.False(t, updatedTeamMember.SchemeGuest) require.True(t, updatedTeamMember.SchemeUser) updatedChannelMember, nErr := ss.Channel().GetMember(rctx, channel.Id, user.Id) require.NoError(t, nErr) require.False(t, updatedChannelMember.SchemeGuest) require.True(t, updatedChannelMember.SchemeUser) }) t.Run("Must work with guest user without teams or channels", func(t *testing.T) { id := model.NewId() user, err := ss.User().Save(rctx, &model.User{ Email: id + "@test.com", Username: "un_" + id, Nickname: "nn_" + id, FirstName: "f_" + id, LastName: "l_" + id, Password: "Password1", Roles: "system_guest", }) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, user.Id)) }() err = ss.User().PromoteGuestToUser(user.Id) require.NoError(t, err) updatedUser, err := ss.User().Get(context.Background(), user.Id) require.NoError(t, err) require.Equal(t, "system_user", updatedUser.Roles) }) t.Run("Must work with guest user with teams but no channels", func(t *testing.T) { id := model.NewId() user, err := ss.User().Save(rctx, &model.User{ Email: id + "@test.com", Username: "un_" + id, Nickname: "nn_" + id, FirstName: "f_" + id, LastName: "l_" + id, Password: "Password1", Roles: "system_guest", }) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, user.Id)) }() teamID := model.NewId() _, nErr := ss.Team().SaveMember(rctx, &model.TeamMember{TeamId: teamID, UserId: user.Id, SchemeGuest: true, SchemeUser: false}, 999) require.NoError(t, nErr) err = ss.User().PromoteGuestToUser(user.Id) require.NoError(t, err) updatedUser, err := ss.User().Get(context.Background(), user.Id) require.NoError(t, err) require.Equal(t, "system_user", updatedUser.Roles) updatedTeamMember, nErr := ss.Team().GetMember(rctx, teamID, user.Id) require.NoError(t, nErr) require.False(t, updatedTeamMember.SchemeGuest) require.True(t, updatedTeamMember.SchemeUser) }) t.Run("Must work with guest user with teams and channels", func(t *testing.T) { id := model.NewId() user, err := ss.User().Save(rctx, &model.User{ Email: id + "@test.com", Username: "un_" + id, Nickname: "nn_" + id, FirstName: "f_" + id, LastName: "l_" + id, Password: "Password1", Roles: "system_guest", }) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, user.Id)) }() teamID := model.NewId() _, nErr := ss.Team().SaveMember(rctx, &model.TeamMember{TeamId: teamID, UserId: user.Id, SchemeGuest: true, SchemeUser: false}, 999) require.NoError(t, nErr) channel, nErr := ss.Channel().Save(rctx, &model.Channel{ TeamId: teamID, DisplayName: "Channel name", Name: "channel-" + model.NewId(), Type: model.ChannelTypeOpen, }, -1) require.NoError(t, nErr) _, nErr = ss.Channel().SaveMember(rctx, &model.ChannelMember{ChannelId: channel.Id, UserId: user.Id, SchemeGuest: true, SchemeUser: false, NotifyProps: model.GetDefaultChannelNotifyProps()}) require.NoError(t, nErr) err = ss.User().PromoteGuestToUser(user.Id) require.NoError(t, err) updatedUser, err := ss.User().Get(context.Background(), user.Id) require.NoError(t, err) require.Equal(t, "system_user", updatedUser.Roles) updatedTeamMember, nErr := ss.Team().GetMember(rctx, teamID, user.Id) require.NoError(t, nErr) require.False(t, updatedTeamMember.SchemeGuest) require.True(t, updatedTeamMember.SchemeUser) updatedChannelMember, nErr := ss.Channel().GetMember(rctx, channel.Id, user.Id) require.NoError(t, nErr) require.False(t, updatedChannelMember.SchemeGuest) require.True(t, updatedChannelMember.SchemeUser) }) t.Run("Must work with guest user with teams and channels and custom role", func(t *testing.T) { id := model.NewId() user, err := ss.User().Save(rctx, &model.User{ Email: id + "@test.com", Username: "un_" + id, Nickname: "nn_" + id, FirstName: "f_" + id, LastName: "l_" + id, Password: "Password1", Roles: "system_guest custom_role", }) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, user.Id)) }() teamID := model.NewId() _, nErr := ss.Team().SaveMember(rctx, &model.TeamMember{TeamId: teamID, UserId: user.Id, SchemeGuest: true, SchemeUser: false}, 999) require.NoError(t, nErr) channel, nErr := ss.Channel().Save(rctx, &model.Channel{ TeamId: teamID, DisplayName: "Channel name", Name: "channel-" + model.NewId(), Type: model.ChannelTypeOpen, }, -1) require.NoError(t, nErr) _, nErr = ss.Channel().SaveMember(rctx, &model.ChannelMember{ChannelId: channel.Id, UserId: user.Id, SchemeGuest: true, SchemeUser: false, NotifyProps: model.GetDefaultChannelNotifyProps()}) require.NoError(t, nErr) err = ss.User().PromoteGuestToUser(user.Id) require.NoError(t, err) updatedUser, err := ss.User().Get(context.Background(), user.Id) require.NoError(t, err) require.Equal(t, "system_user custom_role", updatedUser.Roles) updatedTeamMember, nErr := ss.Team().GetMember(rctx, teamID, user.Id) require.NoError(t, nErr) require.False(t, updatedTeamMember.SchemeGuest) require.True(t, updatedTeamMember.SchemeUser) updatedChannelMember, nErr := ss.Channel().GetMember(rctx, channel.Id, user.Id) require.NoError(t, nErr) require.False(t, updatedChannelMember.SchemeGuest) require.True(t, updatedChannelMember.SchemeUser) }) t.Run("Must no change any other user guest role", func(t *testing.T) { id := model.NewId() user1, err := ss.User().Save(rctx, &model.User{ Email: id + "@test.com", Username: "un_" + id, Nickname: "nn_" + id, FirstName: "f_" + id, LastName: "l_" + id, Password: "Password1", Roles: "system_guest", }) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, user1.Id)) }() teamID1 := model.NewId() _, nErr := ss.Team().SaveMember(rctx, &model.TeamMember{TeamId: teamID1, UserId: user1.Id, SchemeGuest: true, SchemeUser: false}, 999) require.NoError(t, nErr) channel, nErr := ss.Channel().Save(rctx, &model.Channel{ TeamId: teamID1, DisplayName: "Channel name", Name: "channel-" + model.NewId(), Type: model.ChannelTypeOpen, }, -1) require.NoError(t, nErr) _, nErr = ss.Channel().SaveMember(rctx, &model.ChannelMember{ChannelId: channel.Id, UserId: user1.Id, SchemeGuest: true, SchemeUser: false, NotifyProps: model.GetDefaultChannelNotifyProps()}) require.NoError(t, nErr) id = model.NewId() user2, err := ss.User().Save(rctx, &model.User{ Email: id + "@test.com", Username: "un_" + id, Nickname: "nn_" + id, FirstName: "f_" + id, LastName: "l_" + id, Password: "Password1", Roles: "system_guest", }) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, user2.Id)) }() teamID2 := model.NewId() _, nErr = ss.Team().SaveMember(rctx, &model.TeamMember{TeamId: teamID2, UserId: user2.Id, SchemeGuest: true, SchemeUser: false}, 999) require.NoError(t, nErr) _, nErr = ss.Channel().SaveMember(rctx, &model.ChannelMember{ChannelId: channel.Id, UserId: user2.Id, SchemeGuest: true, SchemeUser: false, NotifyProps: model.GetDefaultChannelNotifyProps()}) require.NoError(t, nErr) err = ss.User().PromoteGuestToUser(user1.Id) require.NoError(t, err) updatedUser, err := ss.User().Get(context.Background(), user1.Id) require.NoError(t, err) require.Equal(t, "system_user", updatedUser.Roles) updatedTeamMember, nErr := ss.Team().GetMember(rctx, teamID1, user1.Id) require.NoError(t, nErr) require.False(t, updatedTeamMember.SchemeGuest) require.True(t, updatedTeamMember.SchemeUser) updatedChannelMember, nErr := ss.Channel().GetMember(rctx, channel.Id, user1.Id) require.NoError(t, nErr) require.False(t, updatedChannelMember.SchemeGuest) require.True(t, updatedChannelMember.SchemeUser) notUpdatedUser, err := ss.User().Get(context.Background(), user2.Id) require.NoError(t, err) require.Equal(t, "system_guest", notUpdatedUser.Roles) notUpdatedTeamMember, nErr := ss.Team().GetMember(rctx, teamID2, user2.Id) require.NoError(t, nErr) require.True(t, notUpdatedTeamMember.SchemeGuest) require.False(t, notUpdatedTeamMember.SchemeUser) notUpdatedChannelMember, nErr := ss.Channel().GetMember(rctx, channel.Id, user2.Id) require.NoError(t, nErr) require.True(t, notUpdatedChannelMember.SchemeGuest) require.False(t, notUpdatedChannelMember.SchemeUser) }) } func testUserStoreDemoteUserToGuest(t *testing.T, rctx request.CTX, ss store.Store) { // create users t.Run("Must do nothing with guest", func(t *testing.T) { id := model.NewId() user, err := ss.User().Save(rctx, &model.User{ Email: id + "@test.com", Username: "un_" + id, Nickname: "nn_" + id, FirstName: "f_" + id, LastName: "l_" + id, Password: "Password1", Roles: "system_guest", }) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, user.Id)) }() teamID := model.NewId() _, nErr := ss.Team().SaveMember(rctx, &model.TeamMember{TeamId: teamID, UserId: user.Id, SchemeGuest: false, SchemeUser: true}, 999) require.NoError(t, nErr) channel, nErr := ss.Channel().Save(rctx, &model.Channel{ TeamId: teamID, DisplayName: "Channel name", Name: "channel-" + model.NewId(), Type: model.ChannelTypeOpen, }, -1) require.NoError(t, nErr) _, nErr = ss.Channel().SaveMember(rctx, &model.ChannelMember{ChannelId: channel.Id, UserId: user.Id, SchemeGuest: false, SchemeUser: true, NotifyProps: model.GetDefaultChannelNotifyProps()}) require.NoError(t, nErr) updatedUser, err := ss.User().DemoteUserToGuest(user.Id) require.NoError(t, err) require.Equal(t, "system_guest", updatedUser.Roles) require.True(t, user.UpdateAt < updatedUser.UpdateAt) updatedTeamMember, nErr := ss.Team().GetMember(rctx, teamID, updatedUser.Id) require.NoError(t, nErr) require.True(t, updatedTeamMember.SchemeGuest) require.False(t, updatedTeamMember.SchemeUser) updatedChannelMember, nErr := ss.Channel().GetMember(rctx, channel.Id, updatedUser.Id) require.NoError(t, nErr) require.True(t, updatedChannelMember.SchemeGuest) require.False(t, updatedChannelMember.SchemeUser) }) t.Run("Must demote properly an admin user", func(t *testing.T) { id := model.NewId() user, err := ss.User().Save(rctx, &model.User{ Email: id + "@test.com", Username: "un_" + id, Nickname: "nn_" + id, FirstName: "f_" + id, LastName: "l_" + id, Password: "Password1", Roles: "system_user system_admin", }) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, user.Id)) }() teamID := model.NewId() _, nErr := ss.Team().SaveMember(rctx, &model.TeamMember{TeamId: teamID, UserId: user.Id, SchemeGuest: true, SchemeUser: false}, 999) require.NoError(t, nErr) channel, nErr := ss.Channel().Save(rctx, &model.Channel{ TeamId: teamID, DisplayName: "Channel name", Name: "channel-" + model.NewId(), Type: model.ChannelTypeOpen, }, -1) require.NoError(t, nErr) _, nErr = ss.Channel().SaveMember(rctx, &model.ChannelMember{ChannelId: channel.Id, UserId: user.Id, SchemeGuest: true, SchemeUser: false, NotifyProps: model.GetDefaultChannelNotifyProps()}) require.NoError(t, nErr) updatedUser, err := ss.User().DemoteUserToGuest(user.Id) require.NoError(t, err) require.Equal(t, "system_guest", updatedUser.Roles) updatedTeamMember, nErr := ss.Team().GetMember(rctx, teamID, user.Id) require.NoError(t, nErr) require.True(t, updatedTeamMember.SchemeGuest) require.False(t, updatedTeamMember.SchemeUser) updatedChannelMember, nErr := ss.Channel().GetMember(rctx, channel.Id, user.Id) require.NoError(t, nErr) require.True(t, updatedChannelMember.SchemeGuest) require.False(t, updatedChannelMember.SchemeUser) }) t.Run("Must work with user without teams or channels", func(t *testing.T) { id := model.NewId() user, err := ss.User().Save(rctx, &model.User{ Email: id + "@test.com", Username: "un_" + id, Nickname: "nn_" + id, FirstName: "f_" + id, LastName: "l_" + id, Password: "Password1", Roles: "system_user", }) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, user.Id)) }() updatedUser, err := ss.User().DemoteUserToGuest(user.Id) require.NoError(t, err) require.Equal(t, "system_guest", updatedUser.Roles) }) t.Run("Must work with user with teams but no channels", func(t *testing.T) { id := model.NewId() user, err := ss.User().Save(rctx, &model.User{ Email: id + "@test.com", Username: "un_" + id, Nickname: "nn_" + id, FirstName: "f_" + id, LastName: "l_" + id, Password: "Password1", Roles: "system_user", }) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, user.Id)) }() teamID := model.NewId() _, nErr := ss.Team().SaveMember(rctx, &model.TeamMember{TeamId: teamID, UserId: user.Id, SchemeGuest: false, SchemeUser: true}, 999) require.NoError(t, nErr) updatedUser, err := ss.User().DemoteUserToGuest(user.Id) require.NoError(t, err) require.Equal(t, "system_guest", updatedUser.Roles) updatedTeamMember, nErr := ss.Team().GetMember(rctx, teamID, user.Id) require.NoError(t, nErr) require.True(t, updatedTeamMember.SchemeGuest) require.False(t, updatedTeamMember.SchemeUser) }) t.Run("Must work with user with teams and channels", func(t *testing.T) { id := model.NewId() user, err := ss.User().Save(rctx, &model.User{ Email: id + "@test.com", Username: "un_" + id, Nickname: "nn_" + id, FirstName: "f_" + id, LastName: "l_" + id, Password: "Password1", Roles: "system_user", }) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, user.Id)) }() teamID := model.NewId() _, nErr := ss.Team().SaveMember(rctx, &model.TeamMember{TeamId: teamID, UserId: user.Id, SchemeGuest: false, SchemeUser: true}, 999) require.NoError(t, nErr) channel, nErr := ss.Channel().Save(rctx, &model.Channel{ TeamId: teamID, DisplayName: "Channel name", Name: "channel-" + model.NewId(), Type: model.ChannelTypeOpen, }, -1) require.NoError(t, nErr) _, nErr = ss.Channel().SaveMember(rctx, &model.ChannelMember{ChannelId: channel.Id, UserId: user.Id, SchemeGuest: false, SchemeUser: true, NotifyProps: model.GetDefaultChannelNotifyProps()}) require.NoError(t, nErr) updatedUser, err := ss.User().DemoteUserToGuest(user.Id) require.NoError(t, err) require.Equal(t, "system_guest", updatedUser.Roles) updatedTeamMember, nErr := ss.Team().GetMember(rctx, teamID, user.Id) require.NoError(t, nErr) require.True(t, updatedTeamMember.SchemeGuest) require.False(t, updatedTeamMember.SchemeUser) updatedChannelMember, nErr := ss.Channel().GetMember(rctx, channel.Id, user.Id) require.NoError(t, nErr) require.True(t, updatedChannelMember.SchemeGuest) require.False(t, updatedChannelMember.SchemeUser) }) t.Run("Must work with user with teams and channels and custom role", func(t *testing.T) { id := model.NewId() user, err := ss.User().Save(rctx, &model.User{ Email: id + "@test.com", Username: "un_" + id, Nickname: "nn_" + id, FirstName: "f_" + id, LastName: "l_" + id, Password: "Password1", Roles: "system_user custom_role", }) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, user.Id)) }() teamID := model.NewId() _, nErr := ss.Team().SaveMember(rctx, &model.TeamMember{TeamId: teamID, UserId: user.Id, SchemeGuest: false, SchemeUser: true}, 999) require.NoError(t, nErr) channel, nErr := ss.Channel().Save(rctx, &model.Channel{ TeamId: teamID, DisplayName: "Channel name", Name: "channel-" + model.NewId(), Type: model.ChannelTypeOpen, }, -1) require.NoError(t, nErr) _, nErr = ss.Channel().SaveMember(rctx, &model.ChannelMember{ChannelId: channel.Id, UserId: user.Id, SchemeGuest: false, SchemeUser: true, NotifyProps: model.GetDefaultChannelNotifyProps()}) require.NoError(t, nErr) updatedUser, err := ss.User().DemoteUserToGuest(user.Id) require.NoError(t, err) require.Equal(t, "system_guest", updatedUser.Roles) updatedTeamMember, nErr := ss.Team().GetMember(rctx, teamID, user.Id) require.NoError(t, nErr) require.True(t, updatedTeamMember.SchemeGuest) require.False(t, updatedTeamMember.SchemeUser) updatedChannelMember, nErr := ss.Channel().GetMember(rctx, channel.Id, user.Id) require.NoError(t, nErr) require.True(t, updatedChannelMember.SchemeGuest) require.False(t, updatedChannelMember.SchemeUser) }) t.Run("Must no change any other user role", func(t *testing.T) { id := model.NewId() user1, err := ss.User().Save(rctx, &model.User{ Email: id + "@test.com", Username: "un_" + id, Nickname: "nn_" + id, FirstName: "f_" + id, LastName: "l_" + id, Password: "Password1", Roles: "system_user", }) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, user1.Id)) }() teamID1 := model.NewId() _, nErr := ss.Team().SaveMember(rctx, &model.TeamMember{TeamId: teamID1, UserId: user1.Id, SchemeGuest: false, SchemeUser: true}, 999) require.NoError(t, nErr) channel, nErr := ss.Channel().Save(rctx, &model.Channel{ TeamId: teamID1, DisplayName: "Channel name", Name: "channel-" + model.NewId(), Type: model.ChannelTypeOpen, }, -1) require.NoError(t, nErr) _, nErr = ss.Channel().SaveMember(rctx, &model.ChannelMember{ChannelId: channel.Id, UserId: user1.Id, SchemeGuest: false, SchemeUser: true, NotifyProps: model.GetDefaultChannelNotifyProps()}) require.NoError(t, nErr) id = model.NewId() user2, err := ss.User().Save(rctx, &model.User{ Email: id + "@test.com", Username: "un_" + id, Nickname: "nn_" + id, FirstName: "f_" + id, LastName: "l_" + id, Password: "Password1", Roles: "system_user", }) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, user2.Id)) }() teamID2 := model.NewId() _, nErr = ss.Team().SaveMember(rctx, &model.TeamMember{TeamId: teamID2, UserId: user2.Id, SchemeGuest: false, SchemeUser: true}, 999) require.NoError(t, nErr) _, nErr = ss.Channel().SaveMember(rctx, &model.ChannelMember{ChannelId: channel.Id, UserId: user2.Id, SchemeGuest: false, SchemeUser: true, NotifyProps: model.GetDefaultChannelNotifyProps()}) require.NoError(t, nErr) updatedUser, err := ss.User().DemoteUserToGuest(user1.Id) require.NoError(t, err) require.Equal(t, "system_guest", updatedUser.Roles) updatedTeamMember, nErr := ss.Team().GetMember(rctx, teamID1, user1.Id) require.NoError(t, nErr) require.True(t, updatedTeamMember.SchemeGuest) require.False(t, updatedTeamMember.SchemeUser) updatedChannelMember, nErr := ss.Channel().GetMember(rctx, channel.Id, user1.Id) require.NoError(t, nErr) require.True(t, updatedChannelMember.SchemeGuest) require.False(t, updatedChannelMember.SchemeUser) notUpdatedUser, err := ss.User().Get(context.Background(), user2.Id) require.NoError(t, err) require.Equal(t, "system_user", notUpdatedUser.Roles) notUpdatedTeamMember, nErr := ss.Team().GetMember(rctx, teamID2, user2.Id) require.NoError(t, nErr) require.False(t, notUpdatedTeamMember.SchemeGuest) require.True(t, notUpdatedTeamMember.SchemeUser) notUpdatedChannelMember, nErr := ss.Channel().GetMember(rctx, channel.Id, user2.Id) require.NoError(t, nErr) require.False(t, notUpdatedChannelMember.SchemeGuest) require.True(t, notUpdatedChannelMember.SchemeUser) }) } func testDeactivateGuests(t *testing.T, rctx request.CTX, ss store.Store) { // create users t.Run("Must disable all guests and no regular user or already deactivated users", func(t *testing.T) { guest1Random := model.NewId() guest1, err := ss.User().Save(rctx, &model.User{ Email: guest1Random + "@test.com", Username: "un_" + guest1Random, Nickname: "nn_" + guest1Random, FirstName: "f_" + guest1Random, LastName: "l_" + guest1Random, Password: "Password1", Roles: "system_guest", }) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, guest1.Id)) }() guest2Random := model.NewId() guest2, err := ss.User().Save(rctx, &model.User{ Email: guest2Random + "@test.com", Username: "un_" + guest2Random, Nickname: "nn_" + guest2Random, FirstName: "f_" + guest2Random, LastName: "l_" + guest2Random, Password: "Password1", Roles: "system_guest", }) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, guest2.Id)) }() guest3Random := model.NewId() guest3, err := ss.User().Save(rctx, &model.User{ Email: guest3Random + "@test.com", Username: "un_" + guest3Random, Nickname: "nn_" + guest3Random, FirstName: "f_" + guest3Random, LastName: "l_" + guest3Random, Password: "Password1", Roles: "system_guest", DeleteAt: 10, }) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, guest3.Id)) }() regularUserRandom := model.NewId() regularUser, err := ss.User().Save(rctx, &model.User{ Email: regularUserRandom + "@test.com", Username: "un_" + regularUserRandom, Nickname: "nn_" + regularUserRandom, FirstName: "f_" + regularUserRandom, LastName: "l_" + regularUserRandom, Password: "Password1", Roles: "system_user", }) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, regularUser.Id)) }() ids, err := ss.User().DeactivateGuests() require.NoError(t, err) assert.ElementsMatch(t, []string{guest1.Id, guest2.Id}, ids) u, err := ss.User().Get(context.Background(), guest1.Id) require.NoError(t, err) assert.NotEqual(t, u.DeleteAt, int64(0)) u, err = ss.User().Get(context.Background(), guest2.Id) require.NoError(t, err) assert.NotEqual(t, u.DeleteAt, int64(0)) u, err = ss.User().Get(context.Background(), guest3.Id) require.NoError(t, err) assert.Equal(t, u.DeleteAt, int64(10)) u, err = ss.User().Get(context.Background(), regularUser.Id) require.NoError(t, err) assert.Equal(t, u.DeleteAt, int64(0)) }) } func testUserStoreResetLastPictureUpdate(t *testing.T, rctx request.CTX, ss store.Store) { startTime := model.GetMillis() u1 := &model.User{} u1.Email = MakeEmail() _, err := ss.User().Save(rctx, u1) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u1.Id)) }() _, nErr := ss.Team().SaveMember(rctx, &model.TeamMember{TeamId: model.NewId(), UserId: u1.Id}, -1) require.NoError(t, nErr) err = ss.User().UpdateLastPictureUpdate(u1.Id) require.NoError(t, err) user, err := ss.User().Get(context.Background(), u1.Id) require.NoError(t, err) assert.GreaterOrEqual(t, user.LastPictureUpdate, startTime) // Ensure update at timestamp changes time.Sleep(time.Millisecond) err = ss.User().ResetLastPictureUpdate(u1.Id) require.NoError(t, err) ss.User().InvalidateProfileCacheForUser(u1.Id) user2, err := ss.User().Get(context.Background(), u1.Id) require.NoError(t, err) assert.Greater(t, user2.UpdateAt, user.UpdateAt) assert.Less(t, user2.LastPictureUpdate, -startTime) } func testGetKnownUsers(t *testing.T, rctx request.CTX, ss store.Store) { teamID := model.NewId() u1, err := ss.User().Save(rctx, &model.User{ Email: MakeEmail(), Username: "u1" + model.NewId(), }) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u1.Id)) }() _, nErr := ss.Team().SaveMember(rctx, &model.TeamMember{TeamId: teamID, UserId: u1.Id}, -1) require.NoError(t, nErr) u2, err := ss.User().Save(rctx, &model.User{ Email: MakeEmail(), Username: "u2" + model.NewId(), }) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u2.Id)) }() _, nErr = ss.Team().SaveMember(rctx, &model.TeamMember{TeamId: teamID, UserId: u2.Id}, -1) require.NoError(t, nErr) u3, err := ss.User().Save(rctx, &model.User{ Email: MakeEmail(), Username: "u3" + model.NewId(), }) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u3.Id)) }() _, nErr = ss.Team().SaveMember(rctx, &model.TeamMember{TeamId: teamID, UserId: u3.Id}, -1) require.NoError(t, nErr) _, nErr = ss.Bot().Save(&model.Bot{ UserId: u3.Id, Username: u3.Username, OwnerId: u1.Id, }) require.NoError(t, nErr) u3.IsBot = true defer func() { require.NoError(t, ss.Bot().PermanentDelete(u3.Id)) }() u4, err := ss.User().Save(rctx, &model.User{ Email: MakeEmail(), Username: "u4" + model.NewId(), }) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u4.Id)) }() _, nErr = ss.Team().SaveMember(rctx, &model.TeamMember{TeamId: teamID, UserId: u4.Id}, -1) require.NoError(t, nErr) ch1 := &model.Channel{ TeamId: teamID, DisplayName: "Profiles in channel", Name: "profiles-" + model.NewId(), Type: model.ChannelTypeOpen, } c1, nErr := ss.Channel().Save(rctx, ch1, -1) require.NoError(t, nErr) ch2 := &model.Channel{ TeamId: teamID, DisplayName: "Profiles in private", Name: "profiles-" + model.NewId(), Type: model.ChannelTypePrivate, } c2, nErr := ss.Channel().Save(rctx, ch2, -1) require.NoError(t, nErr) ch3 := &model.Channel{ TeamId: teamID, DisplayName: "Profiles in private", Name: "profiles-" + model.NewId(), Type: model.ChannelTypePrivate, } c3, nErr := ss.Channel().Save(rctx, ch3, -1) require.NoError(t, nErr) _, nErr = ss.Channel().SaveMember(rctx, &model.ChannelMember{ ChannelId: c1.Id, UserId: u1.Id, NotifyProps: model.GetDefaultChannelNotifyProps(), }) require.NoError(t, nErr) _, nErr = ss.Channel().SaveMember(rctx, &model.ChannelMember{ ChannelId: c1.Id, UserId: u2.Id, NotifyProps: model.GetDefaultChannelNotifyProps(), }) require.NoError(t, nErr) _, nErr = ss.Channel().SaveMember(rctx, &model.ChannelMember{ ChannelId: c2.Id, UserId: u3.Id, NotifyProps: model.GetDefaultChannelNotifyProps(), }) require.NoError(t, nErr) _, nErr = ss.Channel().SaveMember(rctx, &model.ChannelMember{ ChannelId: c2.Id, UserId: u1.Id, NotifyProps: model.GetDefaultChannelNotifyProps(), }) require.NoError(t, nErr) _, nErr = ss.Channel().SaveMember(rctx, &model.ChannelMember{ ChannelId: c3.Id, UserId: u4.Id, NotifyProps: model.GetDefaultChannelNotifyProps(), }) require.NoError(t, nErr) t.Run("get know users sharing no channels", func(t *testing.T) { userIds, err := ss.User().GetKnownUsers(u4.Id) require.NoError(t, err) assert.Empty(t, userIds) }) t.Run("get know users sharing one channel", func(t *testing.T) { userIds, err := ss.User().GetKnownUsers(u3.Id) require.NoError(t, err) assert.Len(t, userIds, 1) assert.Equal(t, userIds[0], u1.Id) }) t.Run("get know users sharing multiple channels", func(t *testing.T) { userIds, err := ss.User().GetKnownUsers(u1.Id) require.NoError(t, err) assert.Len(t, userIds, 2) assert.ElementsMatch(t, userIds, []string{u2.Id, u3.Id}) }) } func testIsEmpty(t *testing.T, rctx request.CTX, ss store.Store) { ok, err := ss.User().IsEmpty(false) require.NoError(t, err) require.True(t, ok) ok, err = ss.User().IsEmpty(true) require.NoError(t, err) require.True(t, ok) u := &model.User{ Email: MakeEmail(), Username: model.NewUsername(), } u, err = ss.User().Save(rctx, u) require.NoError(t, err) ok, err = ss.User().IsEmpty(false) require.NoError(t, err) require.False(t, ok) ok, err = ss.User().IsEmpty(true) require.NoError(t, err) require.False(t, ok) b := &model.Bot{ UserId: u.Id, OwnerId: model.NewId(), Username: model.NewUsername(), } _, err = ss.Bot().Save(b) require.NoError(t, err) ok, err = ss.User().IsEmpty(false) require.NoError(t, err) require.False(t, ok) ok, err = ss.User().IsEmpty(true) require.NoError(t, err) require.True(t, ok) err = ss.User().PermanentDelete(rctx, u.Id) require.NoError(t, err) ok, err = ss.User().IsEmpty(false) require.NoError(t, err) require.True(t, ok) } func testGetUsersWithInvalidEmails(t *testing.T, rctx request.CTX, ss store.Store) { u1, err := ss.User().Save(rctx, &model.User{ Email: "ben@invalid.mattermost.com", Username: "u1" + model.NewId(), }) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u1.Id)) }() users, err := ss.User().GetUsersWithInvalidEmails(0, 50, "localhost,simulator.amazonses.com") require.NoError(t, err) assert.Len(t, users, 1) } func testUpdateLastLogin(t *testing.T, rctx request.CTX, ss store.Store) { u1 := model.User{} u1.Email = MakeEmail() _, err := ss.User().Save(rctx, &u1) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u1.Id)) }() err = ss.User().UpdateLastLogin(u1.Id, 1234567890) require.NoError(t, err) user, err := ss.User().Get(context.Background(), u1.Id) require.NoError(t, err) require.Equal(t, int64(1234567890), user.LastLogin) } func testGetUserReport(t *testing.T, rctx request.CTX, ss store.Store, s SqlStore) { numRegularUsers := 90 numSysAdmins := 10 numInactiveUsers := 15 numUsers := numRegularUsers + numSysAdmins + numInactiveUsers numPostsPerUser := 10 now := time.Now() users := make([]*model.User, numUsers) for i := range numUsers { user := &model.User{Username: fmt.Sprintf("username_%d", i), DeleteAt: 0} user.Email = MakeEmail() if i >= numRegularUsers && i < numRegularUsers+numSysAdmins { user.Roles = "system" } if i >= numRegularUsers+numSysAdmins { user.DeleteAt = now.UnixMilli() } user, err := ss.User().Save(rctx, user) require.NoError(t, err) users[i] = user } sort.Slice(users, func(i, j int) bool { return users[i].Username < users[j].Username }) // cleanup users after the test defer func() { for _, user := range users { require.NoError(t, ss.User().PermanentDelete(rctx, user.Id)) } }() for _, user := range users { for i := range numPostsPerUser { post := model.Post{UserId: user.Id, ChannelId: model.NewId(), Message: NewTestID(), CreateAt: now.AddDate(0, 0, -i).UnixMilli()} _, err := ss.Post().Save(rctx, &post) require.NoError(t, err) } } team, err := ss.Team().Save(&model.Team{ DisplayName: model.NewId(), Name: NewTestID(), Email: MakeEmail(), Type: model.TeamOpen, }) require.NoError(t, err) _, err = ss.Team().SaveMember(rctx, &model.TeamMember{UserId: users[0].Id, TeamId: team.Id}, 100) require.NoError(t, err) _, err = ss.Team().SaveMember(rctx, &model.TeamMember{UserId: users[1].Id, TeamId: team.Id}, 100) require.NoError(t, err) defer func() { require.NoError(t, ss.Team().RemoveMember(rctx, team.Id, users[0].Id)) require.NoError(t, ss.Team().RemoveMember(rctx, team.Id, users[1].Id)) require.NoError(t, ss.Team().PermanentDelete(team.Id)) }() err = ss.User().RefreshPostStatsForUsers() require.NoError(t, err) t.Run("should return info for all the users", func(t *testing.T) { userReport, err := ss.User().GetUserReport(&model.UserReportOptions{ ReportingBaseOptions: model.ReportingBaseOptions{ SortColumn: "Username", PageSize: 50, }, }) require.NoError(t, err) require.NotNil(t, userReport) require.Len(t, userReport, 50) require.NotNil(t, userReport[0]) require.Equal(t, users[0].Username, userReport[0].Username) require.NotNil(t, userReport[1]) require.Equal(t, users[1].Username, userReport[1].Username) require.NotNil(t, userReport[2]) require.Equal(t, users[2].Username, userReport[2].Username) }) t.Run("should return in the correct order", func(t *testing.T) { userReport, err := ss.User().GetUserReport(&model.UserReportOptions{ ReportingBaseOptions: model.ReportingBaseOptions{ SortColumn: "Username", SortDesc: true, PageSize: 50, }, }) require.NoError(t, err) require.NotNil(t, userReport) require.Len(t, userReport, 50) require.NotNil(t, userReport[0]) require.Equal(t, users[numUsers-1].Username, userReport[0].Username) require.NotNil(t, userReport[1]) require.Equal(t, users[numUsers-2].Username, userReport[1].Username) require.NotNil(t, userReport[2]) require.Equal(t, users[numUsers-3].Username, userReport[2].Username) }) t.Run("should fail on invalid sort column", func(t *testing.T) { userReport, err := ss.User().GetUserReport(&model.UserReportOptions{ ReportingBaseOptions: model.ReportingBaseOptions{ SortColumn: "FakeColumn", SortDesc: true, PageSize: 50, }, }) require.Error(t, err) require.Nil(t, userReport) }) t.Run("should only return amount of users in page", func(t *testing.T) { userReport, err := ss.User().GetUserReport(&model.UserReportOptions{ ReportingBaseOptions: model.ReportingBaseOptions{ SortColumn: "Username", PageSize: 2, }, }) require.NoError(t, err) require.NotNil(t, userReport) require.Equal(t, 2, len(userReport)) require.NotNil(t, userReport[0]) require.Equal(t, users[0].Username, userReport[0].Username) require.NotNil(t, userReport[1]) require.Equal(t, users[1].Username, userReport[1].Username) }) t.Run("should return correct paging", func(t *testing.T) { userReport, err := ss.User().GetUserReport(&model.UserReportOptions{ ReportingBaseOptions: model.ReportingBaseOptions{ SortColumn: "Username", Direction: "next", PageSize: 50, FromColumnValue: users[10].Username, FromId: users[10].Id, }, }) require.NoError(t, err) require.NotNil(t, userReport) require.Equal(t, 50, len(userReport)) require.NotNil(t, userReport[0]) require.Equal(t, users[11].Username, userReport[0].Username) userReport, err = ss.User().GetUserReport(&model.UserReportOptions{ ReportingBaseOptions: model.ReportingBaseOptions{ SortColumn: "Username", SortDesc: true, Direction: "next", PageSize: 50, FromColumnValue: users[10].Username, FromId: users[10].Id, }, }) require.NoError(t, err) require.NotNil(t, userReport) require.Equal(t, 10, len(userReport)) require.NotNil(t, userReport[0]) require.Equal(t, users[9].Username, userReport[0].Username) userReport, err = ss.User().GetUserReport(&model.UserReportOptions{ ReportingBaseOptions: model.ReportingBaseOptions{ SortColumn: "Username", Direction: "prev", PageSize: 50, FromColumnValue: users[10].Username, FromId: users[10].Id, }, }) require.NoError(t, err) require.NotNil(t, userReport) require.Equal(t, 10, len(userReport)) require.NotNil(t, userReport[0]) require.Equal(t, users[0].Username, userReport[0].Username) userReport, err = ss.User().GetUserReport(&model.UserReportOptions{ ReportingBaseOptions: model.ReportingBaseOptions{ SortColumn: "Username", SortDesc: true, Direction: "prev", PageSize: 50, FromColumnValue: users[10].Username, FromId: users[10].Id, }, }) require.NoError(t, err) require.NotNil(t, userReport) require.Equal(t, 50, len(userReport)) require.NotNil(t, userReport[0]) require.Equal(t, users[60].Username, userReport[0].Username) }) t.Run("should return all users regardless of date range", func(t *testing.T) { userReport, err := ss.User().GetUserReport(&model.UserReportOptions{ ReportingBaseOptions: model.ReportingBaseOptions{ SortColumn: "Username", PageSize: 50, StartAt: now.AddDate(1000, 0, 0).UnixMilli(), EndAt: now.AddDate(1000, 0, 0).UnixMilli(), }, }) require.NoError(t, err) require.Len(t, userReport, 50) }) t.Run("should return accurate post stats for various date ranges", func(t *testing.T) { userReport, err := ss.User().GetUserReport(&model.UserReportOptions{ ReportingBaseOptions: model.ReportingBaseOptions{ SortColumn: "Username", PageSize: 50, }, }) require.NoError(t, err) require.Len(t, userReport, 50) require.Equal(t, numPostsPerUser, *userReport[0].TotalPosts) require.Equal(t, numPostsPerUser, *userReport[0].DaysActive) require.Equal(t, now.UnixMilli(), *userReport[0].LastPostDate) require.Equal(t, numPostsPerUser, *userReport[1].TotalPosts) require.Equal(t, numPostsPerUser, *userReport[1].DaysActive) require.Equal(t, now.UnixMilli(), *userReport[1].LastPostDate) require.Equal(t, numPostsPerUser, *userReport[2].TotalPosts) require.Equal(t, numPostsPerUser, *userReport[2].DaysActive) require.Equal(t, now.UnixMilli(), *userReport[2].LastPostDate) userReport, err = ss.User().GetUserReport(&model.UserReportOptions{ ReportingBaseOptions: model.ReportingBaseOptions{ SortColumn: "Username", PageSize: 50, StartAt: now.AddDate(0, 0, -2).UnixMilli(), }, }) require.NoError(t, err) require.Len(t, userReport, 50) require.Equal(t, 3, *userReport[0].TotalPosts) require.Equal(t, 3, *userReport[0].DaysActive) require.Equal(t, now.UnixMilli(), *userReport[0].LastPostDate) require.Equal(t, 3, *userReport[1].TotalPosts) require.Equal(t, 3, *userReport[1].DaysActive) require.Equal(t, now.UnixMilli(), *userReport[1].LastPostDate) require.Equal(t, 3, *userReport[2].TotalPosts) require.Equal(t, 3, *userReport[2].DaysActive) require.Equal(t, now.UnixMilli(), *userReport[2].LastPostDate) userReport, err = ss.User().GetUserReport(&model.UserReportOptions{ ReportingBaseOptions: model.ReportingBaseOptions{ SortColumn: "Username", PageSize: 50, EndAt: now.AddDate(0, 0, -2).UnixMilli(), }, }) require.NoError(t, err) require.Len(t, userReport, 50) require.Equal(t, 7, *userReport[0].TotalPosts) require.Equal(t, 7, *userReport[0].DaysActive) require.Equal(t, now.AddDate(0, 0, -3).UnixMilli(), *userReport[0].LastPostDate) require.Equal(t, 7, *userReport[1].TotalPosts) require.Equal(t, 7, *userReport[1].DaysActive) require.Equal(t, now.AddDate(0, 0, -3).UnixMilli(), *userReport[1].LastPostDate) require.Equal(t, 7, *userReport[2].TotalPosts) require.Equal(t, 7, *userReport[2].DaysActive) require.Equal(t, now.AddDate(0, 0, -3).UnixMilli(), *userReport[2].LastPostDate) userReport, err = ss.User().GetUserReport(&model.UserReportOptions{ ReportingBaseOptions: model.ReportingBaseOptions{ SortColumn: "Username", PageSize: 50, StartAt: now.AddDate(0, 0, -3).UnixMilli(), EndAt: now.AddDate(0, 0, -2).UnixMilli(), }, }) require.NoError(t, err) require.Len(t, userReport, 50) require.Equal(t, 1, *userReport[0].TotalPosts) require.Equal(t, 1, *userReport[0].DaysActive) require.Equal(t, now.AddDate(0, 0, -3).UnixMilli(), *userReport[0].LastPostDate) require.Equal(t, 1, *userReport[1].TotalPosts) require.Equal(t, 1, *userReport[1].DaysActive) require.Equal(t, now.AddDate(0, 0, -3).UnixMilli(), *userReport[1].LastPostDate) require.Equal(t, 1, *userReport[2].TotalPosts) require.Equal(t, 1, *userReport[2].DaysActive) require.Equal(t, now.AddDate(0, 0, -3).UnixMilli(), *userReport[2].LastPostDate) }) t.Run("should filter on roles", func(t *testing.T) { userReport, err := ss.User().GetUserReport(&model.UserReportOptions{ ReportingBaseOptions: model.ReportingBaseOptions{ SortColumn: "Username", PageSize: 50, }, Role: "system", }) require.NoError(t, err) require.Len(t, userReport, 10) }) t.Run("should filter on teams", func(t *testing.T) { userReport, err := ss.User().GetUserReport(&model.UserReportOptions{ ReportingBaseOptions: model.ReportingBaseOptions{ SortColumn: "Username", PageSize: 50, }, HasNoTeam: true, }) require.NoError(t, err) require.Len(t, userReport, 50) require.Equal(t, users[2].Id, userReport[0].Id) require.Equal(t, users[3].Id, userReport[1].Id) userReport, err = ss.User().GetUserReport(&model.UserReportOptions{ ReportingBaseOptions: model.ReportingBaseOptions{ SortColumn: "Username", PageSize: 50, }, Team: team.Id, }) require.NoError(t, err) require.Len(t, userReport, 2) require.Equal(t, users[0].Id, userReport[0].Id) require.Equal(t, users[1].Id, userReport[1].Id) }) t.Run("should filter on activation", func(t *testing.T) { userReport, err := ss.User().GetUserReport(&model.UserReportOptions{ ReportingBaseOptions: model.ReportingBaseOptions{ SortColumn: "Username", PageSize: 50, }, HideInactive: true, }) require.NoError(t, err) require.Len(t, userReport, 50) userReport, err = ss.User().GetUserReport(&model.UserReportOptions{ ReportingBaseOptions: model.ReportingBaseOptions{ SortColumn: "Username", PageSize: 50, }, HideActive: true, }) require.NoError(t, err) require.Len(t, userReport, 15) }) t.Run("should filter on search term", func(t *testing.T) { userReport, err := ss.User().GetUserReport(&model.UserReportOptions{ ReportingBaseOptions: model.ReportingBaseOptions{ SortColumn: "Username", PageSize: 50, }, SearchTerm: "username_1", }) require.NoError(t, err) require.Len(t, userReport, 26) userReport, err = ss.User().GetUserReport(&model.UserReportOptions{ ReportingBaseOptions: model.ReportingBaseOptions{ SortColumn: "Username", PageSize: 50, }, SearchTerm: "username_2", }) require.NoError(t, err) require.Len(t, userReport, 11) }) } func testMfaUsedTimestamps(t *testing.T, rctx request.CTX, ss store.Store) { u1, err := ss.User().Save(rctx, &model.User{ Email: "ben@invalid.mattermost.com", Username: "u1" + model.NewId(), }) require.NoError(t, err) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u1.Id)) }() tss, err := ss.User().GetMfaUsedTimestamps(u1.Id) require.NoError(t, err) require.Empty(t, tss) err = ss.User().StoreMfaUsedTimestamps(u1.Id, []int{1, 2, 3}) require.NoError(t, err) tss, err = ss.User().GetMfaUsedTimestamps(u1.Id) require.NoError(t, err) require.Equal(t, []int{1, 2, 3}, tss) } func testUserStoreSearchCommonContentFlaggingReviewers(t *testing.T, rctx request.CTX, ss store.Store) { ss.ContentFlagging().ClearCaches() u1, saveErr := ss.User().Save(rctx, &model.User{ Email: MakeEmail(), Username: "reviewer1" + model.NewId(), FirstName: "John", LastName: "Reviewer", Nickname: "johnny", }) require.NoError(t, saveErr) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u1.Id)) }() u2, saveErr := ss.User().Save(rctx, &model.User{ Email: MakeEmail(), Username: "reviewer2" + model.NewId(), FirstName: "Jane", LastName: "Smith", Nickname: "janie", }) require.NoError(t, saveErr) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u2.Id)) }() u3, saveErr := ss.User().Save(rctx, &model.User{ Email: MakeEmail(), Username: "notreviewer" + model.NewId(), DeleteAt: model.GetMillis(), // Inactive user }) require.NoError(t, saveErr) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u3.Id)) }() u4, saveErr := ss.User().Save(rctx, &model.User{ Email: MakeEmail(), Username: "otheruser" + model.NewId(), FirstName: "Bob", LastName: "Johnson", }) require.NoError(t, saveErr) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u4.Id)) }() reviewerSettings := model.ReviewerIDsSettings{ CommonReviewerIds: []string{u1.Id, u2.Id}, TeamReviewersSetting: map[string]*model.TeamReviewerSetting{}, } saveErr = ss.ContentFlagging().SaveReviewerSettings(reviewerSettings) require.NoError(t, saveErr) t.Run("search with empty term returns all common reviewers", func(t *testing.T) { users, err := ss.User().SearchCommonContentFlaggingReviewers("") require.NoError(t, err) require.Len(t, users, 2) userIds := []string{users[0].Id, users[1].Id} assert.Contains(t, userIds, u1.Id) assert.Contains(t, userIds, u2.Id) }) t.Run("search by username", func(t *testing.T) { users, err := ss.User().SearchCommonContentFlaggingReviewers("reviewer1") require.NoError(t, err) require.Len(t, users, 1) assert.Equal(t, u1.Id, users[0].Id) }) t.Run("search does not return non-reviewers", func(t *testing.T) { users, err := ss.User().SearchCommonContentFlaggingReviewers("otheruser") require.NoError(t, err) require.Empty(t, users) // u4 is not a common reviewer }) } func testUserStoreSearchTeamContentFlaggingReviewers(t *testing.T, rctx request.CTX, ss store.Store) { ss.ContentFlagging().ClearCaches() teamId := model.NewId() u1, saveErr := ss.User().Save(rctx, &model.User{ Email: MakeEmail(), Username: "teamreviewer1" + model.NewId(), FirstName: "Alice", LastName: "TeamReviewer", Nickname: "alice", }) require.NoError(t, saveErr) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u1.Id)) }() u2, saveErr := ss.User().Save(rctx, &model.User{ Email: MakeEmail(), Username: "teamreviewer2" + model.NewId(), FirstName: "Charlie", LastName: "Brown", Nickname: "charlie", }) require.NoError(t, saveErr) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u2.Id)) }() u3, saveErr := ss.User().Save(rctx, &model.User{ Email: MakeEmail(), Username: "inactiveteamreviewer" + model.NewId(), DeleteAt: model.GetMillis(), // Inactive user }) require.NoError(t, saveErr) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u3.Id)) }() u4, saveErr := ss.User().Save(rctx, &model.User{ Email: MakeEmail(), Username: "nonteamreviewer" + model.NewId(), FirstName: "David", LastName: "Wilson", }) require.NoError(t, saveErr) defer func() { require.NoError(t, ss.User().PermanentDelete(rctx, u4.Id)) }() reviewerSettings := model.ReviewerIDsSettings{ CommonReviewerIds: []string{}, TeamReviewersSetting: map[string]*model.TeamReviewerSetting{ teamId: { Enabled: model.NewPointer(true), ReviewerIds: []string{u1.Id, u2.Id}, }, }, } saveErr = ss.ContentFlagging().SaveReviewerSettings(reviewerSettings) require.NoError(t, saveErr) t.Run("search with empty term returns all team reviewers", func(t *testing.T) { users, err := ss.User().SearchTeamContentFlaggingReviewers(teamId, "") require.NoError(t, err) require.Len(t, users, 2) userIds := []string{users[0].Id, users[1].Id} assert.Contains(t, userIds, u1.Id) assert.Contains(t, userIds, u2.Id) }) t.Run("search by username", func(t *testing.T) { users, err := ss.User().SearchTeamContentFlaggingReviewers(teamId, "teamreviewer1") require.NoError(t, err) require.Len(t, users, 1) assert.Equal(t, u1.Id, users[0].Id) }) t.Run("search does not return inactive users", func(t *testing.T) { // Add inactive user as team reviewer reviewerSettings.TeamReviewersSetting[teamId].ReviewerIds = append( reviewerSettings.TeamReviewersSetting[teamId].ReviewerIds, u3.Id) err := ss.ContentFlagging().SaveReviewerSettings(reviewerSettings) require.NoError(t, err) users, err := ss.User().SearchTeamContentFlaggingReviewers(teamId, "inactiveteamreviewer") require.NoError(t, err) require.Empty(t, users) // Should not return inactive user }) t.Run("search does not return non-team-reviewers", func(t *testing.T) { users, err := ss.User().SearchTeamContentFlaggingReviewers(teamId, "nonteamreviewer") require.NoError(t, err) require.Empty(t, users) // u4 is not a team reviewer }) t.Run("search with different team returns empty", func(t *testing.T) { differentTeamId := model.NewId() users, err := ss.User().SearchTeamContentFlaggingReviewers(differentTeamId, "teamreviewer") require.NoError(t, err) require.Empty(t, users) // No reviewers for different team }) }