summaryrefslogtreecommitdiffstats
path: root/store
diff options
context:
space:
mode:
authorCorey Hulen <corey@hulen.com>2016-04-21 22:37:01 -0700
committerCorey Hulen <corey@hulen.com>2016-04-21 22:37:01 -0700
commit2e5617c29be69637acd384e85f795a0b343bec8d (patch)
tree6b8bdae1e664013b97c2dda94985375abda91aa5 /store
parent5c755463ed3a4c74a383fb4460b5be02d8868481 (diff)
downloadchat-2e5617c29be69637acd384e85f795a0b343bec8d.tar.gz
chat-2e5617c29be69637acd384e85f795a0b343bec8d.tar.bz2
chat-2e5617c29be69637acd384e85f795a0b343bec8d.zip
PLT-2057 User as a first class object (#2648)
* Adding TeamMember to system * Fixing all unit tests on the backend * Fixing merge conflicts * Fixing merge conflict * Adding javascript unit tests * Adding TeamMember to system * Fixing all unit tests on the backend * Fixing merge conflicts * Fixing merge conflict * Adding javascript unit tests * Adding client side unit test * Cleaning up the clint side tests * Fixing msg * Adding more client side unit tests * Adding more using tests * Adding last bit of client side unit tests and adding make cmd * Fixing bad merge * Fixing libraries * Updating to new client side API * Fixing borken unit test * Fixing unit tests * ugg...trying to beat gofmt * ugg...trying to beat gofmt * Cleaning up remainder of the server side routes * Adding inital load api * Increased coverage of webhook unit tests (#2660) * Adding loading ... to root html * Fixing bad merge * Removing explicit content type so superagent will guess corectly (#2685) * Fixing merge and unit tests * Adding create team UI * Fixing signup flows * Adding LDAP unit tests and enterprise unit test helper (#2702) * Add the ability to reset MFA from the commandline (#2706) * Fixing compliance unit tests * Fixing client side tests * Adding open server to system console * Moving websocket connection * Fixing unit test * Fixing unit tests * Fixing unit tests * Adding nickname and more LDAP unit tests (#2717) * Adding join open teams * Cleaning up all TODOs in the code * Fixing web sockets * Removing unused webockets file * PLT-2533 Add the ability to reset a user's MFA from the system console (#2715) * Add the ability to reset a user's MFA from the system console * Add client side unit test for adminResetMfa * Reorganizing authentication to fix LDAP error message (#2723) * Fixing failing unit test * Initial upgrade db code * Adding upgrade script * Fixing upgrade script after running on core * Update OAuth and Claim routes to work with user model changes (#2739) * Fixing perminant deletion. Adding ability to delete all user and the entire database (#2740) * Fixing team invite ldap login call (#2741) * Fixing bluebar and some img stuff * Fix all the different file upload web utils (#2743) * Fixing invalid session redirect (#2744) * Redirect on bad channel name (#2746) * Fixing a bunch of issue and removing dead code * Patch to fix error message on leave channel (#2747) * Setting EnableOpenServer to false by default * Fixing config * Fixing upgrade * Fixing reported bugs * Bug fixes for PLT-2057 * PLT-2563 Redo password recovery to use a database table (#2745) * Redo password recovery to use a database table * Update reset password audits * Split out admin and user reset password APIs to be separate * Delete password recovery when user is permanently deleted * Consolidate password resetting into a single function * Removed private channels as an option for outgoing webhooks (#2752) * PLT-2577/PLT-2552 Fixes for backstage (#2753) * Added URL to incoming webhook list * Fixed client functions for adding/removing integrations * Disallowed slash commands without trigger words * Fixed clientside handling of errors on AddCommand page * Minor auth cleanup (#2758) * Changed EditPostModal to just close if you save without making any changes (#2759) * Renamed client -> Client in async_client.jsx and fixed eslint warnings (#2756) * Fixed url in channel info modal (#2755) * Fixing reported issues * Moving to version 3 of the apis * Fixing command unit tests (#2760) * Adding team admins * Fixing DM issue * Fixing eslint error * Properly set EditPostModal's originalText state in all cases (#2762) * Update client config check to assume features is defined if server is licensed (#2772) * Fixing url link * Fixing issue with websocket crashing when sending messages to different teams
Diffstat (limited to 'store')
-rw-r--r--store/sql_audit_store.go11
-rw-r--r--store/sql_channel_store.go42
-rw-r--r--store/sql_channel_store_test.go69
-rw-r--r--store/sql_command_store_test.go7
-rw-r--r--store/sql_compliance_store_test.go4
-rw-r--r--store/sql_post_store.go14
-rw-r--r--store/sql_recovery_store.go124
-rw-r--r--store/sql_recovery_store_test.go54
-rw-r--r--store/sql_session_store.go45
-rw-r--r--store/sql_session_store_test.go24
-rw-r--r--store/sql_store.go128
-rw-r--r--store/sql_team_store.go189
-rw-r--r--store/sql_team_store_test.go172
-rw-r--r--store/sql_user_store.go217
-rw-r--r--store/sql_user_store_test.go272
-rw-r--r--store/store.go34
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
+}