diff options
Diffstat (limited to 'store')
-rw-r--r-- | store/sql_post_store.go | 128 | ||||
-rw-r--r-- | store/sql_post_store_test.go | 22 | ||||
-rw-r--r-- | store/sql_store.go | 31 | ||||
-rw-r--r-- | store/sql_team_store.go | 7 | ||||
-rw-r--r-- | store/sql_user_store.go | 2 | ||||
-rw-r--r-- | store/sql_webhook_store.go | 171 | ||||
-rw-r--r-- | store/sql_webhook_store_test.go | 206 | ||||
-rw-r--r-- | store/store.go | 9 |
8 files changed, 502 insertions, 74 deletions
diff --git a/store/sql_post_store.go b/store/sql_post_store.go index 07077bd64..6971de9d7 100644 --- a/store/sql_post_store.go +++ b/store/sql_post_store.go @@ -407,15 +407,23 @@ var specialSearchChar = []string{ "@", } -func (s SqlPostStore) Search(teamId string, userId string, terms string, isHashtagSearch bool) StoreChannel { +func (s SqlPostStore) Search(teamId string, userId string, params *model.SearchParams) StoreChannel { storeChannel := make(StoreChannel) go func() { result := StoreResult{} + termMap := map[string]bool{} + terms := params.Terms + + if terms == "" && params.InChannel == "" && params.FromUser == "" { + result.Data = []*model.Post{} + storeChannel <- result + return + } searchType := "Message" - if isHashtagSearch { + if params.IsHashtag { searchType = "Hashtags" for _, term := range strings.Split(terms, " ") { termMap[term] = true @@ -430,63 +438,85 @@ func (s SqlPostStore) Search(teamId string, userId string, terms string, isHasht var posts []*model.Post if utils.Cfg.SqlSettings.DriverName == model.DATABASE_DRIVER_POSTGRES { + // Parse text for wildcards + if wildcard, err := regexp.Compile("\\*($| )"); err == nil { + terms = wildcard.ReplaceAllLiteralString(terms, "* ") + } + } + searchQuery := ` + SELECT + * + FROM + Posts + WHERE + DeleteAt = 0 + POST_FILTER + AND ChannelId IN ( + SELECT + Id + FROM + Channels, + ChannelMembers + WHERE + Id = ChannelId + AND TeamId = :TeamId + AND UserId = :UserId + AND DeleteAt = 0 + CHANNEL_FILTER) + SEARCH_CLAUSE + ORDER BY CreateAt DESC + LIMIT 100` + + if params.InChannel != "" { + searchQuery = strings.Replace(searchQuery, "CHANNEL_FILTER", "AND Name = :InChannel", 1) + } else { + searchQuery = strings.Replace(searchQuery, "CHANNEL_FILTER", "", 1) + } + + if params.FromUser != "" { + searchQuery = strings.Replace(searchQuery, "POST_FILTER", ` + AND UserId IN ( + SELECT + Id + FROM + Users + WHERE + TeamId = :TeamId + AND Username = :FromUser)`, 1) + } else { + searchQuery = strings.Replace(searchQuery, "POST_FILTER", "", 1) + } + + if terms == "" { + // we've already confirmed that we have a channel or user to search for + searchQuery = strings.Replace(searchQuery, "SEARCH_CLAUSE", "", 1) + } else if utils.Cfg.SqlSettings.DriverName == model.DATABASE_DRIVER_POSTGRES { // Parse text for wildcards if wildcard, err := regexp.Compile("\\*($| )"); err == nil { terms = wildcard.ReplaceAllLiteralString(terms, ":* ") } - searchQuery := fmt.Sprintf(`SELECT - * - FROM - Posts - WHERE - DeleteAt = 0 - AND ChannelId IN (SELECT - Id - FROM - Channels, - ChannelMembers - WHERE - Id = ChannelId AND TeamId = $1 - AND UserId = $2 - AND DeleteAt = 0) - AND %s @@ to_tsquery($3) - ORDER BY CreateAt DESC - LIMIT 100`, searchType) - terms = strings.Join(strings.Fields(terms), " | ") - _, err := s.GetReplica().Select(&posts, searchQuery, teamId, userId, terms) - if err != nil { - result.Err = model.NewAppError("SqlPostStore.Search", "We encounted an error while searching for posts", "teamId="+teamId+", err="+err.Error()) - - } + searchClause := fmt.Sprintf("AND %s @@ to_tsquery(:Terms)", searchType) + searchQuery = strings.Replace(searchQuery, "SEARCH_CLAUSE", searchClause, 1) } else if utils.Cfg.SqlSettings.DriverName == model.DATABASE_DRIVER_MYSQL { - searchQuery := fmt.Sprintf(`SELECT - * - FROM - Posts - WHERE - DeleteAt = 0 - AND ChannelId IN (SELECT - Id - FROM - Channels, - ChannelMembers - WHERE - Id = ChannelId AND TeamId = ? - AND UserId = ? - AND DeleteAt = 0) - AND MATCH (%s) AGAINST (? IN BOOLEAN MODE) - ORDER BY CreateAt DESC - LIMIT 100`, searchType) - - _, err := s.GetReplica().Select(&posts, searchQuery, teamId, userId, terms) - if err != nil { - result.Err = model.NewAppError("SqlPostStore.Search", "We encounted an error while searching for posts", "teamId="+teamId+", err="+err.Error()) + searchClause := fmt.Sprintf("AND MATCH (%s) AGAINST (:Terms IN BOOLEAN MODE)", searchType) + searchQuery = strings.Replace(searchQuery, "SEARCH_CLAUSE", searchClause, 1) + } - } + queryParams := map[string]interface{}{ + "TeamId": teamId, + "UserId": userId, + "Terms": terms, + "InChannel": params.InChannel, + "FromUser": params.FromUser, + } + + _, err := s.GetReplica().Select(&posts, searchQuery, queryParams) + if err != nil { + result.Err = model.NewAppError("SqlPostStore.Search", "We encounted an error while searching for posts", "teamId="+teamId+", err="+err.Error()) } list := &model.PostList{Order: make([]string, 0, len(posts))} diff --git a/store/sql_post_store_test.go b/store/sql_post_store_test.go index 9a7679454..b2256417e 100644 --- a/store/sql_post_store_test.go +++ b/store/sql_post_store_test.go @@ -525,57 +525,57 @@ func TestPostStoreSearch(t *testing.T) { o5.Hashtags = "#secret #howdy" o5 = (<-store.Post().Save(o5)).Data.(*model.Post) - r1 := (<-store.Post().Search(teamId, userId, "corey", false)).Data.(*model.PostList) + r1 := (<-store.Post().Search(teamId, userId, &model.SearchParams{Terms: "corey", IsHashtag: false})).Data.(*model.PostList) if len(r1.Order) != 1 && r1.Order[0] != o1.Id { t.Fatal("returned wrong search result") } - r3 := (<-store.Post().Search(teamId, userId, "new", false)).Data.(*model.PostList) + r3 := (<-store.Post().Search(teamId, userId, &model.SearchParams{Terms: "new", IsHashtag: false})).Data.(*model.PostList) if len(r3.Order) != 2 && r3.Order[0] != o1.Id { t.Fatal("returned wrong search result") } - r4 := (<-store.Post().Search(teamId, userId, "john", false)).Data.(*model.PostList) + r4 := (<-store.Post().Search(teamId, userId, &model.SearchParams{Terms: "john", IsHashtag: false})).Data.(*model.PostList) if len(r4.Order) != 1 && r4.Order[0] != o2.Id { t.Fatal("returned wrong search result") } - r5 := (<-store.Post().Search(teamId, userId, "matter*", false)).Data.(*model.PostList) + r5 := (<-store.Post().Search(teamId, userId, &model.SearchParams{Terms: "matter*", IsHashtag: false})).Data.(*model.PostList) if len(r5.Order) != 1 && r5.Order[0] != o1.Id { t.Fatal("returned wrong search result") } - r6 := (<-store.Post().Search(teamId, userId, "#hashtag", true)).Data.(*model.PostList) + r6 := (<-store.Post().Search(teamId, userId, &model.SearchParams{Terms: "#hashtag", IsHashtag: true})).Data.(*model.PostList) if len(r6.Order) != 1 && r6.Order[0] != o4.Id { t.Fatal("returned wrong search result") } - r7 := (<-store.Post().Search(teamId, userId, "#secret", true)).Data.(*model.PostList) + r7 := (<-store.Post().Search(teamId, userId, &model.SearchParams{Terms: "#secret", IsHashtag: true})).Data.(*model.PostList) if len(r7.Order) != 1 && r7.Order[0] != o5.Id { t.Fatal("returned wrong search result") } - r8 := (<-store.Post().Search(teamId, userId, "@thisshouldmatchnothing", true)).Data.(*model.PostList) + r8 := (<-store.Post().Search(teamId, userId, &model.SearchParams{Terms: "@thisshouldmatchnothing", IsHashtag: true})).Data.(*model.PostList) if len(r8.Order) != 0 { t.Fatal("returned wrong search result") } - r9 := (<-store.Post().Search(teamId, userId, "mattermost jersey", false)).Data.(*model.PostList) + r9 := (<-store.Post().Search(teamId, userId, &model.SearchParams{Terms: "mattermost jersey", IsHashtag: false})).Data.(*model.PostList) if len(r9.Order) != 2 { t.Fatal("returned wrong search result") } - r10 := (<-store.Post().Search(teamId, userId, "matter* jer*", false)).Data.(*model.PostList) + r10 := (<-store.Post().Search(teamId, userId, &model.SearchParams{Terms: "matter* jer*", IsHashtag: false})).Data.(*model.PostList) if len(r10.Order) != 2 { t.Fatal("returned wrong search result") } - r11 := (<-store.Post().Search(teamId, userId, "message blargh", false)).Data.(*model.PostList) + r11 := (<-store.Post().Search(teamId, userId, &model.SearchParams{Terms: "message blargh", IsHashtag: false})).Data.(*model.PostList) if len(r11.Order) != 1 { t.Fatal("returned wrong search result") } - r12 := (<-store.Post().Search(teamId, userId, "blargh>", false)).Data.(*model.PostList) + r12 := (<-store.Post().Search(teamId, userId, &model.SearchParams{Terms: "blargh>", IsHashtag: false})).Data.(*model.PostList) if len(r12.Order) != 1 { t.Fatal("returned wrong search result") } diff --git a/store/sql_store.go b/store/sql_store.go index 692ac2664..d4d8fdf73 100644 --- a/store/sql_store.go +++ b/store/sql_store.go @@ -30,6 +30,11 @@ import ( "github.com/mattermost/platform/utils" ) +const ( + INDEX_TYPE_FULL_TEXT = "full_text" + INDEX_TYPE_DEFAULT = "default" +) + type SqlStore struct { master *gorp.DbMap replicas []*gorp.DbMap @@ -74,7 +79,14 @@ func NewSqlStore() Store { // Check to see if it's the most current database schema version if !model.IsCurrentVersion(schemaVersion) { // If we are upgrading from the previous version then print a warning and continue - if model.IsPreviousVersion(schemaVersion) { + + // Special case + isSchemaVersion07 := false + if schemaVersion == "0.7.1" || schemaVersion == "0.7.0" { + isSchemaVersion07 = true + } + + if model.IsPreviousVersion(schemaVersion) || isSchemaVersion07 { l4g.Warn("The database schema version of " + schemaVersion + " appears to be out of date") l4g.Warn("Attempting to upgrade the database schema version to " + model.CurrentVersion) } else { @@ -86,6 +98,13 @@ func NewSqlStore() Store { } } + // REMOVE in 1.2 + if sqlStore.DoesTableExist("Sessions") { + if sqlStore.DoesColumnExist("Sessions", "AltId") { + sqlStore.GetMaster().Exec("DROP TABLE IF EXISTS Sessions") + } + } + sqlStore.team = NewSqlTeamStore(sqlStore) sqlStore.channel = NewSqlChannelStore(sqlStore) sqlStore.post = NewSqlPostStore(sqlStore) @@ -363,14 +382,14 @@ func (ss SqlStore) RemoveColumnIfExists(tableName string, columnName string) boo // } func (ss SqlStore) CreateIndexIfNotExists(indexName string, tableName string, columnName string) { - ss.createIndexIfNotExists(indexName, tableName, columnName, false) + ss.createIndexIfNotExists(indexName, tableName, columnName, INDEX_TYPE_DEFAULT) } func (ss SqlStore) CreateFullTextIndexIfNotExists(indexName string, tableName string, columnName string) { - ss.createIndexIfNotExists(indexName, tableName, columnName, true) + ss.createIndexIfNotExists(indexName, tableName, columnName, INDEX_TYPE_FULL_TEXT) } -func (ss SqlStore) createIndexIfNotExists(indexName string, tableName string, columnName string, fullText bool) { +func (ss SqlStore) createIndexIfNotExists(indexName string, tableName string, columnName string, indexType string) { if utils.Cfg.SqlSettings.DriverName == model.DATABASE_DRIVER_POSTGRES { _, err := ss.GetMaster().SelectStr("SELECT $1::regclass", indexName) @@ -380,7 +399,7 @@ func (ss SqlStore) createIndexIfNotExists(indexName string, tableName string, co } query := "" - if fullText { + 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 + ")" @@ -406,7 +425,7 @@ func (ss SqlStore) createIndexIfNotExists(indexName string, tableName string, co } fullTextIndex := "" - if fullText { + if indexType == INDEX_TYPE_FULL_TEXT { fullTextIndex = " FULLTEXT " } diff --git a/store/sql_team_store.go b/store/sql_team_store.go index de44782cf..380d979bd 100644 --- a/store/sql_team_store.go +++ b/store/sql_team_store.go @@ -5,6 +5,7 @@ package store import ( "github.com/mattermost/platform/model" + "github.com/mattermost/platform/utils" ) type SqlTeamStore struct { @@ -28,6 +29,8 @@ func NewSqlTeamStore(sqlStore *SqlStore) TeamStore { } func (s SqlTeamStore) UpgradeSchemaIfNeeded() { + // REMOVE in 1.2 + s.RemoveColumnIfExists("Teams", "AllowValet") } func (s SqlTeamStore) CreateIndexesIfNotExists() { @@ -50,7 +53,7 @@ func (s SqlTeamStore) Save(team *model.Team) StoreChannel { team.PreSave() - if result.Err = team.IsValid(); result.Err != nil { + if result.Err = team.IsValid(*utils.Cfg.TeamSettings.RestrictTeamNames); result.Err != nil { storeChannel <- result close(storeChannel) return @@ -82,7 +85,7 @@ func (s SqlTeamStore) Update(team *model.Team) StoreChannel { team.PreUpdate() - if result.Err = team.IsValid(); result.Err != nil { + if result.Err = team.IsValid(*utils.Cfg.TeamSettings.RestrictTeamNames); result.Err != nil { storeChannel <- result close(storeChannel) return diff --git a/store/sql_user_store.go b/store/sql_user_store.go index dc6b07a16..a2b317afa 100644 --- a/store/sql_user_store.go +++ b/store/sql_user_store.go @@ -41,6 +41,8 @@ func NewSqlUserStore(sqlStore *SqlStore) UserStore { } func (us SqlUserStore) UpgradeSchemaIfNeeded() { + // REMOVE in 1.2 + us.CreateColumnIfNotExists("Users", "ThemeProps", "varchar(2000)", "character varying(2000)", "{}") } func (us SqlUserStore) CreateIndexesIfNotExists() { diff --git a/store/sql_webhook_store.go b/store/sql_webhook_store.go index 42a91a80e..1910984f0 100644 --- a/store/sql_webhook_store.go +++ b/store/sql_webhook_store.go @@ -20,6 +20,15 @@ func NewSqlWebhookStore(sqlStore *SqlStore) WebhookStore { table.ColMap("UserId").SetMaxSize(26) table.ColMap("ChannelId").SetMaxSize(26) table.ColMap("TeamId").SetMaxSize(26) + + tableo := db.AddTableWithName(model.OutgoingWebhook{}, "OutgoingWebhooks").SetKeys(false, "Id") + tableo.ColMap("Id").SetMaxSize(26) + tableo.ColMap("Token").SetMaxSize(26) + tableo.ColMap("CreatorId").SetMaxSize(26) + tableo.ColMap("ChannelId").SetMaxSize(26) + tableo.ColMap("TeamId").SetMaxSize(26) + tableo.ColMap("TriggerWords").SetMaxSize(1024) + tableo.ColMap("CallbackURLs").SetMaxSize(1024) } return s @@ -29,8 +38,9 @@ func (s SqlWebhookStore) UpgradeSchemaIfNeeded() { } func (s SqlWebhookStore) CreateIndexesIfNotExists() { - s.CreateIndexIfNotExists("idx_webhook_user_id", "IncomingWebhooks", "UserId") - s.CreateIndexIfNotExists("idx_webhook_team_id", "IncomingWebhooks", "TeamId") + s.CreateIndexIfNotExists("idx_incoming_webhook_user_id", "IncomingWebhooks", "UserId") + s.CreateIndexIfNotExists("idx_incoming_webhook_team_id", "IncomingWebhooks", "TeamId") + s.CreateIndexIfNotExists("idx_outgoing_webhook_team_id", "OutgoingWebhooks", "TeamId") } func (s SqlWebhookStore) SaveIncoming(webhook *model.IncomingWebhook) StoreChannel { @@ -126,3 +136,160 @@ func (s SqlWebhookStore) GetIncomingByUser(userId string) StoreChannel { return storeChannel } + +func (s SqlWebhookStore) SaveOutgoing(webhook *model.OutgoingWebhook) StoreChannel { + storeChannel := make(StoreChannel) + + go func() { + result := StoreResult{} + + if len(webhook.Id) > 0 { + result.Err = model.NewAppError("SqlWebhookStore.SaveOutgoing", + "You cannot overwrite an existing OutgoingWebhook", "id="+webhook.Id) + storeChannel <- result + close(storeChannel) + return + } + + webhook.PreSave() + if result.Err = webhook.IsValid(); result.Err != nil { + storeChannel <- result + close(storeChannel) + return + } + + if err := s.GetMaster().Insert(webhook); err != nil { + result.Err = model.NewAppError("SqlWebhookStore.SaveOutgoing", "We couldn't save the OutgoingWebhook", "id="+webhook.Id+", "+err.Error()) + } else { + result.Data = webhook + } + + storeChannel <- result + close(storeChannel) + }() + + return storeChannel +} + +func (s SqlWebhookStore) GetOutgoing(id string) StoreChannel { + storeChannel := make(StoreChannel) + + go func() { + result := StoreResult{} + + var webhook model.OutgoingWebhook + + if err := s.GetReplica().SelectOne(&webhook, "SELECT * FROM OutgoingWebhooks WHERE Id = :Id AND DeleteAt = 0", map[string]interface{}{"Id": id}); err != nil { + result.Err = model.NewAppError("SqlWebhookStore.GetOutgoing", "We couldn't get the webhook", "id="+id+", err="+err.Error()) + } + + result.Data = &webhook + + storeChannel <- result + close(storeChannel) + }() + + return storeChannel +} + +func (s SqlWebhookStore) GetOutgoingByCreator(userId string) StoreChannel { + storeChannel := make(StoreChannel) + + go func() { + result := StoreResult{} + + var webhooks []*model.OutgoingWebhook + + if _, err := s.GetReplica().Select(&webhooks, "SELECT * FROM OutgoingWebhooks WHERE CreatorId = :UserId AND DeleteAt = 0", map[string]interface{}{"UserId": userId}); err != nil { + result.Err = model.NewAppError("SqlWebhookStore.GetOutgoingByCreator", "We couldn't get the webhooks", "userId="+userId+", err="+err.Error()) + } + + result.Data = webhooks + + storeChannel <- result + close(storeChannel) + }() + + return storeChannel +} + +func (s SqlWebhookStore) GetOutgoingByChannel(channelId string) StoreChannel { + storeChannel := make(StoreChannel) + + go func() { + result := StoreResult{} + + var webhooks []*model.OutgoingWebhook + + if _, err := s.GetReplica().Select(&webhooks, "SELECT * FROM OutgoingWebhooks WHERE ChannelId = :ChannelId AND DeleteAt = 0", map[string]interface{}{"ChannelId": channelId}); err != nil { + result.Err = model.NewAppError("SqlWebhookStore.GetOutgoingByChannel", "We couldn't get the webhooks", "channelId="+channelId+", err="+err.Error()) + } + + result.Data = webhooks + + storeChannel <- result + close(storeChannel) + }() + + return storeChannel +} + +func (s SqlWebhookStore) GetOutgoingByTeam(teamId string) StoreChannel { + storeChannel := make(StoreChannel) + + go func() { + result := StoreResult{} + + var webhooks []*model.OutgoingWebhook + + if _, err := s.GetReplica().Select(&webhooks, "SELECT * FROM OutgoingWebhooks WHERE TeamId = :TeamId AND DeleteAt = 0", map[string]interface{}{"TeamId": teamId}); err != nil { + result.Err = model.NewAppError("SqlWebhookStore.GetOutgoingByTeam", "We couldn't get the webhooks", "teamId="+teamId+", err="+err.Error()) + } + + result.Data = webhooks + + storeChannel <- result + close(storeChannel) + }() + + return storeChannel +} + +func (s SqlWebhookStore) DeleteOutgoing(webhookId string, time int64) StoreChannel { + storeChannel := make(StoreChannel) + + go func() { + result := StoreResult{} + + _, err := s.GetMaster().Exec("Update OutgoingWebhooks SET DeleteAt = :DeleteAt, UpdateAt = :UpdateAt WHERE Id = :Id", map[string]interface{}{"DeleteAt": time, "UpdateAt": time, "Id": webhookId}) + if err != nil { + result.Err = model.NewAppError("SqlWebhookStore.DeleteOutgoing", "We couldn't delete the webhook", "id="+webhookId+", err="+err.Error()) + } + + storeChannel <- result + close(storeChannel) + }() + + return storeChannel +} + +func (s SqlWebhookStore) UpdateOutgoing(hook *model.OutgoingWebhook) StoreChannel { + storeChannel := make(StoreChannel) + + go func() { + result := StoreResult{} + + hook.UpdateAt = model.GetMillis() + + if _, err := s.GetMaster().Update(hook); err != nil { + result.Err = model.NewAppError("SqlWebhookStore.UpdateOutgoing", "We couldn't update the webhook", "id="+hook.Id+", "+err.Error()) + } else { + result.Data = hook + } + + storeChannel <- result + close(storeChannel) + }() + + return storeChannel +} diff --git a/store/sql_webhook_store_test.go b/store/sql_webhook_store_test.go index 6f4ef4354..1fb990f3e 100644 --- a/store/sql_webhook_store_test.go +++ b/store/sql_webhook_store_test.go @@ -8,7 +8,7 @@ import ( "testing" ) -func TestIncomingWebhookStoreSaveIncoming(t *testing.T) { +func TestWebhookStoreSaveIncoming(t *testing.T) { Setup() o1 := model.IncomingWebhook{} @@ -25,7 +25,7 @@ func TestIncomingWebhookStoreSaveIncoming(t *testing.T) { } } -func TestIncomingWebhookStoreGetIncoming(t *testing.T) { +func TestWebhookStoreGetIncoming(t *testing.T) { Setup() o1 := &model.IncomingWebhook{} @@ -48,7 +48,34 @@ func TestIncomingWebhookStoreGetIncoming(t *testing.T) { } } -func TestIncomingWebhookStoreDelete(t *testing.T) { +func TestWebhookStoreGetIncomingByUser(t *testing.T) { + Setup() + + o1 := &model.IncomingWebhook{} + o1.ChannelId = model.NewId() + o1.UserId = model.NewId() + o1.TeamId = model.NewId() + + o1 = (<-store.Webhook().SaveIncoming(o1)).Data.(*model.IncomingWebhook) + + if r1 := <-store.Webhook().GetIncomingByUser(o1.UserId); r1.Err != nil { + t.Fatal(r1.Err) + } else { + if r1.Data.([]*model.IncomingWebhook)[0].CreateAt != o1.CreateAt { + t.Fatal("invalid returned webhook") + } + } + + if result := <-store.Webhook().GetIncomingByUser("123"); result.Err != nil { + t.Fatal(result.Err) + } else { + if len(result.Data.([]*model.IncomingWebhook)) != 0 { + t.Fatal("no webhooks should have returned") + } + } +} + +func TestWebhookStoreDeleteIncoming(t *testing.T) { Setup() o1 := &model.IncomingWebhook{} @@ -75,3 +102,176 @@ func TestIncomingWebhookStoreDelete(t *testing.T) { t.Fatal("Missing id should have failed") } } + +func TestWebhookStoreSaveOutgoing(t *testing.T) { + Setup() + + o1 := model.OutgoingWebhook{} + o1.ChannelId = model.NewId() + o1.CreatorId = model.NewId() + o1.TeamId = model.NewId() + o1.CallbackURLs = []string{"http://nowhere.com/"} + + if err := (<-store.Webhook().SaveOutgoing(&o1)).Err; err != nil { + t.Fatal("couldn't save item", err) + } + + if err := (<-store.Webhook().SaveOutgoing(&o1)).Err; err == nil { + t.Fatal("shouldn't be able to update from save") + } +} + +func TestWebhookStoreGetOutgoing(t *testing.T) { + Setup() + + o1 := &model.OutgoingWebhook{} + o1.ChannelId = model.NewId() + o1.CreatorId = model.NewId() + o1.TeamId = model.NewId() + o1.CallbackURLs = []string{"http://nowhere.com/"} + + o1 = (<-store.Webhook().SaveOutgoing(o1)).Data.(*model.OutgoingWebhook) + + if r1 := <-store.Webhook().GetOutgoing(o1.Id); r1.Err != nil { + t.Fatal(r1.Err) + } else { + if r1.Data.(*model.OutgoingWebhook).CreateAt != o1.CreateAt { + t.Fatal("invalid returned webhook") + } + } + + if err := (<-store.Webhook().GetOutgoing("123")).Err; err == nil { + t.Fatal("Missing id should have failed") + } +} + +func TestWebhookStoreGetOutgoingByChannel(t *testing.T) { + Setup() + + o1 := &model.OutgoingWebhook{} + o1.ChannelId = model.NewId() + o1.CreatorId = model.NewId() + o1.TeamId = model.NewId() + o1.CallbackURLs = []string{"http://nowhere.com/"} + + o1 = (<-store.Webhook().SaveOutgoing(o1)).Data.(*model.OutgoingWebhook) + + if r1 := <-store.Webhook().GetOutgoingByChannel(o1.ChannelId); r1.Err != nil { + t.Fatal(r1.Err) + } else { + if r1.Data.([]*model.OutgoingWebhook)[0].CreateAt != o1.CreateAt { + t.Fatal("invalid returned webhook") + } + } + + if result := <-store.Webhook().GetOutgoingByChannel("123"); result.Err != nil { + t.Fatal(result.Err) + } else { + if len(result.Data.([]*model.OutgoingWebhook)) != 0 { + t.Fatal("no webhooks should have returned") + } + } +} + +func TestWebhookStoreGetOutgoingByCreator(t *testing.T) { + Setup() + + o1 := &model.OutgoingWebhook{} + o1.ChannelId = model.NewId() + o1.CreatorId = model.NewId() + o1.TeamId = model.NewId() + o1.CallbackURLs = []string{"http://nowhere.com/"} + + o1 = (<-store.Webhook().SaveOutgoing(o1)).Data.(*model.OutgoingWebhook) + + if r1 := <-store.Webhook().GetOutgoingByCreator(o1.CreatorId); r1.Err != nil { + t.Fatal(r1.Err) + } else { + if r1.Data.([]*model.OutgoingWebhook)[0].CreateAt != o1.CreateAt { + t.Fatal("invalid returned webhook") + } + } + + if result := <-store.Webhook().GetOutgoingByCreator("123"); result.Err != nil { + t.Fatal(result.Err) + } else { + if len(result.Data.([]*model.OutgoingWebhook)) != 0 { + t.Fatal("no webhooks should have returned") + } + } +} + +func TestWebhookStoreGetOutgoingByTeam(t *testing.T) { + Setup() + + o1 := &model.OutgoingWebhook{} + o1.ChannelId = model.NewId() + o1.CreatorId = model.NewId() + o1.TeamId = model.NewId() + o1.CallbackURLs = []string{"http://nowhere.com/"} + + o1 = (<-store.Webhook().SaveOutgoing(o1)).Data.(*model.OutgoingWebhook) + + if r1 := <-store.Webhook().GetOutgoingByTeam(o1.TeamId); r1.Err != nil { + t.Fatal(r1.Err) + } else { + if r1.Data.([]*model.OutgoingWebhook)[0].CreateAt != o1.CreateAt { + t.Fatal("invalid returned webhook") + } + } + + if result := <-store.Webhook().GetOutgoingByTeam("123"); result.Err != nil { + t.Fatal(result.Err) + } else { + if len(result.Data.([]*model.OutgoingWebhook)) != 0 { + t.Fatal("no webhooks should have returned") + } + } +} + +func TestWebhookStoreDeleteOutgoing(t *testing.T) { + Setup() + + o1 := &model.OutgoingWebhook{} + o1.ChannelId = model.NewId() + o1.CreatorId = model.NewId() + o1.TeamId = model.NewId() + o1.CallbackURLs = []string{"http://nowhere.com/"} + + o1 = (<-store.Webhook().SaveOutgoing(o1)).Data.(*model.OutgoingWebhook) + + if r1 := <-store.Webhook().GetOutgoing(o1.Id); r1.Err != nil { + t.Fatal(r1.Err) + } else { + if r1.Data.(*model.OutgoingWebhook).CreateAt != o1.CreateAt { + t.Fatal("invalid returned webhook") + } + } + + if r2 := <-store.Webhook().DeleteOutgoing(o1.Id, model.GetMillis()); r2.Err != nil { + t.Fatal(r2.Err) + } + + if r3 := (<-store.Webhook().GetOutgoing(o1.Id)); r3.Err == nil { + t.Log(r3.Data) + t.Fatal("Missing id should have failed") + } +} + +func TestWebhookStoreUpdateOutgoing(t *testing.T) { + Setup() + + o1 := &model.OutgoingWebhook{} + o1.ChannelId = model.NewId() + o1.CreatorId = model.NewId() + o1.TeamId = model.NewId() + o1.CallbackURLs = []string{"http://nowhere.com/"} + + o1 = (<-store.Webhook().SaveOutgoing(o1)).Data.(*model.OutgoingWebhook) + + o1.Token = model.NewId() + + if r2 := <-store.Webhook().UpdateOutgoing(o1); r2.Err != nil { + t.Fatal(r2.Err) + } +} diff --git a/store/store.go b/store/store.go index de335cc2b..27731cee1 100644 --- a/store/store.go +++ b/store/store.go @@ -84,7 +84,7 @@ type PostStore interface { GetPosts(channelId string, offset int, limit int) StoreChannel GetPostsSince(channelId string, time int64) StoreChannel GetEtag(channelId string) StoreChannel - Search(teamId string, userId string, terms string, isHashtagSearch bool) StoreChannel + Search(teamId string, userId string, params *model.SearchParams) StoreChannel GetForExport(channelId string) StoreChannel } @@ -150,6 +150,13 @@ type WebhookStore interface { GetIncoming(id string) StoreChannel GetIncomingByUser(userId string) StoreChannel DeleteIncoming(webhookId string, time int64) StoreChannel + SaveOutgoing(webhook *model.OutgoingWebhook) StoreChannel + GetOutgoing(id string) StoreChannel + GetOutgoingByCreator(userId string) StoreChannel + GetOutgoingByChannel(channelId string) StoreChannel + GetOutgoingByTeam(teamId string) StoreChannel + DeleteOutgoing(webhookId string, time int64) StoreChannel + UpdateOutgoing(hook *model.OutgoingWebhook) StoreChannel } type PreferenceStore interface { |