diff options
Diffstat (limited to 'store')
-rw-r--r-- | store/sql_audit_store.go | 11 | ||||
-rw-r--r-- | store/sql_channel_store.go | 42 | ||||
-rw-r--r-- | store/sql_channel_store_test.go | 69 | ||||
-rw-r--r-- | store/sql_command_store_test.go | 7 | ||||
-rw-r--r-- | store/sql_compliance_store_test.go | 4 | ||||
-rw-r--r-- | store/sql_post_store.go | 14 | ||||
-rw-r--r-- | store/sql_recovery_store.go | 124 | ||||
-rw-r--r-- | store/sql_recovery_store_test.go | 54 | ||||
-rw-r--r-- | store/sql_session_store.go | 45 | ||||
-rw-r--r-- | store/sql_session_store_test.go | 24 | ||||
-rw-r--r-- | store/sql_store.go | 128 | ||||
-rw-r--r-- | store/sql_team_store.go | 189 | ||||
-rw-r--r-- | store/sql_team_store_test.go | 172 | ||||
-rw-r--r-- | store/sql_user_store.go | 217 | ||||
-rw-r--r-- | store/sql_user_store_test.go | 272 | ||||
-rw-r--r-- | store/store.go | 34 |
16 files changed, 1124 insertions, 282 deletions
diff --git a/store/sql_audit_store.go b/store/sql_audit_store.go index 7609ebc25..772a549a3 100644 --- a/store/sql_audit_store.go +++ b/store/sql_audit_store.go @@ -28,17 +28,6 @@ func NewSqlAuditStore(sqlStore *SqlStore) AuditStore { } func (s SqlAuditStore) UpgradeSchemaIfNeeded() { - // ADDED for 2.2 REMOVE for 2.6 - extraLength := s.GetMaxLengthOfColumnIfExists("Audits", "ExtraInfo") - if len(extraLength) > 0 && extraLength != "1024" { - s.AlterColumnTypeIfExists("Audits", "ExtraInfo", "VARCHAR(1024)", "VARCHAR(1024)") - } - - // ADDED for 2.2 REMOVE for 2.6 - actionLength := s.GetMaxLengthOfColumnIfExists("Audits", "Action") - if len(actionLength) > 0 && actionLength != "512" { - s.AlterColumnTypeIfExists("Audits", "Action", "VARCHAR(512)", "VARCHAR(512)") - } } func (s SqlAuditStore) CreateIndexesIfNotExists() { diff --git a/store/sql_channel_store.go b/store/sql_channel_store.go index c7ffddd56..46f56e7eb 100644 --- a/store/sql_channel_store.go +++ b/store/sql_channel_store.go @@ -95,6 +95,7 @@ func (s SqlChannelStore) SaveDirectChannel(directchannel *model.Channel, member1 if transaction, err := s.GetMaster().Begin(); err != nil { result.Err = model.NewLocAppError("SqlChannelStore.SaveDirectChannel", "store.sql_channel.save_direct_channel.open_transaction.app_error", nil, err.Error()) } else { + directchannel.TeamId = "" channelResult := s.saveChannelT(transaction, directchannel) if channelResult.Err != nil { @@ -330,7 +331,7 @@ func (s SqlChannelStore) GetChannels(teamId string, userId string) StoreChannel result := StoreResult{} var data []channelWithMember - _, err := s.GetReplica().Select(&data, "SELECT * FROM Channels, ChannelMembers WHERE Id = ChannelId AND TeamId = :TeamId AND UserId = :UserId AND DeleteAt = 0 ORDER BY DisplayName", map[string]interface{}{"TeamId": teamId, "UserId": userId}) + _, err := s.GetReplica().Select(&data, "SELECT * FROM Channels, ChannelMembers WHERE Id = ChannelId AND UserId = :UserId AND DeleteAt = 0 AND (TeamId = :TeamId OR TeamId = '') ORDER BY DisplayName", map[string]interface{}{"TeamId": teamId, "UserId": userId}) if err != nil { result.Err = model.NewLocAppError("SqlChannelStore.GetChannels", "store.sql_channel.get_channels.get.app_error", nil, "teamId="+teamId+", userId="+userId+", err="+err.Error()) @@ -411,7 +412,7 @@ func (s SqlChannelStore) GetChannelCounts(teamId string, userId string) StoreCha result := StoreResult{} var data []channelIdWithCountAndUpdateAt - _, err := s.GetReplica().Select(&data, "SELECT Id, TotalMsgCount, UpdateAt FROM Channels WHERE Id IN (SELECT ChannelId FROM ChannelMembers WHERE UserId = :UserId) AND TeamId = :TeamId AND DeleteAt = 0 ORDER BY DisplayName", map[string]interface{}{"TeamId": teamId, "UserId": userId}) + _, err := s.GetReplica().Select(&data, "SELECT Id, TotalMsgCount, UpdateAt FROM Channels WHERE Id IN (SELECT ChannelId FROM ChannelMembers WHERE UserId = :UserId) AND (TeamId = :TeamId OR TeamId = '') AND DeleteAt = 0 ORDER BY DisplayName", map[string]interface{}{"TeamId": teamId, "UserId": userId}) if err != nil { result.Err = model.NewLocAppError("SqlChannelStore.GetChannelCounts", "store.sql_channel.get_channel_counts.get.app_error", nil, "teamId="+teamId+", userId="+userId+", err="+err.Error()) @@ -441,7 +442,7 @@ func (s SqlChannelStore) GetByName(teamId string, name string) StoreChannel { channel := model.Channel{} - if err := s.GetReplica().SelectOne(&channel, "SELECT * FROM Channels WHERE TeamId = :TeamId AND Name= :Name AND DeleteAt = 0", map[string]interface{}{"TeamId": teamId, "Name": name}); err != nil { + if err := s.GetReplica().SelectOne(&channel, "SELECT * FROM Channels WHERE (TeamId = :TeamId OR TeamId = '') AND Name = :Name AND DeleteAt = 0", map[string]interface{}{"TeamId": teamId, "Name": name}); err != nil { if err == sql.ErrNoRows { result.Err = model.NewLocAppError("SqlChannelStore.GetByName", MISSING_CHANNEL_ERROR, nil, "teamId="+teamId+", "+"name="+name+", "+err.Error()) } else { @@ -719,6 +720,37 @@ func (s SqlChannelStore) PermanentDeleteMembersByUser(userId string) StoreChanne return storeChannel } +func (s SqlChannelStore) CheckPermissionsToNoTeam(channelId string, userId string) StoreChannel { + storeChannel := make(StoreChannel) + + go func() { + result := StoreResult{} + + count, err := s.GetReplica().SelectInt( + `SELECT + COUNT(0) + FROM + Channels, + ChannelMembers + WHERE + Channels.Id = ChannelMembers.ChannelId + AND Channels.DeleteAt = 0 + AND ChannelMembers.ChannelId = :ChannelId + AND ChannelMembers.UserId = :UserId`, + map[string]interface{}{"ChannelId": channelId, "UserId": userId}) + if err != nil { + result.Err = model.NewLocAppError("SqlChannelStore.CheckPermissionsTo", "store.sql_channel.check_permissions.app_error", nil, "channel_id="+channelId+", user_id="+userId+", "+err.Error()) + } else { + result.Data = count + } + + storeChannel <- result + close(storeChannel) + }() + + return storeChannel +} + func (s SqlChannelStore) CheckPermissionsTo(teamId string, channelId string, userId string) StoreChannel { storeChannel := make(StoreChannel) @@ -733,7 +765,7 @@ func (s SqlChannelStore) CheckPermissionsTo(teamId string, channelId string, use ChannelMembers WHERE Channels.Id = ChannelMembers.ChannelId - AND Channels.TeamId = :TeamId + AND (Channels.TeamId = :TeamId OR Channels.TeamId = '') AND Channels.DeleteAt = 0 AND ChannelMembers.ChannelId = :ChannelId AND ChannelMembers.UserId = :UserId`, @@ -765,7 +797,7 @@ func (s SqlChannelStore) CheckPermissionsToByName(teamId string, channelName str ChannelMembers WHERE Channels.Id = ChannelMembers.ChannelId - AND Channels.TeamId = :TeamId + AND (Channels.TeamId = :TeamId OR Channels.TeamId = '') AND Channels.Name = :Name AND Channels.DeleteAt = 0 AND ChannelMembers.UserId = :UserId`, diff --git a/store/sql_channel_store_test.go b/store/sql_channel_store_test.go index 2213aa795..1b3ea6fe5 100644 --- a/store/sql_channel_store_test.go +++ b/store/sql_channel_store_test.go @@ -67,17 +67,17 @@ func TestChannelStoreSaveDirectChannel(t *testing.T) { o1.Name = "a" + model.NewId() + "b" o1.Type = model.CHANNEL_DIRECT - u1 := model.User{} - u1.TeamId = model.NewId() + u1 := &model.User{} u1.Email = model.NewId() u1.Nickname = model.NewId() - Must(store.User().Save(&u1)) + Must(store.User().Save(u1)) + Must(store.Team().SaveMember(&model.TeamMember{TeamId: model.NewId(), UserId: u1.Id})) - u2 := model.User{} - u2.TeamId = model.NewId() + u2 := &model.User{} u2.Email = model.NewId() u2.Nickname = model.NewId() - Must(store.User().Save(&u2)) + Must(store.User().Save(u2)) + Must(store.Team().SaveMember(&model.TeamMember{TeamId: model.NewId(), UserId: u2.Id})) m1 := model.ChannelMember{} m1.ChannelId = o1.Id @@ -163,17 +163,17 @@ func TestChannelStoreGet(t *testing.T) { t.Fatal("Missing id should have failed") } - u1 := model.User{} - u1.TeamId = model.NewId() + u1 := &model.User{} u1.Email = model.NewId() u1.Nickname = model.NewId() - Must(store.User().Save(&u1)) + Must(store.User().Save(u1)) + Must(store.Team().SaveMember(&model.TeamMember{TeamId: model.NewId(), UserId: u1.Id})) u2 := model.User{} - u2.TeamId = model.NewId() u2.Email = model.NewId() u2.Nickname = model.NewId() Must(store.User().Save(&u2)) + Must(store.Team().SaveMember(&model.TeamMember{TeamId: model.NewId(), UserId: u2.Id})) o2 := model.Channel{} o2.TeamId = model.NewId() @@ -309,16 +309,16 @@ func TestChannelMemberStore(t *testing.T) { t1 := c1t1.ExtraUpdateAt u1 := model.User{} - u1.TeamId = model.NewId() u1.Email = model.NewId() u1.Nickname = model.NewId() Must(store.User().Save(&u1)) + Must(store.Team().SaveMember(&model.TeamMember{TeamId: model.NewId(), UserId: u1.Id})) u2 := model.User{} - u2.TeamId = model.NewId() u2.Email = model.NewId() u2.Nickname = model.NewId() Must(store.User().Save(&u2)) + Must(store.Team().SaveMember(&model.TeamMember{TeamId: model.NewId(), UserId: u2.Id})) o1 := model.ChannelMember{} o1.ChannelId = c1.Id @@ -405,16 +405,16 @@ func TestChannelDeleteMemberStore(t *testing.T) { t1 := c1t1.ExtraUpdateAt u1 := model.User{} - u1.TeamId = model.NewId() u1.Email = model.NewId() u1.Nickname = model.NewId() Must(store.User().Save(&u1)) + Must(store.Team().SaveMember(&model.TeamMember{TeamId: model.NewId(), UserId: u1.Id})) u2 := model.User{} - u2.TeamId = model.NewId() u2.Email = model.NewId() u2.Nickname = model.NewId() Must(store.User().Save(&u2)) + Must(store.Team().SaveMember(&model.TeamMember{TeamId: model.NewId(), UserId: u2.Id})) o1 := model.ChannelMember{} o1.ChannelId = c1.Id @@ -469,6 +469,11 @@ func TestChannelStorePermissionsTo(t *testing.T) { t.Fatal("should have permissions") } + count = (<-store.Channel().CheckPermissionsToNoTeam(o1.Id, m1.UserId)).Data.(int64) + if count != 1 { + t.Fatal("should have permissions") + } + count = (<-store.Channel().CheckPermissionsTo("junk", o1.Id, m1.UserId)).Data.(int64) if count != 0 { t.Fatal("shouldn't have permissions") @@ -479,11 +484,21 @@ func TestChannelStorePermissionsTo(t *testing.T) { t.Fatal("shouldn't have permissions") } + count = (<-store.Channel().CheckPermissionsToNoTeam("junk", m1.UserId)).Data.(int64) + if count != 0 { + t.Fatal("shouldn't have permissions") + } + count = (<-store.Channel().CheckPermissionsTo(o1.TeamId, o1.Id, "junk")).Data.(int64) if count != 0 { t.Fatal("shouldn't have permissions") } + count = (<-store.Channel().CheckPermissionsToNoTeam(o1.Id, "junk")).Data.(int64) + if count != 0 { + t.Fatal("shouldn't have permissions") + } + channelId := (<-store.Channel().CheckPermissionsToByName(o1.TeamId, o1.Name, m1.UserId)).Data.(string) if channelId != o1.Id { t.Fatal("should have permissions") @@ -786,12 +801,12 @@ func TestGetMemberCount(t *testing.T) { t.Logf("c1.Id = %v", c1.Id) - u1 := model.User{ - TeamId: teamId, + u1 := &model.User{ Email: model.NewId(), DeleteAt: 0, } - Must(store.User().Save(&u1)) + Must(store.User().Save(u1)) + Must(store.Team().SaveMember(&model.TeamMember{TeamId: teamId, UserId: u1.Id})) m1 := model.ChannelMember{ ChannelId: c1.Id, @@ -807,11 +822,11 @@ func TestGetMemberCount(t *testing.T) { } u2 := model.User{ - TeamId: teamId, Email: model.NewId(), DeleteAt: 0, } Must(store.User().Save(&u2)) + Must(store.Team().SaveMember(&model.TeamMember{TeamId: teamId, UserId: u2.Id})) m2 := model.ChannelMember{ ChannelId: c1.Id, @@ -828,11 +843,11 @@ func TestGetMemberCount(t *testing.T) { // make sure members of other channels aren't counted u3 := model.User{ - TeamId: teamId, Email: model.NewId(), DeleteAt: 0, } Must(store.User().Save(&u3)) + Must(store.Team().SaveMember(&model.TeamMember{TeamId: teamId, UserId: u3.Id})) m3 := model.ChannelMember{ ChannelId: c2.Id, @@ -848,12 +863,12 @@ func TestGetMemberCount(t *testing.T) { } // make sure inactive users aren't counted - u4 := model.User{ - TeamId: teamId, + u4 := &model.User{ Email: model.NewId(), DeleteAt: 10000, } - Must(store.User().Save(&u4)) + Must(store.User().Save(u4)) + Must(store.Team().SaveMember(&model.TeamMember{TeamId: teamId, UserId: u4.Id})) m4 := model.ChannelMember{ ChannelId: c1.Id, @@ -892,12 +907,12 @@ func TestUpdateExtrasByUser(t *testing.T) { t.Logf("c1.Id = %v", c1.Id) - u1 := model.User{ - TeamId: teamId, + u1 := &model.User{ Email: model.NewId(), DeleteAt: 0, } - Must(store.User().Save(&u1)) + Must(store.User().Save(u1)) + Must(store.Team().SaveMember(&model.TeamMember{TeamId: teamId, UserId: u1.Id})) m1 := model.ChannelMember{ ChannelId: c1.Id, @@ -907,7 +922,7 @@ func TestUpdateExtrasByUser(t *testing.T) { Must(store.Channel().SaveMember(&m1)) u1.DeleteAt = model.GetMillis() - Must(store.User().Update(&u1, true)) + Must(store.User().Update(u1, true)) if result := <-store.Channel().ExtraUpdateByUser(u1.Id, u1.DeleteAt); result.Err != nil { t.Fatal("failed to update extras by user: %v", result.Err) @@ -920,7 +935,7 @@ func TestUpdateExtrasByUser(t *testing.T) { } u1.DeleteAt = 0 - Must(store.User().Update(&u1, true)) + Must(store.User().Update(u1, true)) if result := <-store.Channel().ExtraUpdateByUser(u1.Id, u1.DeleteAt); result.Err != nil { t.Fatal("failed to update extras by user: %v", result.Err) diff --git a/store/sql_command_store_test.go b/store/sql_command_store_test.go index 644ebc9ae..ae1c61df3 100644 --- a/store/sql_command_store_test.go +++ b/store/sql_command_store_test.go @@ -16,6 +16,7 @@ func TestCommandStoreSave(t *testing.T) { o1.Method = model.COMMAND_METHOD_POST o1.TeamId = model.NewId() o1.URL = "http://nowhere.com/" + o1.Trigger = "trigger" if err := (<-store.Command().Save(&o1)).Err; err != nil { t.Fatal("couldn't save item", err) @@ -34,6 +35,7 @@ func TestCommandStoreGet(t *testing.T) { o1.Method = model.COMMAND_METHOD_POST o1.TeamId = model.NewId() o1.URL = "http://nowhere.com/" + o1.Trigger = "trigger" o1 = (<-store.Command().Save(o1)).Data.(*model.Command) @@ -58,6 +60,7 @@ func TestCommandStoreGetByTeam(t *testing.T) { o1.Method = model.COMMAND_METHOD_POST o1.TeamId = model.NewId() o1.URL = "http://nowhere.com/" + o1.Trigger = "trigger" o1 = (<-store.Command().Save(o1)).Data.(*model.Command) @@ -86,6 +89,7 @@ func TestCommandStoreDelete(t *testing.T) { o1.Method = model.COMMAND_METHOD_POST o1.TeamId = model.NewId() o1.URL = "http://nowhere.com/" + o1.Trigger = "trigger" o1 = (<-store.Command().Save(o1)).Data.(*model.Command) @@ -115,6 +119,7 @@ func TestCommandStoreDeleteByUser(t *testing.T) { o1.Method = model.COMMAND_METHOD_POST o1.TeamId = model.NewId() o1.URL = "http://nowhere.com/" + o1.Trigger = "trigger" o1 = (<-store.Command().Save(o1)).Data.(*model.Command) @@ -144,6 +149,7 @@ func TestCommandStoreUpdate(t *testing.T) { o1.Method = model.COMMAND_METHOD_POST o1.TeamId = model.NewId() o1.URL = "http://nowhere.com/" + o1.Trigger = "trigger" o1 = (<-store.Command().Save(o1)).Data.(*model.Command) @@ -162,6 +168,7 @@ func TestCommandCount(t *testing.T) { o1.Method = model.COMMAND_METHOD_POST o1.TeamId = model.NewId() o1.URL = "http://nowhere.com/" + o1.Trigger = "trigger" o1 = (<-store.Command().Save(o1)).Data.(*model.Command) diff --git a/store/sql_compliance_store_test.go b/store/sql_compliance_store_test.go index 1a41fa389..b7b270a42 100644 --- a/store/sql_compliance_store_test.go +++ b/store/sql_compliance_store_test.go @@ -58,16 +58,16 @@ func TestComplianceExport(t *testing.T) { t1 = Must(store.Team().Save(t1)).(*model.Team) u1 := &model.User{} - u1.TeamId = t1.Id u1.Email = model.NewId() u1.Username = model.NewId() u1 = Must(store.User().Save(u1)).(*model.User) + Must(store.Team().SaveMember(&model.TeamMember{TeamId: t1.Id, UserId: u1.Id})) u2 := &model.User{} - u2.TeamId = t1.Id u2.Email = model.NewId() u2.Username = model.NewId() u2 = Must(store.User().Save(u2)).(*model.User) + Must(store.Team().SaveMember(&model.TeamMember{TeamId: t1.Id, UserId: u2.Id})) c1 := &model.Channel{} c1.TeamId = t1.Id diff --git a/store/sql_post_store.go b/store/sql_post_store.go index 401306862..54b526191 100644 --- a/store/sql_post_store.go +++ b/store/sql_post_store.go @@ -652,7 +652,7 @@ func (s SqlPostStore) Search(teamId string, userId string, params *model.SearchP ChannelMembers WHERE Id = ChannelId - AND TeamId = :TeamId + AND (TeamId = :TeamId OR TeamId = '') AND UserId = :UserId AND DeleteAt = 0 CHANNEL_FILTER) @@ -693,9 +693,11 @@ func (s SqlPostStore) Search(teamId string, userId string, params *model.SearchP SELECT Id FROM - Users + Users, + TeamMembers WHERE - TeamId = :TeamId + TeamMembers.TeamId = :TeamId + AND Users.Id = TeamMembers.UserId AND Username IN (`+inClause+`))`, 1) } else if len(params.FromUsers) == 1 { queryParams["FromUser"] = params.FromUsers[0] @@ -704,9 +706,11 @@ func (s SqlPostStore) Search(teamId string, userId string, params *model.SearchP SELECT Id FROM - Users + Users, + TeamMembers WHERE - TeamId = :TeamId + TeamMembers.TeamId = :TeamId + AND Users.Id = TeamMembers.UserId AND Username = :FromUser)`, 1) } else { searchQuery = strings.Replace(searchQuery, "POST_FILTER", "", 1) diff --git a/store/sql_recovery_store.go b/store/sql_recovery_store.go new file mode 100644 index 000000000..17a444ebb --- /dev/null +++ b/store/sql_recovery_store.go @@ -0,0 +1,124 @@ +// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved. +// See License.txt for license information. + +package store + +import ( + "github.com/mattermost/platform/model" +) + +type SqlPasswordRecoveryStore struct { + *SqlStore +} + +func NewSqlPasswordRecoveryStore(sqlStore *SqlStore) PasswordRecoveryStore { + s := &SqlPasswordRecoveryStore{sqlStore} + + for _, db := range sqlStore.GetAllConns() { + table := db.AddTableWithName(model.PasswordRecovery{}, "PasswordRecovery").SetKeys(false, "UserId") + table.ColMap("UserId").SetMaxSize(26) + table.ColMap("Code").SetMaxSize(128) + } + + return s +} + +func (s SqlPasswordRecoveryStore) UpgradeSchemaIfNeeded() { +} + +func (s SqlPasswordRecoveryStore) CreateIndexesIfNotExists() { + s.CreateIndexIfNotExists("idx_password_recovery_code", "PasswordRecovery", "Code") +} + +func (s SqlPasswordRecoveryStore) SaveOrUpdate(recovery *model.PasswordRecovery) StoreChannel { + + storeChannel := make(StoreChannel) + + go func() { + result := StoreResult{} + + recovery.PreSave() + if result.Err = recovery.IsValid(); result.Err != nil { + storeChannel <- result + close(storeChannel) + return + } + + if err := s.GetReplica().SelectOne(&model.PasswordRecovery{}, "SELECT * FROM PasswordRecovery WHERE UserId = :UserId", map[string]interface{}{"UserId": recovery.UserId}); err == nil { + if _, err := s.GetMaster().Update(recovery); err != nil { + result.Err = model.NewLocAppError("SqlPasswordRecoveryStore.SaveOrUpdate", "store.sql_recover.update.app_error", nil, "") + } + } else { + if err := s.GetMaster().Insert(recovery); err != nil { + result.Err = model.NewLocAppError("SqlPasswordRecoveryStore.SaveOrUpdate", "store.sql_recover.save.app_error", nil, "") + } + } + + storeChannel <- result + close(storeChannel) + }() + + return storeChannel +} + +func (s SqlPasswordRecoveryStore) Delete(userId string) StoreChannel { + + storeChannel := make(StoreChannel) + + go func() { + result := StoreResult{} + + if _, err := s.GetMaster().Exec("DELETE FROM PasswordRecovery WHERE UserId = :UserId", map[string]interface{}{"UserId": userId}); err != nil { + result.Err = model.NewLocAppError("SqlPasswordRecoveryStore.Delete", "store.sql_recover.delete.app_error", nil, "") + } + + storeChannel <- result + close(storeChannel) + }() + + return storeChannel +} + +func (s SqlPasswordRecoveryStore) Get(userId string) StoreChannel { + + storeChannel := make(StoreChannel) + + go func() { + result := StoreResult{} + + recovery := model.PasswordRecovery{} + + if err := s.GetReplica().SelectOne(&recovery, "SELECT * FROM PasswordRecovery WHERE UserId = :UserId", map[string]interface{}{"UserId": userId}); err != nil { + result.Err = model.NewLocAppError("SqlPasswordRecoveryStore.Get", "store.sql_recover.get.app_error", nil, "") + } + + result.Data = &recovery + + storeChannel <- result + close(storeChannel) + }() + + return storeChannel +} + +func (s SqlPasswordRecoveryStore) GetByCode(code string) StoreChannel { + + storeChannel := make(StoreChannel) + + go func() { + result := StoreResult{} + + recovery := model.PasswordRecovery{} + + if err := s.GetReplica().SelectOne(&recovery, "SELECT * FROM PasswordRecovery WHERE Code = :Code", map[string]interface{}{"Code": code}); err != nil { + result.Err = model.NewLocAppError("SqlPasswordRecoveryStore.GetByCode", "store.sql_recover.get_by_code.app_error", nil, "") + } + + result.Data = &recovery + + storeChannel <- result + close(storeChannel) + }() + + return storeChannel +} diff --git a/store/sql_recovery_store_test.go b/store/sql_recovery_store_test.go new file mode 100644 index 000000000..cf1048482 --- /dev/null +++ b/store/sql_recovery_store_test.go @@ -0,0 +1,54 @@ +// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved. +// See License.txt for license information. + +package store + +import ( + "github.com/mattermost/platform/model" + "testing" +) + +func TestSqlPasswordRecoveryGet(t *testing.T) { + Setup() + + recovery := &model.PasswordRecovery{UserId: "12345678901234567890123456"} + Must(store.PasswordRecovery().SaveOrUpdate(recovery)) + + result := <-store.PasswordRecovery().Get(recovery.UserId) + rrecovery := result.Data.(*model.PasswordRecovery) + if rrecovery.Code != recovery.Code { + t.Fatal("codes didn't match") + } + + result2 := <-store.PasswordRecovery().GetByCode(recovery.Code) + rrecovery2 := result2.Data.(*model.PasswordRecovery) + if rrecovery2.Code != recovery.Code { + t.Fatal("codes didn't match") + } +} + +func TestSqlPasswordRecoverySaveOrUpdate(t *testing.T) { + Setup() + + recovery := &model.PasswordRecovery{UserId: "12345678901234567890123456"} + + if err := (<-store.PasswordRecovery().SaveOrUpdate(recovery)).Err; err != nil { + t.Fatal(err) + } + + // not duplicate, testing update + if err := (<-store.PasswordRecovery().SaveOrUpdate(recovery)).Err; err != nil { + t.Fatal(err) + } +} + +func TestSqlPasswordRecoveryDelete(t *testing.T) { + Setup() + + recovery := &model.PasswordRecovery{UserId: "12345678901234567890123456"} + Must(store.PasswordRecovery().SaveOrUpdate(recovery)) + + if err := (<-store.PasswordRecovery().Delete(recovery.UserId)).Err; err != nil { + t.Fatal(err) + } +} diff --git a/store/sql_session_store.go b/store/sql_session_store.go index 337ad16e6..525d0e5b2 100644 --- a/store/sql_session_store.go +++ b/store/sql_session_store.go @@ -21,7 +21,6 @@ func NewSqlSessionStore(sqlStore *SqlStore) SessionStore { table.ColMap("Id").SetMaxSize(26) table.ColMap("Token").SetMaxSize(26) table.ColMap("UserId").SetMaxSize(26) - table.ColMap("TeamId").SetMaxSize(26) table.ColMap("DeviceId").SetMaxSize(512) table.ColMap("Roles").SetMaxSize(64) table.ColMap("Props").SetMaxSize(1000) @@ -63,12 +62,22 @@ func (me SqlSessionStore) Save(session *model.Session) StoreChannel { l4g.Error(utils.T("store.sql_session.save.cleanup.error"), cur.Err) } + tcs := me.Team().GetTeamsForUser(session.UserId) + if err := me.GetMaster().Insert(session); err != nil { result.Err = model.NewLocAppError("SqlSessionStore.Save", "store.sql_session.save.app_error", nil, "id="+session.Id+", "+err.Error()) + return } else { result.Data = session } + if rtcs := <-tcs; rtcs.Err != nil { + result.Err = model.NewLocAppError("SqlSessionStore.Save", "store.sql_session.save.app_error", nil, "id="+session.Id+", "+rtcs.Err.Error()) + return + } else { + session.TeamMembers = rtcs.Data.([]*model.TeamMember) + } + storeChannel <- result close(storeChannel) }() @@ -91,6 +100,14 @@ func (me SqlSessionStore) Get(sessionIdOrToken string) StoreChannel { result.Err = model.NewLocAppError("SqlSessionStore.Get", "store.sql_session.get.app_error", nil, "sessionIdOrToken="+sessionIdOrToken) } else { result.Data = sessions[0] + + tcs := me.Team().GetTeamsForUser(sessions[0].UserId) + if rtcs := <-tcs; rtcs.Err != nil { + result.Err = model.NewLocAppError("SqlSessionStore.Get", "store.sql_session.get.app_error", nil, "sessionIdOrToken="+sessionIdOrToken+", "+rtcs.Err.Error()) + return + } else { + sessions[0].TeamMembers = rtcs.Data.([]*model.TeamMember) + } } storeChannel <- result @@ -111,9 +128,10 @@ func (me SqlSessionStore) GetSessions(userId string) StoreChannel { } result := StoreResult{} - var sessions []*model.Session + tcs := me.Team().GetTeamsForUser(userId) + if _, err := me.GetReplica().Select(&sessions, "SELECT * FROM Sessions WHERE UserId = :UserId ORDER BY LastActivityAt DESC", map[string]interface{}{"UserId": userId}); err != nil { result.Err = model.NewLocAppError("SqlSessionStore.GetSessions", "store.sql_session.get_sessions.app_error", nil, err.Error()) } else { @@ -121,6 +139,15 @@ func (me SqlSessionStore) GetSessions(userId string) StoreChannel { result.Data = sessions } + if rtcs := <-tcs; rtcs.Err != nil { + result.Err = model.NewLocAppError("SqlSessionStore.GetSessions", "store.sql_session.get_sessions.app_error", nil, rtcs.Err.Error()) + return + } else { + for _, session := range sessions { + session.TeamMembers = rtcs.Data.([]*model.TeamMember) + } + } + storeChannel <- result close(storeChannel) }() @@ -146,15 +173,15 @@ func (me SqlSessionStore) Remove(sessionIdOrToken string) StoreChannel { return storeChannel } -func (me SqlSessionStore) RemoveAllSessionsForTeam(teamId string) StoreChannel { +func (me SqlSessionStore) RemoveAllSessions() StoreChannel { storeChannel := make(StoreChannel) go func() { result := StoreResult{} - _, err := me.GetMaster().Exec("DELETE FROM Sessions WHERE TeamId = :TeamId", map[string]interface{}{"TeamId": teamId}) + _, err := me.GetMaster().Exec("DELETE FROM Sessions") if err != nil { - result.Err = model.NewLocAppError("SqlSessionStore.RemoveAllSessionsForTeam", "store.sql_session.remove_all_sessions_for_team.app_error", nil, "id="+teamId+", err="+err.Error()) + result.Err = model.NewLocAppError("SqlSessionStore.RemoveAllSessions", "store.sql_session.remove_all_sessions_for_team.app_error", nil, err.Error()) } storeChannel <- result @@ -256,7 +283,7 @@ func (me SqlSessionStore) UpdateDeviceId(id, deviceId string) StoreChannel { return storeChannel } -func (me SqlSessionStore) AnalyticsSessionCount(teamId string) StoreChannel { +func (me SqlSessionStore) AnalyticsSessionCount() StoreChannel { storeChannel := make(StoreChannel) go func() { @@ -269,11 +296,7 @@ func (me SqlSessionStore) AnalyticsSessionCount(teamId string) StoreChannel { Sessions WHERE ExpiresAt > :Time` - if len(teamId) > 0 { - query += " AND TeamId = :TeamId" - } - - if c, err := me.GetReplica().SelectInt(query, map[string]interface{}{"Time": model.GetMillis(), "TeamId": teamId}); err != nil { + if c, err := me.GetReplica().SelectInt(query, map[string]interface{}{"Time": model.GetMillis()}); err != nil { result.Err = model.NewLocAppError("SqlSessionStore.AnalyticsSessionCount", "store.sql_session.analytics_session_count.app_error", nil, err.Error()) } else { result.Data = c diff --git a/store/sql_session_store_test.go b/store/sql_session_store_test.go index 506695f0e..d7f07254d 100644 --- a/store/sql_session_store_test.go +++ b/store/sql_session_store_test.go @@ -13,7 +13,6 @@ func TestSessionStoreSave(t *testing.T) { s1 := model.Session{} s1.UserId = model.NewId() - s1.TeamId = model.NewId() if err := (<-store.Session().Save(&s1)).Err; err != nil { t.Fatal(err) @@ -25,17 +24,14 @@ func TestSessionGet(t *testing.T) { s1 := model.Session{} s1.UserId = model.NewId() - s1.TeamId = model.NewId() Must(store.Session().Save(&s1)) s2 := model.Session{} s2.UserId = s1.UserId - s2.TeamId = s1.TeamId Must(store.Session().Save(&s2)) s3 := model.Session{} s3.UserId = s1.UserId - s3.TeamId = s1.TeamId s3.ExpiresAt = 1 Must(store.Session().Save(&s3)) @@ -62,7 +58,6 @@ func TestSessionRemove(t *testing.T) { s1 := model.Session{} s1.UserId = model.NewId() - s1.TeamId = model.NewId() Must(store.Session().Save(&s1)) if rs1 := (<-store.Session().Get(s1.Id)); rs1.Err != nil { @@ -85,7 +80,6 @@ func TestSessionRemoveAll(t *testing.T) { s1 := model.Session{} s1.UserId = model.NewId() - s1.TeamId = model.NewId() Must(store.Session().Save(&s1)) if rs1 := (<-store.Session().Get(s1.Id)); rs1.Err != nil { @@ -96,7 +90,7 @@ func TestSessionRemoveAll(t *testing.T) { } } - Must(store.Session().RemoveAllSessionsForTeam(s1.TeamId)) + Must(store.Session().RemoveAllSessions()) if rs2 := (<-store.Session().Get(s1.Id)); rs2.Err == nil { t.Fatal("should have been removed") @@ -108,7 +102,6 @@ func TestSessionRemoveByUser(t *testing.T) { s1 := model.Session{} s1.UserId = model.NewId() - s1.TeamId = model.NewId() Must(store.Session().Save(&s1)) if rs1 := (<-store.Session().Get(s1.Id)); rs1.Err != nil { @@ -131,7 +124,6 @@ func TestSessionRemoveToken(t *testing.T) { s1 := model.Session{} s1.UserId = model.NewId() - s1.TeamId = model.NewId() Must(store.Session().Save(&s1)) if rs1 := (<-store.Session().Get(s1.Id)); rs1.Err != nil { @@ -162,7 +154,6 @@ func TestSessionUpdateDeviceId(t *testing.T) { s1 := model.Session{} s1.UserId = model.NewId() - s1.TeamId = model.NewId() Must(store.Session().Save(&s1)) if rs1 := (<-store.Session().UpdateDeviceId(s1.Id, model.PUSH_NOTIFY_APPLE+":1234567890")); rs1.Err != nil { @@ -171,7 +162,6 @@ func TestSessionUpdateDeviceId(t *testing.T) { s2 := model.Session{} s2.UserId = model.NewId() - s2.TeamId = model.NewId() Must(store.Session().Save(&s2)) if rs2 := (<-store.Session().UpdateDeviceId(s2.Id, model.PUSH_NOTIFY_APPLE+":1234567890")); rs2.Err != nil { @@ -184,7 +174,6 @@ func TestSessionStoreUpdateLastActivityAt(t *testing.T) { s1 := model.Session{} s1.UserId = model.NewId() - s1.TeamId = model.NewId() Must(store.Session().Save(&s1)) if err := (<-store.Session().UpdateLastActivityAt(s1.Id, 1234567890)).Err; err != nil { @@ -206,23 +195,14 @@ func TestSessionCount(t *testing.T) { s1 := model.Session{} s1.UserId = model.NewId() - s1.TeamId = model.NewId() s1.ExpiresAt = model.GetMillis() + 100000 Must(store.Session().Save(&s1)) - if r1 := <-store.Session().AnalyticsSessionCount(""); r1.Err != nil { + if r1 := <-store.Session().AnalyticsSessionCount(); r1.Err != nil { t.Fatal(r1.Err) } else { if r1.Data.(int64) == 0 { t.Fatal("should have at least 1 session") } } - - if r2 := <-store.Session().AnalyticsSessionCount(s1.TeamId); r2.Err != nil { - t.Fatal(r2.Err) - } else { - if r2.Data.(int64) != 1 { - t.Fatal("should have 1 session") - } - } } diff --git a/store/sql_store.go b/store/sql_store.go index 8ff5da6f7..688e1b116 100644 --- a/store/sql_store.go +++ b/store/sql_store.go @@ -36,25 +36,26 @@ const ( ) type SqlStore struct { - master *gorp.DbMap - replicas []*gorp.DbMap - team TeamStore - channel ChannelStore - post PostStore - user UserStore - audit AuditStore - compliance ComplianceStore - session SessionStore - oauth OAuthStore - system SystemStore - webhook WebhookStore - command CommandStore - preference PreferenceStore - license LicenseStore -} - -func NewSqlStore() Store { - + master *gorp.DbMap + replicas []*gorp.DbMap + team TeamStore + channel ChannelStore + post PostStore + user UserStore + audit AuditStore + compliance ComplianceStore + session SessionStore + oauth OAuthStore + system SystemStore + webhook WebhookStore + command CommandStore + preference PreferenceStore + license LicenseStore + recovery PasswordRecoveryStore + SchemaVersion string +} + +func initConnection() *SqlStore { sqlStore := &SqlStore{} sqlStore.master = setupConnection("master", utils.Cfg.SqlSettings.DriverName, @@ -75,25 +76,43 @@ func NewSqlStore() Store { } } - schemaVersion := sqlStore.GetCurrentSchemaVersion() + sqlStore.SchemaVersion = sqlStore.GetCurrentSchemaVersion() + return sqlStore +} + +func NewSqlStore() Store { + + sqlStore := initConnection() // If the version is already set then we are potentially in an 'upgrade needed' state - if schemaVersion != "" { + if sqlStore.SchemaVersion != "" { // Check to see if it's the most current database schema version - if !model.IsCurrentVersion(schemaVersion) { + if !model.IsCurrentVersion(sqlStore.SchemaVersion) { // If we are upgrading from the previous version then print a warning and continue - if model.IsPreviousVersionsSupported(schemaVersion) { - l4g.Warn(utils.T("store.sql.schema_out_of_date.warn"), schemaVersion) + if model.IsPreviousVersionsSupported(sqlStore.SchemaVersion) { + l4g.Warn(utils.T("store.sql.schema_out_of_date.warn"), sqlStore.SchemaVersion) l4g.Warn(utils.T("store.sql.schema_upgrade_attempt.warn"), model.CurrentVersion) } else { // If this is an 'upgrade needed' state but the user is attempting to skip a version then halt the world - l4g.Critical(utils.T("store.sql.schema_version.critical"), schemaVersion) + l4g.Critical(utils.T("store.sql.schema_version.critical"), sqlStore.SchemaVersion) time.Sleep(time.Second) - panic(fmt.Sprintf(utils.T("store.sql.schema_version.critical"), schemaVersion)) + panic(fmt.Sprintf(utils.T("store.sql.schema_version.critical"), sqlStore.SchemaVersion)) } } } + // This is a speical case for upgrading the schema to the 3.0 user model + // ADDED for 3.0 REMOVE for 3.4 + if sqlStore.SchemaVersion == "2.2.0" || + sqlStore.SchemaVersion == "2.1.0" || + sqlStore.SchemaVersion == "2.0.0" { + l4g.Critical("The database version of %v cannot be automatically upgraded to 3.0 schema", sqlStore.SchemaVersion) + l4g.Critical("You will need to run the command line tool './platform -upgrade_db_30'") + l4g.Critical("Please see 'http://www.mattermost.org/upgrade-to-3-0/' for more information on how to upgrade.") + time.Sleep(time.Second) + os.Exit(1) + } + sqlStore.team = NewSqlTeamStore(sqlStore) sqlStore.channel = NewSqlChannelStore(sqlStore) sqlStore.post = NewSqlPostStore(sqlStore) @@ -107,10 +126,13 @@ func NewSqlStore() Store { sqlStore.command = NewSqlCommandStore(sqlStore) sqlStore.preference = NewSqlPreferenceStore(sqlStore) sqlStore.license = NewSqlLicenseStore(sqlStore) + sqlStore.recovery = NewSqlPasswordRecoveryStore(sqlStore) err := sqlStore.master.CreateTablesIfNotExists() if err != nil { l4g.Critical(utils.T("store.sql.creating_tables.critical"), err) + time.Sleep(time.Second) + os.Exit(1) } sqlStore.team.(*SqlTeamStore).UpgradeSchemaIfNeeded() @@ -126,6 +148,7 @@ func NewSqlStore() Store { sqlStore.command.(*SqlCommandStore).UpgradeSchemaIfNeeded() sqlStore.preference.(*SqlPreferenceStore).UpgradeSchemaIfNeeded() sqlStore.license.(*SqlLicenseStore).UpgradeSchemaIfNeeded() + sqlStore.recovery.(*SqlPasswordRecoveryStore).UpgradeSchemaIfNeeded() sqlStore.team.(*SqlTeamStore).CreateIndexesIfNotExists() sqlStore.channel.(*SqlChannelStore).CreateIndexesIfNotExists() @@ -140,22 +163,44 @@ func NewSqlStore() Store { sqlStore.command.(*SqlCommandStore).CreateIndexesIfNotExists() sqlStore.preference.(*SqlPreferenceStore).CreateIndexesIfNotExists() sqlStore.license.(*SqlLicenseStore).CreateIndexesIfNotExists() + sqlStore.recovery.(*SqlPasswordRecoveryStore).CreateIndexesIfNotExists() sqlStore.preference.(*SqlPreferenceStore).DeleteUnusedFeatures() - if model.IsPreviousVersionsSupported(schemaVersion) && !model.IsCurrentVersion(schemaVersion) { + if model.IsPreviousVersionsSupported(sqlStore.SchemaVersion) && !model.IsCurrentVersion(sqlStore.SchemaVersion) { sqlStore.system.Update(&model.System{Name: "Version", Value: model.CurrentVersion}) + sqlStore.SchemaVersion = model.CurrentVersion l4g.Warn(utils.T("store.sql.upgraded.warn"), model.CurrentVersion) } - if schemaVersion == "" { + if sqlStore.SchemaVersion == "" { sqlStore.system.Save(&model.System{Name: "Version", Value: model.CurrentVersion}) + sqlStore.SchemaVersion = model.CurrentVersion l4g.Info(utils.T("store.sql.schema_set.info"), model.CurrentVersion) } return sqlStore } +// ADDED for 3.0 REMOVE for 3.4 +// This is a speical case for upgrading the schema to the 3.0 user model +func NewSqlStoreForUpgrade30() *SqlStore { + sqlStore := initConnection() + + sqlStore.team = NewSqlTeamStore(sqlStore) + sqlStore.user = NewSqlUserStore(sqlStore) + sqlStore.system = NewSqlSystemStore(sqlStore) + + err := sqlStore.master.CreateTablesIfNotExists() + if err != nil { + l4g.Critical(utils.T("store.sql.creating_tables.critical"), err) + time.Sleep(time.Second) + os.Exit(1) + } + + return sqlStore +} + func setupConnection(con_type string, driver string, dataSource string, maxIdle int, maxOpen int, trace bool) *gorp.DbMap { db, err := dbsql.Open(driver, dataSource) @@ -426,15 +471,24 @@ func (ss SqlStore) AlterColumnTypeIfExists(tableName string, columnName string, return true } +func (ss SqlStore) CreateUniqueIndexIfNotExists(indexName string, tableName string, columnName string) { + ss.createIndexIfNotExists(indexName, tableName, columnName, INDEX_TYPE_DEFAULT, true) +} + func (ss SqlStore) CreateIndexIfNotExists(indexName string, tableName string, columnName string) { - ss.createIndexIfNotExists(indexName, tableName, columnName, INDEX_TYPE_DEFAULT) + ss.createIndexIfNotExists(indexName, tableName, columnName, INDEX_TYPE_DEFAULT, false) } func (ss SqlStore) CreateFullTextIndexIfNotExists(indexName string, tableName string, columnName string) { - ss.createIndexIfNotExists(indexName, tableName, columnName, INDEX_TYPE_FULL_TEXT) + ss.createIndexIfNotExists(indexName, tableName, columnName, INDEX_TYPE_FULL_TEXT, false) } -func (ss SqlStore) createIndexIfNotExists(indexName string, tableName string, columnName string, indexType string) { +func (ss SqlStore) createIndexIfNotExists(indexName string, tableName string, columnName string, indexType string, unique bool) { + + uniqueStr := "" + if unique { + uniqueStr = "UNIQUE " + } if utils.Cfg.SqlSettings.DriverName == model.DATABASE_DRIVER_POSTGRES { _, err := ss.GetMaster().SelectStr("SELECT $1::regclass", indexName) @@ -447,7 +501,7 @@ func (ss SqlStore) createIndexIfNotExists(indexName string, tableName string, co if indexType == INDEX_TYPE_FULL_TEXT { query = "CREATE INDEX " + indexName + " ON " + tableName + " USING gin(to_tsvector('english', " + columnName + "))" } else { - query = "CREATE INDEX " + indexName + " ON " + tableName + " (" + columnName + ")" + query = "CREATE " + uniqueStr + "INDEX " + indexName + " ON " + tableName + " (" + columnName + ")" } _, err = ss.GetMaster().Exec(query) @@ -474,7 +528,7 @@ func (ss SqlStore) createIndexIfNotExists(indexName string, tableName string, co fullTextIndex = " FULLTEXT " } - _, err = ss.GetMaster().Exec("CREATE " + fullTextIndex + " INDEX " + indexName + " ON " + tableName + " (" + columnName + ")") + _, err = ss.GetMaster().Exec("CREATE " + uniqueStr + fullTextIndex + " INDEX " + indexName + " ON " + tableName + " (" + columnName + ")") if err != nil { l4g.Critical(utils.T("store.sql.create_index.critical"), err) time.Sleep(time.Second) @@ -623,6 +677,14 @@ func (ss SqlStore) License() LicenseStore { return ss.license } +func (ss SqlStore) PasswordRecovery() PasswordRecoveryStore { + return ss.recovery +} + +func (ss SqlStore) DropAllTables() { + ss.master.TruncateTables() +} + type mattermConverter struct{} func (me mattermConverter) ToDb(val interface{}) (interface{}, error) { diff --git a/store/sql_team_store.go b/store/sql_team_store.go index 8a345bfa0..c17a45d97 100644 --- a/store/sql_team_store.go +++ b/store/sql_team_store.go @@ -6,7 +6,6 @@ package store import ( "github.com/mattermost/platform/model" "github.com/mattermost/platform/utils" - "strings" ) type SqlTeamStore struct { @@ -25,6 +24,11 @@ func NewSqlTeamStore(sqlStore *SqlStore) TeamStore { table.ColMap("CompanyName").SetMaxSize(64) table.ColMap("AllowedDomains").SetMaxSize(500) table.ColMap("InviteId").SetMaxSize(32) + + tablem := db.AddTableWithName(model.TeamMember{}, "TeamMembers").SetKeys(false, "TeamId", "UserId") + tablem.ColMap("TeamId").SetMaxSize(26) + tablem.ColMap("UserId").SetMaxSize(26) + tablem.ColMap("Roles").SetMaxSize(64) } return s @@ -36,6 +40,9 @@ func (s SqlTeamStore) UpgradeSchemaIfNeeded() { func (s SqlTeamStore) CreateIndexesIfNotExists() { s.CreateIndexIfNotExists("idx_teams_name", "Teams", "Name") s.CreateIndexIfNotExists("idx_teams_invite_id", "Teams", "InviteId") + + s.CreateIndexIfNotExists("idx_teammembers_team_id", "TeamMembers", "TeamId") + s.CreateIndexIfNotExists("idx_teammembers_user_id", "TeamMembers", "UserId") } func (s SqlTeamStore) Save(team *model.Team) StoreChannel { @@ -218,17 +225,15 @@ func (s SqlTeamStore) GetByName(name string) StoreChannel { return storeChannel } -func (s SqlTeamStore) GetTeamsForEmail(email string) StoreChannel { +func (s SqlTeamStore) GetAll() StoreChannel { storeChannel := make(StoreChannel) go func() { result := StoreResult{} - email = strings.ToLower(email) - var data []*model.Team - if _, err := s.GetReplica().Select(&data, "SELECT Teams.* FROM Teams, Users WHERE Teams.Id = Users.TeamId AND Users.Email = :Email", map[string]interface{}{"Email": email}); err != nil { - result.Err = model.NewLocAppError("SqlTeamStore.GetTeamsForEmail", "store.sql_team.get_teams_for_email.app_error", nil, "email="+email+", "+err.Error()) + if _, err := s.GetReplica().Select(&data, "SELECT * FROM Teams"); err != nil { + result.Err = model.NewLocAppError("SqlTeamStore.GetAllTeams", "store.sql_team.get_all.app_error", nil, err.Error()) } for _, team := range data { @@ -246,15 +251,15 @@ func (s SqlTeamStore) GetTeamsForEmail(email string) StoreChannel { return storeChannel } -func (s SqlTeamStore) GetAll() StoreChannel { +func (s SqlTeamStore) GetTeamsByUserId(userId string) StoreChannel { storeChannel := make(StoreChannel) go func() { result := StoreResult{} var data []*model.Team - if _, err := s.GetReplica().Select(&data, "SELECT * FROM Teams"); err != nil { - result.Err = model.NewLocAppError("SqlTeamStore.GetAllTeams", "store.sql_team.get_all.app_error", nil, err.Error()) + if _, err := s.GetReplica().Select(&data, "SELECT Teams.* FROM Teams, TeamMembers WHERE TeamMembers.TeamId = Teams.Id AND TeamMembers.UserId = :UserId", map[string]interface{}{"UserId": userId}); err != nil { + result.Err = model.NewLocAppError("SqlTeamStore.GetTeamsByUserId", "store.sql_team.get_all.app_error", nil, err.Error()) } for _, team := range data { @@ -278,10 +283,10 @@ func (s SqlTeamStore) GetAllTeamListing() StoreChannel { go func() { result := StoreResult{} - query := "SELECT * FROM Teams WHERE AllowTeamListing = 1" + query := "SELECT * FROM Teams WHERE AllowOpenInvite = 1" if utils.Cfg.SqlSettings.DriverName == model.DATABASE_DRIVER_POSTGRES { - query = "SELECT * FROM Teams WHERE AllowTeamListing = true" + query = "SELECT * FROM Teams WHERE AllowOpenInvite = true" } var data []*model.Team @@ -339,3 +344,165 @@ func (s SqlTeamStore) AnalyticsTeamCount() StoreChannel { return storeChannel } + +func (s SqlTeamStore) SaveMember(member *model.TeamMember) StoreChannel { + storeChannel := make(StoreChannel) + + go func() { + result := StoreResult{} + + if result.Err = member.IsValid(); result.Err != nil { + storeChannel <- result + close(storeChannel) + return + } + + if count, err := s.GetMaster().SelectInt("SELECT COUNT(0) FROM TeamMembers WHERE TeamId = :TeamId", map[string]interface{}{"TeamId": member.TeamId}); err != nil { + result.Err = model.NewLocAppError("SqlUserStore.Save", "store.sql_user.save.member_count.app_error", nil, "teamId="+member.TeamId+", "+err.Error()) + storeChannel <- result + close(storeChannel) + return + } else if int(count) > utils.Cfg.TeamSettings.MaxUsersPerTeam { + result.Err = model.NewLocAppError("SqlUserStore.Save", "store.sql_user.save.max_accounts.app_error", nil, "teamId="+member.TeamId) + storeChannel <- result + close(storeChannel) + return + } + + if err := s.GetMaster().Insert(member); err != nil { + if IsUniqueConstraintError(err.Error(), "TeamId", "teammembers_pkey") { + result.Err = model.NewLocAppError("SqlTeamStore.SaveMember", "store.sql_team.save_member.exists.app_error", nil, "team_id="+member.TeamId+", user_id="+member.UserId+", "+err.Error()) + } else { + result.Err = model.NewLocAppError("SqlTeamStore.SaveMember", "store.sql_team.save_member.save.app_error", nil, "team_id="+member.TeamId+", user_id="+member.UserId+", "+err.Error()) + } + } else { + result.Data = member + } + + storeChannel <- result + close(storeChannel) + }() + + return storeChannel +} + +func (s SqlTeamStore) UpdateMember(member *model.TeamMember) StoreChannel { + storeChannel := make(StoreChannel) + + go func() { + result := StoreResult{} + + if result.Err = member.IsValid(); result.Err != nil { + storeChannel <- result + close(storeChannel) + return + } + + if _, err := s.GetMaster().Update(member); err != nil { + result.Err = model.NewLocAppError("SqlTeamStore.UpdateMember", "store.sql_team.save_member.save.app_error", nil, err.Error()) + } else { + result.Data = member + } + + storeChannel <- result + close(storeChannel) + }() + + return storeChannel +} + +func (s SqlTeamStore) GetMembers(teamId string) StoreChannel { + storeChannel := make(StoreChannel) + + go func() { + result := StoreResult{} + + var members []*model.TeamMember + _, err := s.GetReplica().Select(&members, "SELECT * FROM TeamMembers WHERE TeamId = :TeamId", map[string]interface{}{"TeamId": teamId}) + if err != nil { + result.Err = model.NewLocAppError("SqlTeamStore.GetMembers", "store.sql_team.get_members.app_error", nil, "teamId="+teamId+" "+err.Error()) + } else { + result.Data = members + } + + storeChannel <- result + close(storeChannel) + }() + + return storeChannel +} + +func (s SqlTeamStore) GetTeamsForUser(userId string) StoreChannel { + storeChannel := make(StoreChannel) + + go func() { + result := StoreResult{} + + var members []*model.TeamMember + _, err := s.GetReplica().Select(&members, "SELECT * FROM TeamMembers WHERE UserId = :UserId", map[string]interface{}{"UserId": userId}) + if err != nil { + result.Err = model.NewLocAppError("SqlTeamStore.GetMembers", "store.sql_team.get_members.app_error", nil, "userId="+userId+" "+err.Error()) + } else { + result.Data = members + } + + storeChannel <- result + close(storeChannel) + }() + + return storeChannel +} + +func (s SqlTeamStore) RemoveMember(teamId string, userId string) StoreChannel { + storeChannel := make(StoreChannel) + + go func() { + result := StoreResult{} + + _, err := s.GetMaster().Exec("DELETE FROM TeamMembers WHERE TeamId = :TeamId AND UserId = :UserId", map[string]interface{}{"TeamId": teamId, "UserId": userId}) + if err != nil { + result.Err = model.NewLocAppError("SqlChannelStore.RemoveMember", "store.sql_team.remove_member.app_error", nil, "team_id="+teamId+", user_id="+userId+", "+err.Error()) + } + + storeChannel <- result + close(storeChannel) + }() + + return storeChannel +} + +func (s SqlTeamStore) RemoveAllMembersByTeam(teamId string) StoreChannel { + storeChannel := make(StoreChannel) + + go func() { + result := StoreResult{} + + _, err := s.GetMaster().Exec("DELETE FROM TeamMembers WHERE TeamId = :TeamId", map[string]interface{}{"TeamId": teamId}) + if err != nil { + result.Err = model.NewLocAppError("SqlChannelStore.RemoveMember", "store.sql_team.remove_member.app_error", nil, "team_id="+teamId+", "+err.Error()) + } + + storeChannel <- result + close(storeChannel) + }() + + return storeChannel +} + +func (s SqlTeamStore) RemoveAllMembersByUser(userId string) StoreChannel { + storeChannel := make(StoreChannel) + + go func() { + result := StoreResult{} + + _, err := s.GetMaster().Exec("DELETE FROM TeamMembers WHERE UserId = :UserId", map[string]interface{}{"UserId": userId}) + if err != nil { + result.Err = model.NewLocAppError("SqlChannelStore.RemoveMember", "store.sql_team.remove_member.app_error", nil, "user_id="+userId+", "+err.Error()) + } + + storeChannel <- result + close(storeChannel) + }() + + return storeChannel +} diff --git a/store/sql_team_store_test.go b/store/sql_team_store_test.go index 743ef053f..d5ee15bc6 100644 --- a/store/sql_team_store_test.go +++ b/store/sql_team_store_test.go @@ -14,7 +14,7 @@ func TestTeamStoreSave(t *testing.T) { o1 := model.Team{} o1.DisplayName = "DisplayName" - o1.Name = "a" + model.NewId() + "b" + o1.Name = "z-z-z" + model.NewId() + "b" o1.Email = model.NewId() + "@nowhere.com" o1.Type = model.TEAM_OPEN @@ -37,7 +37,7 @@ func TestTeamStoreUpdate(t *testing.T) { o1 := model.Team{} o1.DisplayName = "DisplayName" - o1.Name = "a" + model.NewId() + "b" + o1.Name = "z-z-z" + model.NewId() + "b" o1.Email = model.NewId() + "@nowhere.com" o1.Type = model.TEAM_OPEN if err := (<-store.Team().Save(&o1)).Err; err != nil { @@ -66,7 +66,7 @@ func TestTeamStoreUpdateDisplayName(t *testing.T) { o1 := &model.Team{} o1.DisplayName = "Display Name" - o1.Name = "a" + model.NewId() + "b" + o1.Name = "z-z-z" + model.NewId() + "b" o1.Email = model.NewId() + "@nowhere.com" o1.Type = model.TEAM_OPEN o1 = (<-store.Team().Save(o1)).Data.(*model.Team) @@ -88,7 +88,7 @@ func TestTeamStoreGet(t *testing.T) { o1 := model.Team{} o1.DisplayName = "DisplayName" - o1.Name = "a" + model.NewId() + "b" + o1.Name = "z-z-z" + model.NewId() + "b" o1.Email = model.NewId() + "@nowhere.com" o1.Type = model.TEAM_OPEN Must(store.Team().Save(&o1)) @@ -111,7 +111,7 @@ func TestTeamStoreGetByName(t *testing.T) { o1 := model.Team{} o1.DisplayName = "DisplayName" - o1.Name = "a" + model.NewId() + "b" + o1.Name = "z-z-z" + model.NewId() + "b" o1.Email = model.NewId() + "@nowhere.com" o1.Type = model.TEAM_OPEN @@ -137,7 +137,7 @@ func TestTeamStoreGetByIniviteId(t *testing.T) { o1 := model.Team{} o1.DisplayName = "DisplayName" - o1.Name = "a" + model.NewId() + "b" + o1.Name = "z-z-z" + model.NewId() + "b" o1.Email = model.NewId() + "@nowhere.com" o1.Type = model.TEAM_OPEN o1.InviteId = model.NewId() @@ -180,33 +180,32 @@ func TestTeamStoreGetByIniviteId(t *testing.T) { } } -func TestTeamStoreGetForEmail(t *testing.T) { +func TestTeamStoreByUserId(t *testing.T) { Setup() - o1 := model.Team{} + o1 := &model.Team{} o1.DisplayName = "DisplayName" - o1.Name = "a" + model.NewId() + "b" + o1.Name = "z-z-z" + model.NewId() + "b" o1.Email = model.NewId() + "@nowhere.com" o1.Type = model.TEAM_OPEN - Must(store.Team().Save(&o1)) + o1.InviteId = model.NewId() + o1 = Must(store.Team().Save(o1)).(*model.Team) - u1 := model.User{} - u1.TeamId = o1.Id - u1.Email = model.NewId() - Must(store.User().Save(&u1)) + m1 := &model.TeamMember{TeamId: o1.Id, UserId: model.NewId()} + Must(store.Team().SaveMember(m1)) - if r1 := <-store.Team().GetTeamsForEmail(u1.Email); r1.Err != nil { + if r1 := <-store.Team().GetTeamsByUserId(m1.UserId); r1.Err != nil { t.Fatal(r1.Err) } else { teams := r1.Data.([]*model.Team) + if len(teams) == 0 { + t.Fatal("Should return a team") + } if teams[0].Id != o1.Id { - t.Fatal("failed to lookup by email") + t.Fatal("should be a member") } - } - if r1 := <-store.Team().GetTeamsForEmail("missing"); r1.Err != nil { - t.Fatal(r1.Err) } } @@ -215,10 +214,10 @@ func TestAllTeamListing(t *testing.T) { o1 := model.Team{} o1.DisplayName = "DisplayName" - o1.Name = "a" + model.NewId() + "b" + o1.Name = "z-z-z" + model.NewId() + "b" o1.Email = model.NewId() + "@nowhere.com" o1.Type = model.TEAM_OPEN - o1.AllowTeamListing = true + o1.AllowOpenInvite = true Must(store.Team().Save(&o1)) o2 := model.Team{} @@ -244,10 +243,10 @@ func TestDelete(t *testing.T) { o1 := model.Team{} o1.DisplayName = "DisplayName" - o1.Name = "a" + model.NewId() + "b" + o1.Name = "z-z-z" + model.NewId() + "b" o1.Email = model.NewId() + "@nowhere.com" o1.Type = model.TEAM_OPEN - o1.AllowTeamListing = true + o1.AllowOpenInvite = true Must(store.Team().Save(&o1)) o2 := model.Team{} @@ -267,10 +266,10 @@ func TestTeamCount(t *testing.T) { o1 := model.Team{} o1.DisplayName = "DisplayName" - o1.Name = "a" + model.NewId() + "b" + o1.Name = "z-z-z" + model.NewId() + "b" o1.Email = model.NewId() + "@nowhere.com" o1.Type = model.TEAM_OPEN - o1.AllowTeamListing = true + o1.AllowOpenInvite = true Must(store.Team().Save(&o1)) if r1 := <-store.Team().AnalyticsTeamCount(); r1.Err != nil { @@ -281,3 +280,126 @@ func TestTeamCount(t *testing.T) { } } } + +func TestTeamMembers(t *testing.T) { + Setup() + + teamId1 := model.NewId() + teamId2 := model.NewId() + + m1 := &model.TeamMember{TeamId: teamId1, UserId: model.NewId()} + m2 := &model.TeamMember{TeamId: teamId1, UserId: model.NewId()} + m3 := &model.TeamMember{TeamId: teamId2, UserId: model.NewId()} + + if r1 := <-store.Team().SaveMember(m1); r1.Err != nil { + t.Fatal(r1.Err) + } + + Must(store.Team().SaveMember(m2)) + Must(store.Team().SaveMember(m3)) + + if r1 := <-store.Team().GetMembers(teamId1); r1.Err != nil { + t.Fatal(r1.Err) + } else { + ms := r1.Data.([]*model.TeamMember) + + if len(ms) != 2 { + t.Fatal() + } + } + + if r1 := <-store.Team().GetMembers(teamId2); r1.Err != nil { + t.Fatal(r1.Err) + } else { + ms := r1.Data.([]*model.TeamMember) + + if len(ms) != 1 { + t.Fatal() + } + + if ms[0].UserId != m3.UserId { + t.Fatal() + + } + } + + if r1 := <-store.Team().GetTeamsForUser(m1.UserId); r1.Err != nil { + t.Fatal(r1.Err) + } else { + ms := r1.Data.([]*model.TeamMember) + + if len(ms) != 1 { + t.Fatal() + } + + if ms[0].TeamId != m1.TeamId { + t.Fatal() + + } + } + + if r1 := <-store.Team().RemoveMember(teamId1, m1.UserId); r1.Err != nil { + t.Fatal(r1.Err) + } + + if r1 := <-store.Team().GetMembers(teamId1); r1.Err != nil { + t.Fatal(r1.Err) + } else { + ms := r1.Data.([]*model.TeamMember) + + if len(ms) != 1 { + t.Fatal() + } + + if ms[0].UserId != m2.UserId { + t.Fatal() + + } + } + + Must(store.Team().SaveMember(m1)) + + if r1 := <-store.Team().RemoveAllMembersByTeam(teamId1); r1.Err != nil { + t.Fatal(r1.Err) + } + + if r1 := <-store.Team().GetMembers(teamId1); r1.Err != nil { + t.Fatal(r1.Err) + } else { + ms := r1.Data.([]*model.TeamMember) + + if len(ms) != 0 { + t.Fatal() + } + } + + uid := model.NewId() + m4 := &model.TeamMember{TeamId: teamId1, UserId: uid} + m5 := &model.TeamMember{TeamId: teamId2, UserId: uid} + Must(store.Team().SaveMember(m4)) + Must(store.Team().SaveMember(m5)) + + if r1 := <-store.Team().GetTeamsForUser(uid); r1.Err != nil { + t.Fatal(r1.Err) + } else { + ms := r1.Data.([]*model.TeamMember) + + if len(ms) != 2 { + t.Fatal() + } + } + + if r1 := <-store.Team().RemoveAllMembersByUser(uid); r1.Err != nil { + t.Fatal(r1.Err) + } + + if r1 := <-store.Team().GetTeamsForUser(m1.UserId); r1.Err != nil { + t.Fatal(r1.Err) + } else { + ms := r1.Data.([]*model.TeamMember) + + if len(ms) != 0 { + t.Fatal() + } + } +} diff --git a/store/sql_user_store.go b/store/sql_user_store.go index 2b52dfbd7..ea83458e9 100644 --- a/store/sql_user_store.go +++ b/store/sql_user_store.go @@ -6,9 +6,10 @@ package store import ( "database/sql" "fmt" - "github.com/mattermost/platform/model" - "github.com/mattermost/platform/utils" + "strconv" "strings" + + "github.com/mattermost/platform/model" ) const ( @@ -26,12 +27,11 @@ func NewSqlUserStore(sqlStore *SqlStore) UserStore { for _, db := range sqlStore.GetAllConns() { table := db.AddTableWithName(model.User{}, "Users").SetKeys(false, "Id") table.ColMap("Id").SetMaxSize(26) - table.ColMap("TeamId").SetMaxSize(26) - table.ColMap("Username").SetMaxSize(64) + table.ColMap("Username").SetMaxSize(64).SetUnique(true) table.ColMap("Password").SetMaxSize(128) table.ColMap("AuthData").SetMaxSize(128) table.ColMap("AuthService").SetMaxSize(32) - table.ColMap("Email").SetMaxSize(128) + table.ColMap("Email").SetMaxSize(128).SetUnique(true) table.ColMap("Nickname").SetMaxSize(64) table.ColMap("FirstName").SetMaxSize(64) table.ColMap("LastName").SetMaxSize(64) @@ -41,8 +41,6 @@ func NewSqlUserStore(sqlStore *SqlStore) UserStore { table.ColMap("ThemeProps").SetMaxSize(2000) table.ColMap("Locale").SetMaxSize(5) table.ColMap("MfaSecret").SetMaxSize(128) - table.SetUniqueTogether("Email", "TeamId") - table.SetUniqueTogether("Username", "TeamId") } return us @@ -51,13 +49,9 @@ func NewSqlUserStore(sqlStore *SqlStore) UserStore { func (us SqlUserStore) UpgradeSchemaIfNeeded() { // ADDED for 2.0 REMOVE for 2.4 us.CreateColumnIfNotExists("Users", "Locale", "varchar(5)", "character varying(5)", model.DEFAULT_LOCALE) - // ADDED for 2.2 REMOVE for 2.6 - us.CreateColumnIfNotExists("Users", "MfaActive", "tinyint(1)", "boolean", "0") - us.CreateColumnIfNotExists("Users", "MfaSecret", "varchar(128)", "character varying(128)", "") } func (us SqlUserStore) CreateIndexesIfNotExists() { - us.CreateIndexIfNotExists("idx_users_team_id", "Users", "TeamId") us.CreateIndexIfNotExists("idx_users_email", "Users", "Email") } @@ -82,18 +76,6 @@ func (us SqlUserStore) Save(user *model.User) StoreChannel { return } - if count, err := us.GetMaster().SelectInt("SELECT COUNT(0) FROM Users WHERE TeamId = :TeamId AND DeleteAt = 0", map[string]interface{}{"TeamId": user.TeamId}); err != nil { - result.Err = model.NewLocAppError("SqlUserStore.Save", "store.sql_user.save.member_count.app_error", nil, "teamId="+user.TeamId+", "+err.Error()) - storeChannel <- result - close(storeChannel) - return - } else if int(count) > utils.Cfg.TeamSettings.MaxUsersPerTeam { - result.Err = model.NewLocAppError("SqlUserStore.Save", "store.sql_user.save.max_accounts.app_error", nil, "teamId="+user.TeamId) - storeChannel <- result - close(storeChannel) - return - } - if err := us.GetMaster().Insert(user); err != nil { if IsUniqueConstraintError(err.Error(), "Email", "users_email_teamid_key") { result.Err = model.NewLocAppError("SqlUserStore.Save", "store.sql_user.save.email_exists.app_error", nil, "user_id="+user.Id+", "+err.Error()) @@ -140,7 +122,6 @@ func (us SqlUserStore) Update(user *model.User, allowActiveUpdate bool) StoreCha user.Password = oldUser.Password user.LastPasswordUpdate = oldUser.LastPasswordUpdate user.LastPictureUpdate = oldUser.LastPictureUpdate - user.TeamId = oldUser.TeamId user.LastActivityAt = oldUser.LastActivityAt user.LastPingAt = oldUser.LastPingAt user.EmailVerified = oldUser.EmailVerified @@ -153,7 +134,7 @@ func (us SqlUserStore) Update(user *model.User, allowActiveUpdate bool) StoreCha user.DeleteAt = oldUser.DeleteAt } - if user.IsSSOUser() { + if user.IsOAuthUser() { user.Email = oldUser.Email } else if !user.IsLDAPUser() && user.Email != oldUser.Email { user.EmailVerified = false @@ -421,13 +402,76 @@ func (us SqlUserStore) Get(id string) StoreChannel { return storeChannel } +func (us SqlUserStore) GetAll() StoreChannel { + + storeChannel := make(StoreChannel) + + go func() { + result := StoreResult{} + + var data []*model.User + if _, err := us.GetReplica().Select(&data, "SELECT * FROM Users"); err != nil { + result.Err = model.NewLocAppError("SqlUserStore.GetAll", "store.sql_user.get.app_error", nil, err.Error()) + } + + result.Data = data + + storeChannel <- result + close(storeChannel) + + }() + + return storeChannel +} + +func (s SqlUserStore) GetEtagForDirectProfiles(userId string) StoreChannel { + storeChannel := make(StoreChannel) + + go func() { + result := StoreResult{} + + updateAt, err := s.GetReplica().SelectInt(` + SELECT + UpdateAt + FROM + Users + WHERE + Id IN (SELECT DISTINCT + UserId + FROM + ChannelMembers + WHERE + ChannelMembers.UserId != :UserId + AND ChannelMembers.ChannelId IN (SELECT + Channels.Id + FROM + Channels, + ChannelMembers + WHERE + Channels.Type = 'D' + AND Channels.Id = ChannelMembers.ChannelId + AND ChannelMembers.UserId = :UserId)) + `, map[string]interface{}{"UserId": userId}) + if err != nil { + result.Data = fmt.Sprintf("%v.%v", model.CurrentVersion, model.GetMillis()) + } else { + result.Data = fmt.Sprintf("%v.%v", model.CurrentVersion, updateAt) + } + + storeChannel <- result + close(storeChannel) + }() + + return storeChannel +} + func (s SqlUserStore) GetEtagForProfiles(teamId string) StoreChannel { storeChannel := make(StoreChannel) go func() { result := StoreResult{} - updateAt, err := s.GetReplica().SelectInt("SELECT UpdateAt FROM Users WHERE TeamId = :TeamId ORDER BY UpdateAt DESC LIMIT 1", map[string]interface{}{"TeamId": teamId}) + updateAt, err := s.GetReplica().SelectInt("SELECT UpdateAt FROM Users, TeamMembers WHERE TeamMembers.TeamId = :TeamId AND Users.Id = TeamMembers.UserId ORDER BY UpdateAt DESC LIMIT 1", map[string]interface{}{"TeamId": teamId}) if err != nil { result.Data = fmt.Sprintf("%v.%v", model.CurrentVersion, model.GetMillis()) } else { @@ -450,7 +494,7 @@ func (us SqlUserStore) GetProfiles(teamId string) StoreChannel { var users []*model.User - if _, err := us.GetReplica().Select(&users, "SELECT * FROM Users WHERE TeamId = :TeamId", map[string]interface{}{"TeamId": teamId}); err != nil { + if _, err := us.GetReplica().Select(&users, "SELECT Users.* FROM Users, TeamMembers WHERE TeamMembers.TeamId = :TeamId AND Users.Id = TeamMembers.UserId", map[string]interface{}{"TeamId": teamId}); err != nil { result.Err = model.NewLocAppError("SqlUserStore.GetProfiles", "store.sql_user.get_profiles.app_error", nil, err.Error()) } else { @@ -472,6 +516,99 @@ func (us SqlUserStore) GetProfiles(teamId string) StoreChannel { return storeChannel } +func (us SqlUserStore) GetDirectProfiles(userId string) StoreChannel { + + storeChannel := make(StoreChannel) + + go func() { + result := StoreResult{} + + var users []*model.User + + if _, err := us.GetReplica().Select(&users, ` + SELECT + Users.* + FROM + Users + WHERE + Id IN (SELECT DISTINCT + UserId + FROM + ChannelMembers + WHERE + ChannelMembers.UserId != :UserId + AND ChannelMembers.ChannelId IN (SELECT + Channels.Id + FROM + Channels, + ChannelMembers + WHERE + Channels.Type = 'D' + AND Channels.Id = ChannelMembers.ChannelId + AND ChannelMembers.UserId = :UserId))`, map[string]interface{}{"UserId": userId}); err != nil { + result.Err = model.NewLocAppError("SqlUserStore.GetDirectProfiles", "store.sql_user.get_profiles.app_error", nil, err.Error()) + } else { + + userMap := make(map[string]*model.User) + + for _, u := range users { + u.Password = "" + u.AuthData = "" + userMap[u.Id] = u + } + + result.Data = userMap + } + + storeChannel <- result + close(storeChannel) + }() + + return storeChannel +} + +func (us SqlUserStore) GetProfileByIds(userIds []string) StoreChannel { + + storeChannel := make(StoreChannel) + + go func() { + result := StoreResult{} + + var users []*model.User + props := make(map[string]interface{}) + idQuery := "" + + for index, userId := range userIds { + if len(idQuery) > 0 { + idQuery += ", " + } + + props["userId"+strconv.Itoa(index)] = userId + idQuery += ":userId" + strconv.Itoa(index) + } + + if _, err := us.GetReplica().Select(&users, "SELECT * FROM Users WHERE Users.Id IN ("+idQuery+")", props); err != nil { + result.Err = model.NewLocAppError("SqlUserStore.GetProfileByIds", "store.sql_user.get_profiles.app_error", nil, err.Error()) + } else { + + userMap := make(map[string]*model.User) + + for _, u := range users { + u.Password = "" + u.AuthData = "" + userMap[u.Id] = u + } + + result.Data = userMap + } + + storeChannel <- result + close(storeChannel) + }() + + return storeChannel +} + func (us SqlUserStore) GetSystemAdminProfiles() StoreChannel { storeChannel := make(StoreChannel) @@ -503,7 +640,7 @@ func (us SqlUserStore) GetSystemAdminProfiles() StoreChannel { return storeChannel } -func (us SqlUserStore) GetByEmail(teamId string, email string) StoreChannel { +func (us SqlUserStore) GetByEmail(email string) StoreChannel { storeChannel := make(StoreChannel) @@ -514,8 +651,8 @@ func (us SqlUserStore) GetByEmail(teamId string, email string) StoreChannel { user := model.User{} - if err := us.GetReplica().SelectOne(&user, "SELECT * FROM Users WHERE TeamId = :TeamId AND Email = :Email", map[string]interface{}{"TeamId": teamId, "Email": email}); err != nil { - result.Err = model.NewLocAppError("SqlUserStore.GetByEmail", MISSING_ACCOUNT_ERROR, nil, "teamId="+teamId+", email="+email+", "+err.Error()) + if err := us.GetReplica().SelectOne(&user, "SELECT * FROM Users WHERE Email = :Email", map[string]interface{}{"Email": email}); err != nil { + result.Err = model.NewLocAppError("SqlUserStore.GetByEmail", MISSING_ACCOUNT_ERROR, nil, "email="+email+", "+err.Error()) } result.Data = &user @@ -527,7 +664,7 @@ func (us SqlUserStore) GetByEmail(teamId string, email string) StoreChannel { return storeChannel } -func (us SqlUserStore) GetByAuth(teamId string, authData string, authService string) StoreChannel { +func (us SqlUserStore) GetByAuth(authData string, authService string) StoreChannel { storeChannel := make(StoreChannel) @@ -536,11 +673,11 @@ func (us SqlUserStore) GetByAuth(teamId string, authData string, authService str user := model.User{} - if err := us.GetReplica().SelectOne(&user, "SELECT * FROM Users WHERE TeamId = :TeamId AND AuthData = :AuthData AND AuthService = :AuthService", map[string]interface{}{"TeamId": teamId, "AuthData": authData, "AuthService": authService}); err != nil { + if err := us.GetReplica().SelectOne(&user, "SELECT * FROM Users WHERE AuthData = :AuthData AND AuthService = :AuthService", map[string]interface{}{"AuthData": authData, "AuthService": authService}); err != nil { if err == sql.ErrNoRows { - result.Err = model.NewLocAppError("SqlUserStore.GetByAuth", MISSING_AUTH_ACCOUNT_ERROR, nil, "teamId="+teamId+", authData="+authData+", authService="+authService+", "+err.Error()) + result.Err = model.NewLocAppError("SqlUserStore.GetByAuth", MISSING_AUTH_ACCOUNT_ERROR, nil, "authData="+authData+", authService="+authService+", "+err.Error()) } else { - result.Err = model.NewLocAppError("SqlUserStore.GetByAuth", "store.sql_user.get_by_auth.other.app_error", nil, "teamId="+teamId+", authData="+authData+", authService="+authService+", "+err.Error()) + result.Err = model.NewLocAppError("SqlUserStore.GetByAuth", "store.sql_user.get_by_auth.other.app_error", nil, "authData="+authData+", authService="+authService+", "+err.Error()) } } @@ -553,7 +690,7 @@ func (us SqlUserStore) GetByAuth(teamId string, authData string, authService str return storeChannel } -func (us SqlUserStore) GetByUsername(teamId string, username string) StoreChannel { +func (us SqlUserStore) GetByUsername(username string) StoreChannel { storeChannel := make(StoreChannel) @@ -562,9 +699,9 @@ func (us SqlUserStore) GetByUsername(teamId string, username string) StoreChanne user := model.User{} - if err := us.GetReplica().SelectOne(&user, "SELECT * FROM Users WHERE TeamId = :TeamId AND Username = :Username", map[string]interface{}{"TeamId": teamId, "Username": username}); err != nil { + if err := us.GetReplica().SelectOne(&user, "SELECT * FROM Users WHERE Username = :Username", map[string]interface{}{"Username": username}); err != nil { result.Err = model.NewLocAppError("SqlUserStore.GetByUsername", "store.sql_user.get_by_username.app_error", - nil, "teamId="+teamId+", username="+username+", "+err.Error()) + nil, err.Error()) } result.Data = &user @@ -604,8 +741,8 @@ func (us SqlUserStore) GetForExport(teamId string) StoreChannel { var users []*model.User - if _, err := us.GetReplica().Select(&users, "SELECT * FROM Users WHERE TeamId = :TeamId", map[string]interface{}{"TeamId": teamId}); err != nil { - result.Err = model.NewLocAppError("SqlUserStore.GetProfiles", "store.sql_user.get_for_export.app_error", nil, err.Error()) + if _, err := us.GetReplica().Select(&users, "SELECT Users.* FROM Users, TeamMembers WHERE TeamMembers.TeamId = :TeamId AND Users.Id = TeamMembers.UserId", map[string]interface{}{"TeamId": teamId}); err != nil { + result.Err = model.NewLocAppError("SqlUserStore.GetForExport", "store.sql_user.get_for_export.app_error", nil, err.Error()) } else { for _, u := range users { u.Password = "" @@ -690,7 +827,7 @@ func (us SqlUserStore) AnalyticsUniqueUserCount(teamId string) StoreChannel { query := "SELECT COUNT(DISTINCT Email) FROM Users" if len(teamId) > 0 { - query += " WHERE TeamId = :TeamId" + query += ", TeamMembers WHERE TeamMembers.TeamId = :TeamId AND Users.Id = TeamMembers.UserId" } v, err := us.GetReplica().SelectInt(query, map[string]interface{}{"TeamId": teamId}) diff --git a/store/sql_user_store_test.go b/store/sql_user_store_test.go index dcd2440ac..2d17c5888 100644 --- a/store/sql_user_store_test.go +++ b/store/sql_user_store_test.go @@ -13,15 +13,18 @@ import ( func TestUserStoreSave(t *testing.T) { Setup() + teamId := model.NewId() + u1 := model.User{} u1.Email = model.NewId() u1.Username = model.NewId() - u1.TeamId = model.NewId() if err := (<-store.User().Save(&u1)).Err; err != nil { t.Fatal("couldn't save user", err) } + Must(store.Team().SaveMember(&model.TeamMember{TeamId: teamId, UserId: u1.Id})) + if err := (<-store.User().Save(&u1)).Err; err == nil { t.Fatal("shouldn't be able to update user from save") } @@ -49,37 +52,44 @@ func TestUserStoreSave(t *testing.T) { if err := (<-store.User().Save(&u1)).Err; err != nil { t.Fatal("couldn't save item", err) } + + Must(store.Team().SaveMember(&model.TeamMember{TeamId: teamId, UserId: u1.Id})) } u1.Id = "" u1.Email = model.NewId() u1.Username = model.NewId() - if err := (<-store.User().Save(&u1)).Err; err == nil { - t.Fatal("should be the limit", err) + if err := (<-store.User().Save(&u1)).Err; err != nil { + t.Fatal("couldn't save item", err) } + + if err := (<-store.Team().SaveMember(&model.TeamMember{TeamId: teamId, UserId: u1.Id})).Err; err == nil { + t.Fatal("should be the limit") + } + } func TestUserStoreUpdate(t *testing.T) { Setup() - u1 := model.User{} - u1.TeamId = model.NewId() + u1 := &model.User{} u1.Email = model.NewId() - Must(store.User().Save(&u1)) + Must(store.User().Save(u1)) + Must(store.Team().SaveMember(&model.TeamMember{TeamId: model.NewId(), UserId: u1.Id})) time.Sleep(100 * time.Millisecond) - if err := (<-store.User().Update(&u1, false)).Err; err != nil { + if err := (<-store.User().Update(u1, false)).Err; err != nil { t.Fatal(err) } u1.Id = "missing" - if err := (<-store.User().Update(&u1, false)).Err; err == nil { + if err := (<-store.User().Update(u1, false)).Err; err == nil { t.Fatal("Update should have failed because of missing key") } u1.Id = model.NewId() - if err := (<-store.User().Update(&u1, false)).Err; err == nil { + if err := (<-store.User().Update(u1, false)).Err; err == nil { t.Fatal("Update should have faile because id change") } } @@ -87,10 +97,10 @@ func TestUserStoreUpdate(t *testing.T) { func TestUserStoreUpdateLastPingAt(t *testing.T) { Setup() - u1 := model.User{} - u1.TeamId = model.NewId() + u1 := &model.User{} u1.Email = model.NewId() - Must(store.User().Save(&u1)) + Must(store.User().Save(u1)) + Must(store.Team().SaveMember(&model.TeamMember{TeamId: model.NewId(), UserId: u1.Id})) if err := (<-store.User().UpdateLastPingAt(u1.Id, 1234567890)).Err; err != nil { t.Fatal(err) @@ -109,10 +119,10 @@ func TestUserStoreUpdateLastPingAt(t *testing.T) { func TestUserStoreUpdateLastActivityAt(t *testing.T) { Setup() - u1 := model.User{} - u1.TeamId = model.NewId() + u1 := &model.User{} u1.Email = model.NewId() - Must(store.User().Save(&u1)) + Must(store.User().Save(u1)) + Must(store.Team().SaveMember(&model.TeamMember{TeamId: model.NewId(), UserId: u1.Id})) if err := (<-store.User().UpdateLastActivityAt(u1.Id, 1234567890)).Err; err != nil { t.Fatal(err) @@ -131,10 +141,10 @@ func TestUserStoreUpdateLastActivityAt(t *testing.T) { func TestUserStoreUpdateFailedPasswordAttempts(t *testing.T) { Setup() - u1 := model.User{} - u1.TeamId = model.NewId() + u1 := &model.User{} u1.Email = model.NewId() - Must(store.User().Save(&u1)) + Must(store.User().Save(u1)) + Must(store.Team().SaveMember(&model.TeamMember{TeamId: model.NewId(), UserId: u1.Id})) if err := (<-store.User().UpdateFailedPasswordAttempts(u1.Id, 3)).Err; err != nil { t.Fatal(err) @@ -153,14 +163,13 @@ func TestUserStoreUpdateFailedPasswordAttempts(t *testing.T) { func TestUserStoreUpdateUserAndSessionActivity(t *testing.T) { Setup() - u1 := model.User{} - u1.TeamId = model.NewId() + u1 := &model.User{} u1.Email = model.NewId() - Must(store.User().Save(&u1)) + Must(store.User().Save(u1)) + Must(store.Team().SaveMember(&model.TeamMember{TeamId: model.NewId(), UserId: u1.Id})) s1 := model.Session{} s1.UserId = u1.Id - s1.TeamId = u1.TeamId Must(store.Session().Save(&s1)) if err := (<-store.User().UpdateUserAndSessionActivity(u1.Id, s1.Id, 1234567890)).Err; err != nil { @@ -188,10 +197,10 @@ func TestUserStoreUpdateUserAndSessionActivity(t *testing.T) { func TestUserStoreGet(t *testing.T) { Setup() - u1 := model.User{} - u1.TeamId = model.NewId() + u1 := &model.User{} u1.Email = model.NewId() - Must(store.User().Save(&u1)) + Must(store.User().Save(u1)) + Must(store.Team().SaveMember(&model.TeamMember{TeamId: model.NewId(), UserId: u1.Id})) if r1 := <-store.User().Get(u1.Id); r1.Err != nil { t.Fatal(r1.Err) @@ -209,10 +218,10 @@ func TestUserStoreGet(t *testing.T) { func TestUserCount(t *testing.T) { Setup() - u1 := model.User{} - u1.TeamId = model.NewId() + u1 := &model.User{} u1.Email = model.NewId() - Must(store.User().Save(&u1)) + Must(store.User().Save(u1)) + Must(store.Team().SaveMember(&model.TeamMember{TeamId: model.NewId(), UserId: u1.Id})) if result := <-store.User().GetTotalUsersCount(); result.Err != nil { t.Fatal(result.Err) @@ -227,10 +236,11 @@ func TestUserCount(t *testing.T) { func TestActiveUserCount(t *testing.T) { Setup() - u1 := model.User{} - u1.TeamId = model.NewId() + u1 := &model.User{} u1.Email = model.NewId() - Must(store.User().Save(&u1)) + Must(store.User().Save(u1)) + Must(store.Team().SaveMember(&model.TeamMember{TeamId: model.NewId(), UserId: u1.Id})) + <-store.User().UpdateLastActivityAt(u1.Id, model.GetMillis()) if result := <-store.User().GetTotalActiveUsersCount(); result.Err != nil { t.Fatal(result.Err) @@ -245,17 +255,89 @@ func TestActiveUserCount(t *testing.T) { func TestUserStoreGetProfiles(t *testing.T) { Setup() - u1 := model.User{} - u1.TeamId = model.NewId() + teamId := model.NewId() + + u1 := &model.User{} u1.Email = model.NewId() - Must(store.User().Save(&u1)) + Must(store.User().Save(u1)) + Must(store.Team().SaveMember(&model.TeamMember{TeamId: teamId, UserId: u1.Id})) + + u2 := &model.User{} + u2.Email = model.NewId() + Must(store.User().Save(u2)) + Must(store.Team().SaveMember(&model.TeamMember{TeamId: teamId, UserId: u2.Id})) + + if r1 := <-store.User().GetProfiles(teamId); r1.Err != nil { + t.Fatal(r1.Err) + } else { + users := r1.Data.(map[string]*model.User) + if len(users) != 2 { + t.Fatal("invalid returned users") + } + + if users[u1.Id].Id != u1.Id { + t.Fatal("invalid returned user") + } + } + + if r2 := <-store.User().GetProfiles("123"); r2.Err != nil { + t.Fatal(r2.Err) + } else { + if len(r2.Data.(map[string]*model.User)) != 0 { + t.Fatal("should have returned empty map") + } + } +} + +func TestUserStoreGetDirectProfiles(t *testing.T) { + Setup() + + teamId := model.NewId() + + u1 := &model.User{} + u1.Email = model.NewId() + Must(store.User().Save(u1)) + Must(store.Team().SaveMember(&model.TeamMember{TeamId: teamId, UserId: u1.Id})) + + u2 := &model.User{} + u2.Email = model.NewId() + Must(store.User().Save(u2)) + Must(store.Team().SaveMember(&model.TeamMember{TeamId: teamId, UserId: u2.Id})) + + if r1 := <-store.User().GetDirectProfiles(u1.Id); r1.Err != nil { + t.Fatal(r1.Err) + } else { + users := r1.Data.(map[string]*model.User) + if len(users) != 0 { + t.Fatal("invalid returned users") + } + } + + if r2 := <-store.User().GetDirectProfiles("123"); r2.Err != nil { + t.Fatal(r2.Err) + } else { + if len(r2.Data.(map[string]*model.User)) != 0 { + t.Fatal("should have returned empty map") + } + } +} + +func TestUserStoreGetProfilesByIds(t *testing.T) { + Setup() + + teamId := model.NewId() + + u1 := &model.User{} + u1.Email = model.NewId() + Must(store.User().Save(u1)) + Must(store.Team().SaveMember(&model.TeamMember{TeamId: teamId, UserId: u1.Id})) - u2 := model.User{} - u2.TeamId = u1.TeamId + u2 := &model.User{} u2.Email = model.NewId() - Must(store.User().Save(&u2)) + Must(store.User().Save(u2)) + Must(store.Team().SaveMember(&model.TeamMember{TeamId: teamId, UserId: u2.Id})) - if r1 := <-store.User().GetProfiles(u1.TeamId); r1.Err != nil { + if r1 := <-store.User().GetProfileByIds([]string{u1.Id, u2.Id}); r1.Err != nil { t.Fatal(r1.Err) } else { users := r1.Data.(map[string]*model.User) @@ -268,6 +350,19 @@ func TestUserStoreGetProfiles(t *testing.T) { } } + if r1 := <-store.User().GetProfileByIds([]string{u1.Id}); r1.Err != nil { + t.Fatal(r1.Err) + } else { + users := r1.Data.(map[string]*model.User) + if len(users) != 1 { + t.Fatal("invalid returned users") + } + + if users[u1.Id].Id != u1.Id { + t.Fatal("invalid returned user") + } + } + if r2 := <-store.User().GetProfiles("123"); r2.Err != nil { t.Fatal(r2.Err) } else { @@ -280,15 +375,18 @@ func TestUserStoreGetProfiles(t *testing.T) { func TestUserStoreGetSystemAdminProfiles(t *testing.T) { Setup() - u1 := model.User{} - u1.TeamId = model.NewId() + teamId := model.NewId() + + u1 := &model.User{} u1.Email = model.NewId() - Must(store.User().Save(&u1)) + u1.Roles = model.ROLE_SYSTEM_ADMIN + Must(store.User().Save(u1)) + Must(store.Team().SaveMember(&model.TeamMember{TeamId: teamId, UserId: u1.Id})) - u2 := model.User{} - u2.TeamId = u1.TeamId + u2 := &model.User{} u2.Email = model.NewId() - Must(store.User().Save(&u2)) + Must(store.User().Save(u2)) + Must(store.Team().SaveMember(&model.TeamMember{TeamId: teamId, UserId: u2.Id})) if r1 := <-store.User().GetSystemAdminProfiles(); r1.Err != nil { t.Fatal(r1.Err) @@ -303,16 +401,18 @@ func TestUserStoreGetSystemAdminProfiles(t *testing.T) { func TestUserStoreGetByEmail(t *testing.T) { Setup() - u1 := model.User{} - u1.TeamId = model.NewId() + teamid := model.NewId() + + u1 := &model.User{} u1.Email = model.NewId() - Must(store.User().Save(&u1)) + Must(store.User().Save(u1)) + Must(store.Team().SaveMember(&model.TeamMember{TeamId: teamid, UserId: u1.Id})) - if err := (<-store.User().GetByEmail(u1.TeamId, u1.Email)).Err; err != nil { + if err := (<-store.User().GetByEmail(u1.Email)).Err; err != nil { t.Fatal(err) } - if err := (<-store.User().GetByEmail("", "")).Err; err == nil { + if err := (<-store.User().GetByEmail("")).Err; err == nil { t.Fatal("Should have failed because of missing email") } } @@ -320,18 +420,20 @@ func TestUserStoreGetByEmail(t *testing.T) { func TestUserStoreGetByAuthData(t *testing.T) { Setup() - u1 := model.User{} - u1.TeamId = model.NewId() + teamId := model.NewId() + + u1 := &model.User{} u1.Email = model.NewId() - u1.AuthData = "123" + u1.AuthData = "123" + model.NewId() u1.AuthService = "service" - Must(store.User().Save(&u1)) + Must(store.User().Save(u1)) + Must(store.Team().SaveMember(&model.TeamMember{TeamId: teamId, UserId: u1.Id})) - if err := (<-store.User().GetByAuth(u1.TeamId, u1.AuthData, u1.AuthService)).Err; err != nil { + if err := (<-store.User().GetByAuth(u1.AuthData, u1.AuthService)).Err; err != nil { t.Fatal(err) } - if err := (<-store.User().GetByAuth("", "", "")).Err; err == nil { + if err := (<-store.User().GetByAuth("", "")).Err; err == nil { t.Fatal("Should have failed because of missing auth data") } } @@ -339,17 +441,19 @@ func TestUserStoreGetByAuthData(t *testing.T) { func TestUserStoreGetByUsername(t *testing.T) { Setup() - u1 := model.User{} - u1.TeamId = model.NewId() + teamId := model.NewId() + + u1 := &model.User{} u1.Email = model.NewId() u1.Username = model.NewId() - Must(store.User().Save(&u1)) + Must(store.User().Save(u1)) + Must(store.Team().SaveMember(&model.TeamMember{TeamId: teamId, UserId: u1.Id})) - if err := (<-store.User().GetByUsername(u1.TeamId, u1.Username)).Err; err != nil { + if err := (<-store.User().GetByUsername(u1.Username)).Err; err != nil { t.Fatal(err) } - if err := (<-store.User().GetByUsername("", "")).Err; err == nil { + if err := (<-store.User().GetByUsername("")).Err; err == nil { t.Fatal("Should have failed because of missing username") } } @@ -357,10 +461,12 @@ func TestUserStoreGetByUsername(t *testing.T) { func TestUserStoreUpdatePassword(t *testing.T) { Setup() - u1 := model.User{} - u1.TeamId = model.NewId() + teamId := model.NewId() + + u1 := &model.User{} u1.Email = model.NewId() - Must(store.User().Save(&u1)) + Must(store.User().Save(u1)) + Must(store.Team().SaveMember(&model.TeamMember{TeamId: teamId, UserId: u1.Id})) hashedPassword := model.HashPassword("newpwd") @@ -368,7 +474,7 @@ func TestUserStoreUpdatePassword(t *testing.T) { t.Fatal(err) } - if r1 := <-store.User().GetByEmail(u1.TeamId, u1.Email); r1.Err != nil { + if r1 := <-store.User().GetByEmail(u1.Email); r1.Err != nil { t.Fatal(r1.Err) } else { user := r1.Data.(*model.User) @@ -381,10 +487,10 @@ func TestUserStoreUpdatePassword(t *testing.T) { func TestUserStoreDelete(t *testing.T) { Setup() - u1 := model.User{} - u1.TeamId = model.NewId() + u1 := &model.User{} u1.Email = model.NewId() - Must(store.User().Save(&u1)) + Must(store.User().Save(u1)) + Must(store.Team().SaveMember(&model.TeamMember{TeamId: model.NewId(), UserId: u1.Id})) if err := (<-store.User().PermanentDelete(u1.Id)).Err; err != nil { t.Fatal(err) @@ -394,10 +500,12 @@ func TestUserStoreDelete(t *testing.T) { func TestUserStoreUpdateAuthData(t *testing.T) { Setup() - u1 := model.User{} - u1.TeamId = model.NewId() + teamId := model.NewId() + + u1 := &model.User{} u1.Email = model.NewId() - Must(store.User().Save(&u1)) + Must(store.User().Save(u1)) + Must(store.Team().SaveMember(&model.TeamMember{TeamId: teamId, UserId: u1.Id})) service := "someservice" authData := "1" @@ -406,7 +514,7 @@ func TestUserStoreUpdateAuthData(t *testing.T) { t.Fatal(err) } - if r1 := <-store.User().GetByEmail(u1.TeamId, u1.Email); r1.Err != nil { + if r1 := <-store.User().GetByEmail(u1.Email); r1.Err != nil { t.Fatal(r1.Err) } else { user := r1.Data.(*model.User) @@ -430,26 +538,26 @@ func TestUserUnreadCount(t *testing.T) { c1 := model.Channel{} c1.TeamId = teamId c1.DisplayName = "Unread Messages" - c1.Name = "unread-messages" + c1.Name = "unread-messages-" + model.NewId() c1.Type = model.CHANNEL_OPEN c2 := model.Channel{} c2.TeamId = teamId c2.DisplayName = "Unread Direct" - c2.Name = "unread-direct" + c2.Name = "unread-direct-" + model.NewId() c2.Type = model.CHANNEL_DIRECT - u1 := model.User{} + u1 := &model.User{} + u1.Username = "user1" + model.NewId() u1.Email = model.NewId() - u1.Username = "user1" - u1.TeamId = teamId - Must(store.User().Save(&u1)) + Must(store.User().Save(u1)) + Must(store.Team().SaveMember(&model.TeamMember{TeamId: teamId, UserId: u1.Id})) - u2 := model.User{} + u2 := &model.User{} u2.Email = model.NewId() - u2.Username = "user2" - u2.TeamId = teamId - Must(store.User().Save(&u2)) + u2.Username = "user2" + model.NewId() + Must(store.User().Save(u2)) + Must(store.Team().SaveMember(&model.TeamMember{TeamId: teamId, UserId: u2.Id})) if err := (<-store.Channel().Save(&c1)).Err; err != nil { t.Fatal("couldn't save item", err) @@ -507,7 +615,6 @@ func TestUserStoreUpdateMfaSecret(t *testing.T) { Setup() u1 := model.User{} - u1.TeamId = model.NewId() u1.Email = model.NewId() Must(store.User().Save(&u1)) @@ -527,7 +634,6 @@ func TestUserStoreUpdateMfaActive(t *testing.T) { Setup() u1 := model.User{} - u1.TeamId = model.NewId() u1.Email = model.NewId() Must(store.User().Save(&u1)) diff --git a/store/store.go b/store/store.go index 4a4fa1481..f5c440721 100644 --- a/store/store.go +++ b/store/store.go @@ -41,8 +41,10 @@ type Store interface { Command() CommandStore Preference() PreferenceStore License() LicenseStore + PasswordRecovery() PasswordRecoveryStore MarkSystemRanUnitTests() Close() + DropAllTables() } type TeamStore interface { @@ -51,12 +53,19 @@ type TeamStore interface { UpdateDisplayName(name string, teamId string) StoreChannel Get(id string) StoreChannel GetByName(name string) StoreChannel - GetTeamsForEmail(domain string) StoreChannel GetAll() StoreChannel GetAllTeamListing() StoreChannel + GetTeamsByUserId(userId string) StoreChannel GetByInviteId(inviteId string) StoreChannel PermanentDelete(teamId string) StoreChannel AnalyticsTeamCount() StoreChannel + SaveMember(member *model.TeamMember) StoreChannel + UpdateMember(member *model.TeamMember) StoreChannel + GetMembers(teamId string) StoreChannel + GetTeamsForUser(userId string) StoreChannel + RemoveMember(teamId string, userId string) StoreChannel + RemoveAllMembersByTeam(teamId string) StoreChannel + RemoveAllMembersByUser(userId string) StoreChannel } type ChannelStore interface { @@ -82,6 +91,7 @@ type ChannelStore interface { PermanentDeleteMembersByUser(userId string) StoreChannel GetExtraMembers(channelId string, limit int) StoreChannel CheckPermissionsTo(teamId string, channelId string, userId string) StoreChannel + CheckPermissionsToNoTeam(channelId string, userId string) StoreChannel CheckOpenChannelPermissions(teamId string, channelId string) StoreChannel CheckPermissionsToByName(teamId string, channelName string, userId string) StoreChannel UpdateLastViewedAt(channelId string, userId string) StoreChannel @@ -120,12 +130,16 @@ type UserStore interface { UpdateMfaSecret(userId, secret string) StoreChannel UpdateMfaActive(userId string, active bool) StoreChannel Get(id string) StoreChannel + GetAll() StoreChannel GetProfiles(teamId string) StoreChannel - GetByEmail(teamId string, email string) StoreChannel - GetByAuth(teamId string, authData string, authService string) StoreChannel - GetByUsername(teamId string, username string) StoreChannel + GetDirectProfiles(userId string) StoreChannel + GetProfileByIds(userId []string) StoreChannel + GetByEmail(email string) StoreChannel + GetByAuth(authData string, authService string) StoreChannel + GetByUsername(username string) StoreChannel VerifyEmail(userId string) StoreChannel GetEtagForProfiles(teamId string) StoreChannel + GetEtagForDirectProfiles(userId string) StoreChannel UpdateFailedPasswordAttempts(userId string, attempts int) StoreChannel GetForExport(teamId string) StoreChannel GetTotalUsersCount() StoreChannel @@ -133,7 +147,6 @@ type UserStore interface { GetSystemAdminProfiles() StoreChannel PermanentDelete(userId string) StoreChannel AnalyticsUniqueUserCount(teamId string) StoreChannel - GetUnreadCount(userId string) StoreChannel } @@ -142,12 +155,12 @@ type SessionStore interface { Get(sessionIdOrToken string) StoreChannel GetSessions(userId string) StoreChannel Remove(sessionIdOrToken string) StoreChannel - RemoveAllSessionsForTeam(teamId string) StoreChannel + RemoveAllSessions() StoreChannel PermanentDeleteSessionsByUser(teamId string) StoreChannel UpdateLastActivityAt(sessionId string, time int64) StoreChannel UpdateRoles(userId string, roles string) StoreChannel UpdateDeviceId(id string, deviceId string) StoreChannel - AnalyticsSessionCount(teamId string) StoreChannel + AnalyticsSessionCount() StoreChannel } type AuditStore interface { @@ -228,3 +241,10 @@ type LicenseStore interface { Save(license *model.LicenseRecord) StoreChannel Get(id string) StoreChannel } + +type PasswordRecoveryStore interface { + SaveOrUpdate(recovery *model.PasswordRecovery) StoreChannel + Delete(userId string) StoreChannel + Get(userId string) StoreChannel + GetByCode(code string) StoreChannel +} |