From 0da0cf1a21d7dea61f4459ee71bf01b6ca362aee Mon Sep 17 00:00:00 2001 From: George Goldberg Date: Mon, 9 Oct 2017 18:14:27 +0100 Subject: [PATCH 1/8] PLT-7826: Don't fetch posts from store if ES returns none. (#7596) --- app/post.go | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/app/post.go b/app/post.go index 497cab5a6f..4a465450b8 100644 --- a/app/post.go +++ b/app/post.go @@ -602,12 +602,14 @@ func (a *App) SearchPostsInTeam(terms string, userId string, teamId string, isOr // Get the posts postList := model.NewPostList() - if presult := <-a.Srv.Store.Post().GetPostsByIds(postIds); presult.Err != nil { - return nil, presult.Err - } else { - for _, p := range presult.Data.([]*model.Post) { - postList.AddPost(p) - postList.AddOrder(p.Id) + if len(postIds) > 0 { + if presult := <-a.Srv.Store.Post().GetPostsByIds(postIds); presult.Err != nil { + return nil, presult.Err + } else { + for _, p := range presult.Data.([]*model.Post) { + postList.AddPost(p) + postList.AddOrder(p.Id) + } } } From 9adaf53e110e0e806b21903111aacb93129668cb Mon Sep 17 00:00:00 2001 From: Joram Wilander Date: Mon, 9 Oct 2017 13:30:48 -0400 Subject: [PATCH 2/8] PLT-7818 Updates to post type (#7579) * Updates to post type * Update tests --- api/post_test.go | 10 +++++++--- api4/post_test.go | 14 +++++++++++--- app/command.go | 5 +++++ app/command_test.go | 20 ++++++++++++++++++++ app/post.go | 5 +++++ app/webhook.go | 5 +++++ app/webhook_test.go | 5 +++++ 7 files changed, 58 insertions(+), 6 deletions(-) diff --git a/api/post_test.go b/api/post_test.go index f57c2e05cd..c01a5fa936 100644 --- a/api/post_test.go +++ b/api/post_test.go @@ -61,6 +61,11 @@ func TestCreatePost(t *testing.T) { t.Fatal("Newly craeted post shouldn't have EditAt set") } + _, err = Client.CreatePost(&model.Post{ChannelId: channel1.Id, Message: "#hashtag a" + model.NewId() + "a", Type: model.POST_SYSTEM_GENERIC}) + if err == nil { + t.Fatal("should have failed - bad post type") + } + post2 := &model.Post{ChannelId: channel1.Id, Message: "zz" + model.NewId() + "a", RootId: rpost1.Data.(*model.Post).Id} rpost2, err := Client.CreatePost(post2) if err != nil { @@ -454,13 +459,12 @@ func TestUpdatePost(t *testing.T) { } } - post3 := &model.Post{ChannelId: channel1.Id, Message: "zz" + model.NewId() + "a", Type: model.POST_JOIN_LEAVE} - rpost3, err := Client.CreatePost(post3) + rpost3, err := th.App.CreatePost(&model.Post{ChannelId: channel1.Id, Message: "zz" + model.NewId() + "a", Type: model.POST_JOIN_LEAVE, UserId: th.BasicUser.Id}, channel1, false) if err != nil { t.Fatal(err) } - up3 := &model.Post{Id: rpost3.Data.(*model.Post).Id, ChannelId: channel1.Id, Message: "zz" + model.NewId() + " update post 3"} + up3 := &model.Post{Id: rpost3.Id, ChannelId: channel1.Id, Message: "zz" + model.NewId() + " update post 3"} if _, err := Client.UpdatePost(up3); err == nil { t.Fatal("shouldn't have been able to update system message") } diff --git a/api4/post_test.go b/api4/post_test.go index fd6f8031d0..27e6d6458a 100644 --- a/api4/post_test.go +++ b/api4/post_test.go @@ -66,6 +66,13 @@ func TestCreatePost(t *testing.T) { t.Fatal("create at should not match") } + post.RootId = "" + post.ParentId = "" + post.Type = model.POST_SYSTEM_GENERIC + _, resp = Client.CreatePost(post) + CheckBadRequestStatus(t, resp) + + post.Type = "" post.RootId = rpost2.Id post.ParentId = rpost2.Id _, resp = Client.CreatePost(post) @@ -417,9 +424,10 @@ func TestUpdatePost(t *testing.T) { t.Fatal("failed to updates") } - post2 := &model.Post{ChannelId: channel.Id, Message: "zz" + model.NewId() + "a", Type: model.POST_JOIN_LEAVE} - rpost2, resp := Client.CreatePost(post2) - CheckNoError(t, resp) + rpost2, err := th.App.CreatePost(&model.Post{ChannelId: channel.Id, Message: "zz" + model.NewId() + "a", Type: model.POST_JOIN_LEAVE, UserId: th.BasicUser.Id}, channel, false) + if err != nil { + t.Fatal(err) + } up2 := &model.Post{Id: rpost2.Id, ChannelId: channel.Id, Message: "zz" + model.NewId() + " update post 2"} _, resp = Client.UpdatePost(rpost2.Id, up2) diff --git a/app/command.go b/app/command.go index 6e439537ef..811294b6d3 100644 --- a/app/command.go +++ b/app/command.go @@ -41,6 +41,11 @@ func (a *App) CreateCommandPost(post *model.Post, teamId string, response *model post.Message = parseSlackLinksToMarkdown(response.Text) post.CreateAt = model.GetMillis() + if strings.HasPrefix(post.Type, model.POST_SYSTEM_MESSAGE_PREFIX) { + err := model.NewAppError("CreateCommandPost", "api.context.invalid_param.app_error", map[string]interface{}{"Name": "post.type"}, "", http.StatusBadRequest) + return nil, err + } + if response.Attachments != nil { parseSlackAttachment(post, response.Attachments) } diff --git a/app/command_test.go b/app/command_test.go index b37e78ea96..de48224369 100644 --- a/app/command_test.go +++ b/app/command_test.go @@ -45,3 +45,23 @@ func TestMoveCommand(t *testing.T) { assert.Nil(t, err) assert.EqualValues(t, targetTeam.Id, retrievedCommand.TeamId) } + +func TestCreateCommandPost(t *testing.T) { + th := Setup().InitBasic() + defer th.TearDown() + + post := &model.Post{ + ChannelId: th.BasicChannel.Id, + UserId: th.BasicUser.Id, + Type: model.POST_SYSTEM_GENERIC, + } + + resp := &model.CommandResponse{ + Text: "some message", + } + + _, err := th.App.CreateCommandPost(post, th.BasicTeam.Id, resp) + if err == nil && err.Id != "api.context.invalid_param.app_error" { + t.Fatal("should have failed - bad post type") + } +} diff --git a/app/post.go b/app/post.go index 4a465450b8..fa929b844f 100644 --- a/app/post.go +++ b/app/post.go @@ -29,6 +29,11 @@ func (a *App) CreatePostAsUser(post *model.Post) (*model.Post, *model.AppError) channel = result.Data.(*model.Channel) } + if strings.HasPrefix(post.Type, model.POST_SYSTEM_MESSAGE_PREFIX) { + err := model.NewAppError("CreatePostAsUser", "api.context.invalid_param.app_error", map[string]interface{}{"Name": "post.type"}, "", http.StatusBadRequest) + return nil, err + } + if channel.DeleteAt != 0 { err := model.NewAppError("createPost", "api.post.create_post.can_not_post_to_deleted.error", nil, "", http.StatusBadRequest) return nil, err diff --git a/app/webhook.go b/app/webhook.go index 9d9b24b10e..1530ba94a4 100644 --- a/app/webhook.go +++ b/app/webhook.go @@ -131,6 +131,11 @@ func (a *App) CreateWebhookPost(userId string, channel *model.Channel, text, ove post := &model.Post{UserId: userId, ChannelId: channel.Id, Message: text, Type: postType} post.AddProp("from_webhook", "true") + if strings.HasPrefix(post.Type, model.POST_SYSTEM_MESSAGE_PREFIX) { + err := model.NewAppError("CreateWebhookPost", "api.context.invalid_param.app_error", map[string]interface{}{"Name": "post.type"}, "", http.StatusBadRequest) + return nil, err + } + if metrics := a.Metrics; metrics != nil { metrics.IncrementWebhookPost() } diff --git a/app/webhook_test.go b/app/webhook_test.go index 5699addbfa..b9ba35f433 100644 --- a/app/webhook_test.go +++ b/app/webhook_test.go @@ -44,4 +44,9 @@ func TestCreateWebhookPost(t *testing.T) { t.Fatal(k) } } + + _, err = th.App.CreateWebhookPost(hook.UserId, th.BasicChannel, "foo", "user", "http://iconurl", nil, model.POST_SYSTEM_GENERIC) + if err == nil { + t.Fatal("should have failed - bad post type") + } } From e522a1c2e49f5d21e45dd66f83d06e10fc3cdb67 Mon Sep 17 00:00:00 2001 From: Harrison Healey Date: Mon, 9 Oct 2017 13:30:59 -0400 Subject: [PATCH 3/8] PLT-7811 Standardized team sanitization flow (#7586) * post-4.3 commit (#7581) * reduce store boiler plate (#7585) * fix GetPostsByIds error (#7591) * PLT-7811 Standardized team sanitization flow * Fixed TestGetAllTeamListings * Stopped sanitizing teams for team admins * Removed debug logging * Added TearDown to sanitization tests that needed it --- api/apitestlib.go | 13 +- api/team.go | 24 +- api/team_test.go | 357 +++++++++- api4/team.go | 16 + api4/team_test.go | 469 ++++++++++++- app/team.go | 26 +- app/team_test.go | 214 ++++++ model/client.go | 2 +- store/sqlstore/audit_store.go | 57 +- store/sqlstore/channel_store.go | 549 +++------------- store/sqlstore/cluster_discovery_store.go | 81 +-- .../sqlstore/cluster_discovery_store_test.go | 2 +- store/sqlstore/command_store.go | 121 +--- store/sqlstore/command_webhook_store.go | 43 +- store/sqlstore/compliance_store.go | 74 +-- store/sqlstore/compliance_store_test.go | 2 +- store/sqlstore/emoji_store.go | 69 +- store/sqlstore/emoji_store_test.go | 2 +- store/sqlstore/file_info_store.go | 108 +-- store/sqlstore/file_info_store_test.go | 8 +- store/sqlstore/job_store.go | 155 +---- store/sqlstore/license_store.go | 31 +- store/sqlstore/license_store_test.go | 2 +- store/sqlstore/oauth_store.go | 266 ++------ store/sqlstore/oauth_store_test.go | 2 +- store/sqlstore/post_store.go | 382 ++--------- store/sqlstore/post_store_test.go | 2 +- store/sqlstore/preference_store.go | 131 +--- store/sqlstore/preference_store_test.go | 2 +- store/sqlstore/reaction_store_test.go | 2 +- store/sqlstore/session_store.go | 159 +---- store/sqlstore/session_store_test.go | 2 +- store/sqlstore/status_store.go | 117 +--- store/sqlstore/status_store_test.go | 2 +- store/sqlstore/system_store.go | 70 +- store/sqlstore/system_store_test.go | 2 +- store/sqlstore/team_store.go | 393 ++--------- store/sqlstore/team_store_test.go | 2 +- store/sqlstore/tokens_store.go | 44 +- store/sqlstore/upgrade.go | 9 + store/sqlstore/user_access_token_store.go | 90 +-- .../sqlstore/user_access_token_store_test.go | 2 +- store/sqlstore/user_store.go | 616 +++--------------- store/sqlstore/webhook_store.go | 270 ++------ 44 files changed, 1686 insertions(+), 3304 deletions(-) diff --git a/api/apitestlib.go b/api/apitestlib.go index c0fd79ae93..3c64d24304 100644 --- a/api/apitestlib.go +++ b/api/apitestlib.go @@ -4,6 +4,7 @@ package api import ( + "strings" "time" "github.com/mattermost/mattermost-server/api4" @@ -130,8 +131,8 @@ func (me *TestHelper) CreateTeam(client *model.Client) *model.Team { id := model.NewId() team := &model.Team{ DisplayName: "dn_" + id, - Name: "name" + id, - Email: "success+" + id + "@simulator.amazonses.com", + Name: GenerateTestTeamName(), + Email: GenerateTestEmail(), Type: model.TEAM_OPEN, } @@ -308,6 +309,14 @@ func (me *TestHelper) LoginSystemAdmin() { utils.EnableDebugLogForTest() } +func GenerateTestEmail() string { + return strings.ToLower("success+" + model.NewId() + "@simulator.amazonses.com") +} + +func GenerateTestTeamName() string { + return "faketeam" + model.NewRandomString(6) +} + func (me *TestHelper) TearDown() { me.App.Shutdown() } diff --git a/api/team.go b/api/team.go index 8a8d3c9356..49b20686d8 100644 --- a/api/team.go +++ b/api/team.go @@ -67,6 +67,8 @@ func createTeam(c *Context, w http.ResponseWriter, r *http.Request) { return } + // Don't sanitize the team here since the user will be a team admin and their session won't reflect that yet + w.Write([]byte(rteam.ToJson())) } @@ -82,11 +84,10 @@ func GetAllTeamListings(c *Context, w http.ResponseWriter, r *http.Request) { m := make(map[string]*model.Team) for _, v := range teams { m[v.Id] = v - if !app.SessionHasPermissionTo(c.Session, model.PERMISSION_MANAGE_SYSTEM) { - m[v.Id].Sanitize() - } } + sanitizeTeamMap(c.Session, m) + w.Write([]byte(model.TeamMapToJson(m))) } @@ -112,6 +113,8 @@ func getAll(c *Context, w http.ResponseWriter, r *http.Request) { m[v.Id] = v } + sanitizeTeamMap(c.Session, m) + w.Write([]byte(model.TeamMapToJson(m))) } @@ -207,7 +210,7 @@ func addUserToTeamFromInvite(c *Context, w http.ResponseWriter, r *http.Request) return } - team.Sanitize() + app.SanitizeTeam(c.Session, team) w.Write([]byte(team.ToJson())) } @@ -241,6 +244,8 @@ func getTeamByName(c *Context, w http.ResponseWriter, r *http.Request) { } } + app.SanitizeTeam(c.Session, team) + w.Write([]byte(team.ToJson())) return } @@ -294,6 +299,8 @@ func updateTeam(c *Context, w http.ResponseWriter, r *http.Request) { return } + app.SanitizeTeam(c.Session, updatedTeam) + w.Write([]byte(updatedTeam.ToJson())) } @@ -342,6 +349,9 @@ func getMyTeam(c *Context, w http.ResponseWriter, r *http.Request) { return } else { w.Header().Set(model.HEADER_ETAG_SERVER, team.Etag()) + + app.SanitizeTeam(c.Session, team) + w.Write([]byte(team.ToJson())) return } @@ -529,3 +539,9 @@ func getTeamMembersByIds(c *Context, w http.ResponseWriter, r *http.Request) { return } } + +func sanitizeTeamMap(session model.Session, teams map[string]*model.Team) { + for _, team := range teams { + app.SanitizeTeam(session, team) + } +} diff --git a/api/team_test.go b/api/team_test.go index ea29b9d6fc..1e4b364336 100644 --- a/api/team_test.go +++ b/api/team_test.go @@ -56,6 +56,49 @@ func TestCreateTeam(t *testing.T) { } } +func TestCreateTeamSanitization(t *testing.T) { + th := Setup().InitBasic().InitSystemAdmin() + defer th.TearDown() + + // Non-admin users can create a team, but they become a team admin by doing so + + t.Run("team admin", func(t *testing.T) { + team := &model.Team{ + DisplayName: t.Name() + "_1", + Name: GenerateTestTeamName(), + Email: GenerateTestEmail(), + Type: model.TEAM_OPEN, + AllowedDomains: "simulator.amazonses.com", + } + + if res, err := th.BasicClient.CreateTeam(team); err != nil { + t.Fatal(err) + } else if rteam := res.Data.(*model.Team); rteam.Email == "" { + t.Fatal("should not have sanitized email") + } else if rteam.AllowedDomains == "" { + t.Fatal("should not have sanitized allowed domains") + } + }) + + t.Run("system admin", func(t *testing.T) { + team := &model.Team{ + DisplayName: t.Name() + "_2", + Name: GenerateTestTeamName(), + Email: GenerateTestEmail(), + Type: model.TEAM_OPEN, + AllowedDomains: "simulator.amazonses.com", + } + + if res, err := th.SystemAdminClient.CreateTeam(team); err != nil { + t.Fatal(err) + } else if rteam := res.Data.(*model.Team); rteam.Email == "" { + t.Fatal("should not have sanitized email") + } else if rteam.AllowedDomains == "" { + t.Fatal("should not have sanitized allowed domains") + } + }) +} + func TestAddUserToTeam(t *testing.T) { th := Setup().InitSystemAdmin().InitBasic() defer th.TearDown() @@ -253,6 +296,77 @@ func TestGetAllTeams(t *testing.T) { } } +func TestGetAllTeamsSanitization(t *testing.T) { + th := Setup().InitBasic().InitSystemAdmin() + defer th.TearDown() + + var team *model.Team + if res, err := th.BasicClient.CreateTeam(&model.Team{ + DisplayName: t.Name() + "_1", + Name: GenerateTestTeamName(), + Email: GenerateTestEmail(), + Type: model.TEAM_OPEN, + AllowedDomains: "simulator.amazonses.com", + }); err != nil { + t.Fatal(err) + } else { + team = res.Data.(*model.Team) + } + + var team2 *model.Team + if res, err := th.SystemAdminClient.CreateTeam(&model.Team{ + DisplayName: t.Name() + "_2", + Name: GenerateTestTeamName(), + Email: GenerateTestEmail(), + Type: model.TEAM_OPEN, + AllowedDomains: "simulator.amazonses.com", + }); err != nil { + t.Fatal(err) + } else { + team2 = res.Data.(*model.Team) + } + + t.Run("team admin/team user", func(t *testing.T) { + if res, err := th.BasicClient.GetAllTeams(); err != nil { + t.Fatal(err) + } else { + for _, rteam := range res.Data.(map[string]*model.Team) { + if rteam.Id == team.Id { + if rteam.Email == "" { + t.Fatal("should not have sanitized email for team admin") + } else if rteam.AllowedDomains == "" { + t.Fatal("should not have sanitized allowed domains for team admin") + } + } else if rteam.Id == team2.Id { + if rteam.Email != "" { + t.Fatal("should've sanitized email for non-admin") + } else if rteam.AllowedDomains != "" { + t.Fatal("should've sanitized allowed domains for non-admin") + } + } + } + } + }) + + t.Run("system admin", func(t *testing.T) { + if res, err := th.SystemAdminClient.GetAllTeams(); err != nil { + t.Fatal(err) + } else { + for _, rteam := range res.Data.(map[string]*model.Team) { + if rteam.Id != team.Id && rteam.Id != team2.Id { + continue + } + + if rteam.Email == "" { + t.Fatal("should not have sanitized email") + } else if rteam.AllowedDomains == "" { + t.Fatal("should not have sanitized allowed domains") + } + } + } + }) +} + func TestGetAllTeamListings(t *testing.T) { th := Setup().InitBasic() defer th.TearDown() @@ -277,10 +391,7 @@ func TestGetAllTeamListings(t *testing.T) { } else { teams := r1.Data.(map[string]*model.Team) if teams[team.Id].Name != team.Name { - t.Fatal() - } - if teams[team.Id].Email != "" { - t.Fatal("Non admin users shoudn't get full listings") + t.Fatal("team name doesn't match") } } @@ -294,14 +405,84 @@ func TestGetAllTeamListings(t *testing.T) { } else { teams := r1.Data.(map[string]*model.Team) if teams[team.Id].Name != team.Name { - t.Fatal() - } - if teams[team.Id].Email != team.Email { - t.Fatal() + t.Fatal("team name doesn't match") } } } +func TestGetAllTeamListingsSanitization(t *testing.T) { + th := Setup().InitBasic().InitSystemAdmin() + defer th.TearDown() + + var team *model.Team + if res, err := th.BasicClient.CreateTeam(&model.Team{ + DisplayName: t.Name() + "_1", + Name: GenerateTestTeamName(), + Email: GenerateTestEmail(), + Type: model.TEAM_OPEN, + AllowedDomains: "simulator.amazonses.com", + AllowOpenInvite: true, + }); err != nil { + t.Fatal(err) + } else { + team = res.Data.(*model.Team) + } + + var team2 *model.Team + if res, err := th.SystemAdminClient.CreateTeam(&model.Team{ + DisplayName: t.Name() + "_2", + Name: GenerateTestTeamName(), + Email: GenerateTestEmail(), + Type: model.TEAM_OPEN, + AllowedDomains: "simulator.amazonses.com", + AllowOpenInvite: true, + }); err != nil { + t.Fatal(err) + } else { + team2 = res.Data.(*model.Team) + } + + t.Run("team admin/non-admin", func(t *testing.T) { + if res, err := th.BasicClient.GetAllTeamListings(); err != nil { + t.Fatal(err) + } else { + for _, rteam := range res.Data.(map[string]*model.Team) { + if rteam.Id == team.Id { + if rteam.Email == "" { + t.Fatal("should not have sanitized email for team admin") + } else if rteam.AllowedDomains == "" { + t.Fatal("should not have sanitized allowed domains for team admin") + } + } else if rteam.Id == team2.Id { + if rteam.Email != "" { + t.Fatal("should've sanitized email for non-admin") + } else if rteam.AllowedDomains != "" { + t.Fatal("should've sanitized allowed domains for non-admin") + } + } + } + } + }) + + t.Run("system admin", func(t *testing.T) { + if res, err := th.SystemAdminClient.GetAllTeamListings(); err != nil { + t.Fatal(err) + } else { + for _, rteam := range res.Data.(map[string]*model.Team) { + if rteam.Id != team.Id && rteam.Id != team2.Id { + continue + } + + if rteam.Email == "" { + t.Fatal("should not have sanitized email") + } else if rteam.AllowedDomains == "" { + t.Fatal("should not have sanitized allowed domains") + } + } + } + }) +} + func TestTeamPermDelete(t *testing.T) { th := Setup().InitBasic() defer th.TearDown() @@ -476,6 +657,52 @@ func TestUpdateTeamDisplayName(t *testing.T) { } } +func TestUpdateTeamSanitization(t *testing.T) { + th := Setup().InitBasic().InitSystemAdmin() + defer th.TearDown() + + var team *model.Team + if res, err := th.BasicClient.CreateTeam(&model.Team{ + DisplayName: t.Name() + "_1", + Name: GenerateTestTeamName(), + Email: GenerateTestEmail(), + Type: model.TEAM_OPEN, + AllowedDomains: "simulator.amazonses.com", + }); err != nil { + t.Fatal(err) + } else { + team = res.Data.(*model.Team) + } + + // Non-admin users cannot update the team + + t.Run("team admin", func(t *testing.T) { + // API v3 always assumes you're updating the current team + th.BasicClient.SetTeamId(team.Id) + + if res, err := th.BasicClient.UpdateTeam(team); err != nil { + t.Fatal(err) + } else if rteam := res.Data.(*model.Team); rteam.Email == "" { + t.Fatal("should not have sanitized email for admin") + } else if rteam.AllowedDomains == "" { + t.Fatal("should not have sanitized allowed domains") + } + }) + + t.Run("system admin", func(t *testing.T) { + // API v3 always assumes you're updating the current team + th.SystemAdminClient.SetTeamId(team.Id) + + if res, err := th.SystemAdminClient.UpdateTeam(team); err != nil { + t.Fatal(err) + } else if rteam := res.Data.(*model.Team); rteam.Email == "" { + t.Fatal("should not have sanitized email for admin") + } else if rteam.AllowedDomains == "" { + t.Fatal("should not have sanitized allowed domains") + } + }) +} + func TestFuzzyTeamCreate(t *testing.T) { th := Setup().InitBasic() defer th.TearDown() @@ -537,6 +764,65 @@ func TestGetMyTeam(t *testing.T) { } } +func TestGetMyTeamSanitization(t *testing.T) { + th := Setup().InitBasic().InitSystemAdmin() + defer th.TearDown() + + var team *model.Team + if res, err := th.BasicClient.CreateTeam(&model.Team{ + DisplayName: t.Name() + "_1", + Name: GenerateTestTeamName(), + Email: GenerateTestEmail(), + Type: model.TEAM_OPEN, + AllowedDomains: "simulator.amazonses.com", + }); err != nil { + t.Fatal(err) + } else { + team = res.Data.(*model.Team) + } + + t.Run("team user", func(t *testing.T) { + th.LinkUserToTeam(th.BasicUser2, team) + + client := th.CreateClient() + client.Must(client.Login(th.BasicUser2.Email, th.BasicUser2.Password)) + + client.SetTeamId(team.Id) + + if res, err := client.GetMyTeam(""); err != nil { + t.Fatal(err) + } else if rteam := res.Data.(*model.Team); rteam.Email != "" { + t.Fatal("should've sanitized email") + } else if rteam.AllowedDomains != "" { + t.Fatal("should've sanitized allowed domains") + } + }) + + t.Run("team admin", func(t *testing.T) { + th.BasicClient.SetTeamId(team.Id) + + if res, err := th.BasicClient.GetMyTeam(""); err != nil { + t.Fatal(err) + } else if rteam := res.Data.(*model.Team); rteam.Email == "" { + t.Fatal("should not have sanitized email") + } else if rteam.AllowedDomains == "" { + t.Fatal("should not have sanitized allowed domains") + } + }) + + t.Run("system admin", func(t *testing.T) { + th.SystemAdminClient.SetTeamId(team.Id) + + if res, err := th.SystemAdminClient.GetMyTeam(""); err != nil { + t.Fatal(err) + } else if rteam := res.Data.(*model.Team); rteam.Email == "" { + t.Fatal("should not have sanitized email") + } else if rteam.AllowedDomains == "" { + t.Fatal("should not have sanitized allowed domains") + } + }) +} + func TestGetTeamMembers(t *testing.T) { th := Setup().InitBasic() defer th.TearDown() @@ -898,6 +1184,61 @@ func TestGetTeamByName(t *testing.T) { } } +func TestGetTeamByNameSanitization(t *testing.T) { + th := Setup().InitBasic().InitSystemAdmin() + defer th.TearDown() + + var team *model.Team + if res, err := th.BasicClient.CreateTeam(&model.Team{ + DisplayName: t.Name() + "_1", + Name: GenerateTestTeamName(), + Email: GenerateTestEmail(), + Type: model.TEAM_OPEN, + AllowedDomains: "simulator.amazonses.com", + }); err != nil { + t.Fatal(err) + } else { + team = res.Data.(*model.Team) + } + + t.Run("team user", func(t *testing.T) { + th.LinkUserToTeam(th.BasicUser2, team) + + client := th.CreateClient() + client.Must(client.Login(th.BasicUser2.Email, th.BasicUser2.Password)) + + if res, err := client.GetTeamByName(team.Name); err != nil { + t.Fatal(err) + } else if rteam := res.Data.(*model.Team); rteam.Email != "" { + t.Fatal("should've sanitized email") + } else if rteam.AllowedDomains != "" { + t.Fatal("should've sanitized allowed domains") + } + }) + + t.Run("team admin", func(t *testing.T) { + if res, err := th.BasicClient.GetTeamByName(team.Name); err != nil { + t.Fatal(err) + } else if rteam := res.Data.(*model.Team); rteam.Email == "" { + t.Fatal("should not have sanitized email") + } else if rteam.AllowedDomains == "" { + t.Fatal("should not have sanitized allowed domains") + } + }) + + t.Run("system admin", func(t *testing.T) { + th.SystemAdminClient.SetTeamId(team.Id) + + if res, err := th.SystemAdminClient.GetTeamByName(team.Name); err != nil { + t.Fatal(err) + } else if rteam := res.Data.(*model.Team); rteam.Email == "" { + t.Fatal("should not have sanitized email") + } else if rteam.AllowedDomains == "" { + t.Fatal("should not have sanitized allowed domains") + } + }) +} + func TestFindTeamByName(t *testing.T) { th := Setup().InitBasic() defer th.TearDown() diff --git a/api4/team.go b/api4/team.go index a94da2bef1..2c60d40a1f 100644 --- a/api4/team.go +++ b/api4/team.go @@ -71,6 +71,8 @@ func createTeam(c *Context, w http.ResponseWriter, r *http.Request) { return } + // Don't sanitize the team here since the user will be a team admin and their session won't reflect that yet + w.WriteHeader(http.StatusCreated) w.Write([]byte(rteam.ToJson())) } @@ -90,6 +92,8 @@ func getTeam(c *Context, w http.ResponseWriter, r *http.Request) { return } + app.SanitizeTeam(c.Session, team) + w.Write([]byte(team.ToJson())) return } @@ -110,6 +114,8 @@ func getTeamByName(c *Context, w http.ResponseWriter, r *http.Request) { return } + app.SanitizeTeam(c.Session, team) + w.Write([]byte(team.ToJson())) return } @@ -142,6 +148,8 @@ func updateTeam(c *Context, w http.ResponseWriter, r *http.Request) { return } + app.SanitizeTeam(c.Session, updatedTeam) + w.Write([]byte(updatedTeam.ToJson())) } @@ -170,6 +178,8 @@ func patchTeam(c *Context, w http.ResponseWriter, r *http.Request) { return } + app.SanitizeTeam(c.Session, patchedTeam) + c.LogAudit("") w.Write([]byte(patchedTeam.ToJson())) } @@ -215,6 +225,8 @@ func getTeamsForUser(c *Context, w http.ResponseWriter, r *http.Request) { c.Err = err return } else { + app.SanitizeTeams(c.Session, teams) + w.Write([]byte(model.TeamListToJson(teams))) } } @@ -541,6 +553,8 @@ func getAllTeams(c *Context, w http.ResponseWriter, r *http.Request) { return } + app.SanitizeTeams(c.Session, teams) + w.Write([]byte(model.TeamListToJson(teams))) } @@ -570,6 +584,8 @@ func searchTeams(c *Context, w http.ResponseWriter, r *http.Request) { return } + app.SanitizeTeams(c.Session, teams) + w.Write([]byte(model.TeamListToJson(teams))) } diff --git a/api4/team_test.go b/api4/team_test.go index bd42682bfd..45484e2a1c 100644 --- a/api4/team_test.go +++ b/api4/team_test.go @@ -7,7 +7,6 @@ import ( "encoding/binary" "fmt" "net/http" - "reflect" "strconv" "strings" "testing" @@ -82,6 +81,49 @@ func TestCreateTeam(t *testing.T) { CheckForbiddenStatus(t, resp) } +func TestCreateTeamSanitization(t *testing.T) { + th := Setup().InitBasic().InitSystemAdmin() + defer th.TearDown() + + // Non-admin users can create a team, but they become a team admin by doing so + + t.Run("team admin", func(t *testing.T) { + team := &model.Team{ + DisplayName: t.Name() + "_1", + Name: GenerateTestTeamName(), + Email: GenerateTestEmail(), + Type: model.TEAM_OPEN, + AllowedDomains: "simulator.amazonses.com", + } + + rteam, resp := th.Client.CreateTeam(team) + CheckNoError(t, resp) + if rteam.Email == "" { + t.Fatal("should not have sanitized email") + } else if rteam.AllowedDomains == "" { + t.Fatal("should not have sanitized allowed domains") + } + }) + + t.Run("system admin", func(t *testing.T) { + team := &model.Team{ + DisplayName: t.Name() + "_2", + Name: GenerateTestTeamName(), + Email: GenerateTestEmail(), + Type: model.TEAM_OPEN, + AllowedDomains: "simulator.amazonses.com", + } + + rteam, resp := th.SystemAdminClient.CreateTeam(team) + CheckNoError(t, resp) + if rteam.Email == "" { + t.Fatal("should not have sanitized email") + } else if rteam.AllowedDomains == "" { + t.Fatal("should not have sanitized allowed domains") + } + }) +} + func TestGetTeam(t *testing.T) { th := Setup().InitBasic().InitSystemAdmin() defer th.TearDown() @@ -129,6 +171,55 @@ func TestGetTeam(t *testing.T) { CheckNoError(t, resp) } +func TestGetTeamSanitization(t *testing.T) { + th := Setup().InitBasic().InitSystemAdmin() + defer th.TearDown() + + team, resp := th.Client.CreateTeam(&model.Team{ + DisplayName: t.Name() + "_1", + Name: GenerateTestTeamName(), + Email: GenerateTestEmail(), + Type: model.TEAM_OPEN, + AllowedDomains: "simulator.amazonses.com", + }) + CheckNoError(t, resp) + + t.Run("team user", func(t *testing.T) { + th.LinkUserToTeam(th.BasicUser2, team) + + client := th.CreateClient() + th.LoginBasic2WithClient(client) + + rteam, resp := client.GetTeam(team.Id, "") + CheckNoError(t, resp) + if rteam.Email != "" { + t.Fatal("should've sanitized email") + } else if rteam.AllowedDomains != "" { + t.Fatal("should've sanitized allowed domains") + } + }) + + t.Run("team admin", func(t *testing.T) { + rteam, resp := th.Client.GetTeam(team.Id, "") + CheckNoError(t, resp) + if rteam.Email == "" { + t.Fatal("should not have sanitized email") + } else if rteam.AllowedDomains == "" { + t.Fatal("should not have sanitized allowed domains") + } + }) + + t.Run("system admin", func(t *testing.T) { + rteam, resp := th.SystemAdminClient.GetTeam(team.Id, "") + CheckNoError(t, resp) + if rteam.Email == "" { + t.Fatal("should not have sanitized email") + } else if rteam.AllowedDomains == "" { + t.Fatal("should not have sanitized allowed domains") + } + }) +} + func TestGetTeamUnread(t *testing.T) { th := Setup().InitBasic().InitSystemAdmin() defer th.TearDown() @@ -203,6 +294,14 @@ func TestUpdateTeam(t *testing.T) { t.Fatal("Update failed") } + team.AllowedDomains = "domain" + uteam, resp = Client.UpdateTeam(team) + CheckNoError(t, resp) + + if uteam.AllowedDomains != "domain" { + t.Fatal("Update failed") + } + team.Name = "Updated name" uteam, resp = Client.UpdateTeam(team) CheckNoError(t, resp) @@ -227,14 +326,6 @@ func TestUpdateTeam(t *testing.T) { t.Fatal("Should not update type") } - team.AllowedDomains = "domain" - uteam, resp = Client.UpdateTeam(team) - CheckNoError(t, resp) - - if uteam.AllowedDomains == "domain" { - t.Fatal("Should not update allowed_domains") - } - originalTeamId := team.Id team.Id = model.NewId() @@ -261,6 +352,42 @@ func TestUpdateTeam(t *testing.T) { CheckNoError(t, resp) } +func TestUpdateTeamSanitization(t *testing.T) { + th := Setup().InitBasic().InitSystemAdmin() + defer th.TearDown() + + team, resp := th.Client.CreateTeam(&model.Team{ + DisplayName: t.Name() + "_1", + Name: GenerateTestTeamName(), + Email: GenerateTestEmail(), + Type: model.TEAM_OPEN, + AllowedDomains: "simulator.amazonses.com", + }) + CheckNoError(t, resp) + + // Non-admin users cannot update the team + + t.Run("team admin", func(t *testing.T) { + rteam, resp := th.Client.UpdateTeam(team) + CheckNoError(t, resp) + if rteam.Email == "" { + t.Fatal("should not have sanitized email for admin") + } else if rteam.AllowedDomains == "" { + t.Fatal("should not have sanitized allowed domains") + } + }) + + t.Run("system admin", func(t *testing.T) { + rteam, resp := th.SystemAdminClient.UpdateTeam(team) + CheckNoError(t, resp) + if rteam.Email == "" { + t.Fatal("should not have sanitized email for admin") + } else if rteam.AllowedDomains == "" { + t.Fatal("should not have sanitized allowed domains") + } + }) +} + func TestPatchTeam(t *testing.T) { th := Setup().InitBasic().InitSystemAdmin() defer th.TearDown() @@ -284,7 +411,6 @@ func TestPatchTeam(t *testing.T) { rteam, resp := Client.PatchTeam(team.Id, patch) CheckNoError(t, resp) - CheckTeamSanitization(t, rteam) if rteam.DisplayName != "Other name" { t.Fatal("DisplayName did not update properly") @@ -330,6 +456,42 @@ func TestPatchTeam(t *testing.T) { CheckNoError(t, resp) } +func TestPatchTeamSanitization(t *testing.T) { + th := Setup().InitBasic().InitSystemAdmin() + defer th.TearDown() + + team, resp := th.Client.CreateTeam(&model.Team{ + DisplayName: t.Name() + "_1", + Name: GenerateTestTeamName(), + Email: GenerateTestEmail(), + Type: model.TEAM_OPEN, + AllowedDomains: "simulator.amazonses.com", + }) + CheckNoError(t, resp) + + // Non-admin users cannot update the team + + t.Run("team admin", func(t *testing.T) { + rteam, resp := th.Client.PatchTeam(team.Id, &model.TeamPatch{}) + CheckNoError(t, resp) + if rteam.Email == "" { + t.Fatal("should not have sanitized email for admin") + } else if rteam.AllowedDomains == "" { + t.Fatal("should not have sanitized allowed domains") + } + }) + + t.Run("system admin", func(t *testing.T) { + rteam, resp := th.SystemAdminClient.PatchTeam(team.Id, &model.TeamPatch{}) + CheckNoError(t, resp) + if rteam.Email == "" { + t.Fatal("should not have sanitized email for admin") + } else if rteam.AllowedDomains == "" { + t.Fatal("should not have sanitized allowed domains") + } + }) +} + func TestSoftDeleteTeam(t *testing.T) { th := Setup().InitBasic().InitSystemAdmin() defer th.TearDown() @@ -463,6 +625,77 @@ func TestGetAllTeams(t *testing.T) { CheckUnauthorizedStatus(t, resp) } +func TestGetAllTeamsSanitization(t *testing.T) { + th := Setup().InitBasic().InitSystemAdmin() + defer th.TearDown() + + team, resp := th.Client.CreateTeam(&model.Team{ + DisplayName: t.Name() + "_1", + Name: GenerateTestTeamName(), + Email: GenerateTestEmail(), + Type: model.TEAM_OPEN, + AllowedDomains: "simulator.amazonses.com", + AllowOpenInvite: true, + }) + CheckNoError(t, resp) + team2, resp := th.SystemAdminClient.CreateTeam(&model.Team{ + DisplayName: t.Name() + "_2", + Name: GenerateTestTeamName(), + Email: GenerateTestEmail(), + Type: model.TEAM_OPEN, + AllowedDomains: "simulator.amazonses.com", + AllowOpenInvite: true, + }) + CheckNoError(t, resp) + + // This may not work if the server has over 1000 open teams on it + + t.Run("team admin/non-admin", func(t *testing.T) { + teamFound := false + team2Found := false + + rteams, resp := th.Client.GetAllTeams("", 0, 1000) + CheckNoError(t, resp) + for _, rteam := range rteams { + if rteam.Id == team.Id { + teamFound = true + if rteam.Email == "" { + t.Fatal("should not have sanitized email for team admin") + } else if rteam.AllowedDomains == "" { + t.Fatal("should not have sanitized allowed domains for team admin") + } + } else if rteam.Id == team2.Id { + team2Found = true + if rteam.Email != "" { + t.Fatal("should've sanitized email for non-admin") + } else if rteam.AllowedDomains != "" { + t.Fatal("should've sanitized allowed domains for non-admin") + } + } + } + + if !teamFound || !team2Found { + t.Fatal("wasn't returned the expected teams so the test wasn't run correctly") + } + }) + + t.Run("system admin", func(t *testing.T) { + rteams, resp := th.SystemAdminClient.GetAllTeams("", 0, 1000) + CheckNoError(t, resp) + for _, rteam := range rteams { + if rteam.Id != team.Id && rteam.Id != team2.Id { + continue + } + + if rteam.Email == "" { + t.Fatal("should not have sanitized email") + } else if rteam.AllowedDomains == "" { + t.Fatal("should not have sanitized allowed domains") + } + } + }) +} + func TestGetTeamByName(t *testing.T) { th := Setup().InitBasic().InitSystemAdmin() defer th.TearDown() @@ -507,6 +740,55 @@ func TestGetTeamByName(t *testing.T) { CheckForbiddenStatus(t, resp) } +func TestGetTeamByNameSanitization(t *testing.T) { + th := Setup().InitBasic().InitSystemAdmin() + defer th.TearDown() + + team, resp := th.Client.CreateTeam(&model.Team{ + DisplayName: t.Name() + "_1", + Name: GenerateTestTeamName(), + Email: GenerateTestEmail(), + Type: model.TEAM_OPEN, + AllowedDomains: "simulator.amazonses.com", + }) + CheckNoError(t, resp) + + t.Run("team user", func(t *testing.T) { + th.LinkUserToTeam(th.BasicUser2, team) + + client := th.CreateClient() + th.LoginBasic2WithClient(client) + + rteam, resp := client.GetTeamByName(team.Name, "") + CheckNoError(t, resp) + if rteam.Email != "" { + t.Fatal("should've sanitized email") + } else if rteam.AllowedDomains != "" { + t.Fatal("should've sanitized allowed domains") + } + }) + + t.Run("team admin/non-admin", func(t *testing.T) { + rteam, resp := th.Client.GetTeamByName(team.Name, "") + CheckNoError(t, resp) + if rteam.Email == "" { + t.Fatal("should not have sanitized email") + } else if rteam.AllowedDomains == "" { + t.Fatal("should not have sanitized allowed domains") + } + }) + + t.Run("system admin", func(t *testing.T) { + rteam, resp := th.SystemAdminClient.GetTeamByName(team.Name, "") + CheckNoError(t, resp) + if rteam.Email == "" { + t.Fatal("should not have sanitized email") + } else if rteam.AllowedDomains == "" { + t.Fatal("should not have sanitized allowed domains") + } + }) +} + func TestSearchAllTeams(t *testing.T) { th := Setup().InitBasic().InitSystemAdmin() defer th.TearDown() @@ -514,8 +796,11 @@ func TestSearchAllTeams(t *testing.T) { oTeam := th.BasicTeam oTeam.AllowOpenInvite = true - updatedTeam, _ := th.App.UpdateTeam(oTeam) - oTeam.UpdateAt = updatedTeam.UpdateAt + if updatedTeam, err := th.App.UpdateTeam(oTeam); err != nil { + t.Fatal(err) + } else { + oTeam.UpdateAt = updatedTeam.UpdateAt + } pTeam := &model.Team{DisplayName: "PName", Name: GenerateTestTeamName(), Email: GenerateTestEmail(), Type: model.TEAM_INVITE} Client.CreateTeam(pTeam) @@ -527,7 +812,7 @@ func TestSearchAllTeams(t *testing.T) { t.Fatal("should have returned 1 team") } - if !reflect.DeepEqual(rteams[0], oTeam) { + if oTeam.Id != rteams[0].Id { t.Fatal("invalid team") } @@ -538,7 +823,7 @@ func TestSearchAllTeams(t *testing.T) { t.Fatal("should have returned 1 team") } - if !reflect.DeepEqual(rteams[0], oTeam) { + if rteams[0].Id != oTeam.Id { t.Fatal("invalid team") } @@ -586,6 +871,86 @@ func TestSearchAllTeams(t *testing.T) { CheckUnauthorizedStatus(t, resp) } +func TestSearchAllTeamsSanitization(t *testing.T) { + th := Setup().InitBasic().InitSystemAdmin() + defer th.TearDown() + + team, resp := th.Client.CreateTeam(&model.Team{ + DisplayName: t.Name() + "_1", + Name: GenerateTestTeamName(), + Email: GenerateTestEmail(), + Type: model.TEAM_OPEN, + AllowedDomains: "simulator.amazonses.com", + }) + CheckNoError(t, resp) + team2, resp := th.Client.CreateTeam(&model.Team{ + DisplayName: t.Name() + "_2", + Name: GenerateTestTeamName(), + Email: GenerateTestEmail(), + Type: model.TEAM_OPEN, + AllowedDomains: "simulator.amazonses.com", + }) + CheckNoError(t, resp) + + t.Run("non-team user", func(t *testing.T) { + client := th.CreateClient() + th.LoginBasic2WithClient(client) + + rteams, resp := client.SearchTeams(&model.TeamSearch{Term: t.Name()}) + CheckNoError(t, resp) + for _, rteam := range rteams { + if rteam.Email != "" { + t.Fatal("should've sanitized email") + } else if rteam.AllowedDomains != "" { + t.Fatal("should've sanitized allowed domains") + } + } + }) + + t.Run("team user", func(t *testing.T) { + th.LinkUserToTeam(th.BasicUser2, team) + + client := th.CreateClient() + th.LoginBasic2WithClient(client) + + rteams, resp := client.SearchTeams(&model.TeamSearch{Term: t.Name()}) + CheckNoError(t, resp) + for _, rteam := range rteams { + if rteam.Email != "" { + t.Fatal("should've sanitized email") + } else if rteam.AllowedDomains != "" { + t.Fatal("should've sanitized allowed domains") + } + } + }) + + t.Run("team admin", func(t *testing.T) { + rteams, resp := th.Client.SearchTeams(&model.TeamSearch{Term: t.Name()}) + CheckNoError(t, resp) + for _, rteam := range rteams { + if rteam.Id == team.Id || rteam.Id == team2.Id || rteam.Id == th.BasicTeam.Id { + if rteam.Email == "" { + t.Fatal("should not have sanitized email") + } else if rteam.AllowedDomains == "" { + t.Fatal("should not have sanitized allowed domains") + } + } + } + }) + + t.Run("system admin", func(t *testing.T) { + rteams, resp := th.SystemAdminClient.SearchTeams(&model.TeamSearch{Term: t.Name()}) + CheckNoError(t, resp) + for _, rteam := range rteams { + if rteam.Email == "" { + t.Fatal("should not have sanitized email") + } else if rteam.AllowedDomains == "" { + t.Fatal("should not have sanitized allowed domains") + } + } + }) +} + func TestGetTeamsForUser(t *testing.T) { th := Setup().InitBasic().InitSystemAdmin() defer th.TearDown() @@ -628,6 +993,82 @@ func TestGetTeamsForUser(t *testing.T) { CheckNoError(t, resp) } +func TestGetTeamsForUserSanitization(t *testing.T) { + th := Setup().InitBasic().InitSystemAdmin() + defer th.TearDown() + + team, resp := th.Client.CreateTeam(&model.Team{ + DisplayName: t.Name() + "_1", + Name: GenerateTestTeamName(), + Email: GenerateTestEmail(), + Type: model.TEAM_OPEN, + AllowedDomains: "simulator.amazonses.com", + }) + CheckNoError(t, resp) + team2, resp := th.Client.CreateTeam(&model.Team{ + DisplayName: t.Name() + "_2", + Name: GenerateTestTeamName(), + Email: GenerateTestEmail(), + Type: model.TEAM_OPEN, + AllowedDomains: "simulator.amazonses.com", + }) + CheckNoError(t, resp) + + t.Run("team user", func(t *testing.T) { + th.LinkUserToTeam(th.BasicUser2, team) + th.LinkUserToTeam(th.BasicUser2, team2) + + client := th.CreateClient() + th.LoginBasic2WithClient(client) + + rteams, resp := client.GetTeamsForUser(th.BasicUser2.Id, "") + CheckNoError(t, resp) + for _, rteam := range rteams { + if rteam.Id != team.Id && rteam.Id != team2.Id { + continue + } + + if rteam.Email != "" { + t.Fatal("should've sanitized email") + } else if rteam.AllowedDomains != "" { + t.Fatal("should've sanitized allowed domains") + } + } + }) + + t.Run("team admin", func(t *testing.T) { + rteams, resp := th.Client.GetTeamsForUser(th.BasicUser.Id, "") + CheckNoError(t, resp) + for _, rteam := range rteams { + if rteam.Id != team.Id && rteam.Id != team2.Id { + continue + } + + if rteam.Email == "" { + t.Fatal("should not have sanitized email") + } else if rteam.AllowedDomains == "" { + t.Fatal("should not have sanitized allowed domains") + } + } + }) + + t.Run("system admin", func(t *testing.T) { + rteams, resp := th.SystemAdminClient.GetTeamsForUser(th.BasicUser.Id, "") + CheckNoError(t, resp) + for _, rteam := range rteams { + if rteam.Id != team.Id && rteam.Id != team2.Id { + continue + } + + if rteam.Email == "" { + t.Fatal("should not have sanitized email") + } else if rteam.AllowedDomains == "" { + t.Fatal("should not have sanitized allowed domains") + } + } + }) +} + func TestGetTeamMember(t *testing.T) { th := Setup().InitBasic().InitSystemAdmin() defer th.TearDown() diff --git a/app/team.go b/app/team.go index 4bfb617a8a..1bc77c9f03 100644 --- a/app/team.go +++ b/app/team.go @@ -104,8 +104,6 @@ func (a *App) UpdateTeam(team *model.Team) (*model.Team, *model.AppError) { return nil, result.Err } - oldTeam.Sanitize() - a.sendUpdatedTeamEvent(oldTeam) return oldTeam, nil @@ -124,16 +122,18 @@ func (a *App) PatchTeam(teamId string, patch *model.TeamPatch) (*model.Team, *mo return nil, err } - updatedTeam.Sanitize() - a.sendUpdatedTeamEvent(updatedTeam) return updatedTeam, nil } func (a *App) sendUpdatedTeamEvent(team *model.Team) { + sanitizedTeam := &model.Team{} + *sanitizedTeam = *team + sanitizedTeam.Sanitize() + message := model.NewWebSocketEvent(model.WEBSOCKET_EVENT_UPDATE_TEAM, "", "", "", nil) - message.Add("team", team.ToJson()) + message.Add("team", sanitizedTeam.ToJson()) a.Go(func() { a.Publish(message) }) @@ -833,3 +833,19 @@ func (a *App) GetTeamIdFromQuery(query url.Values) (string, *model.AppError) { return "", nil } + +func SanitizeTeam(session model.Session, team *model.Team) *model.Team { + if !SessionHasPermissionToTeam(session, team.Id, model.PERMISSION_MANAGE_TEAM) { + team.Sanitize() + } + + return team +} + +func SanitizeTeams(session model.Session, teams []*model.Team) []*model.Team { + for _, team := range teams { + SanitizeTeam(session, team) + } + + return teams +} diff --git a/app/team_test.go b/app/team_test.go index 7992dd0c36..61ae03f749 100644 --- a/app/team_test.go +++ b/app/team_test.go @@ -179,3 +179,217 @@ func TestPermanentDeleteTeam(t *testing.T) { t.Fatal(err) } } + +func TestSanitizeTeam(t *testing.T) { + th := Setup() + defer th.TearDown() + + team := &model.Team{ + Id: model.NewId(), + Email: th.MakeEmail(), + AllowedDomains: "example.com", + } + copyTeam := func() *model.Team { + copy := &model.Team{} + *copy = *team + return copy + } + + t.Run("not a user of the team", func(t *testing.T) { + userId := model.NewId() + session := model.Session{ + Roles: model.ROLE_SYSTEM_USER.Id, + TeamMembers: []*model.TeamMember{ + { + UserId: userId, + TeamId: model.NewId(), + Roles: model.ROLE_TEAM_USER.Id, + }, + }, + } + + sanitized := SanitizeTeam(session, copyTeam()) + if sanitized.Email != "" && sanitized.AllowedDomains != "" { + t.Fatal("should've sanitized team") + } + }) + + t.Run("user of the team", func(t *testing.T) { + userId := model.NewId() + session := model.Session{ + Roles: model.ROLE_SYSTEM_USER.Id, + TeamMembers: []*model.TeamMember{ + { + UserId: userId, + TeamId: team.Id, + Roles: model.ROLE_TEAM_USER.Id, + }, + }, + } + + sanitized := SanitizeTeam(session, copyTeam()) + if sanitized.Email != "" && sanitized.AllowedDomains != "" { + t.Fatal("should've sanitized team") + } + }) + + t.Run("team admin", func(t *testing.T) { + userId := model.NewId() + session := model.Session{ + Roles: model.ROLE_SYSTEM_USER.Id, + TeamMembers: []*model.TeamMember{ + { + UserId: userId, + TeamId: team.Id, + Roles: model.ROLE_TEAM_USER.Id + " " + model.ROLE_TEAM_ADMIN.Id, + }, + }, + } + + sanitized := SanitizeTeam(session, copyTeam()) + if sanitized.Email == "" && sanitized.AllowedDomains == "" { + t.Fatal("shouldn't have sanitized team") + } + }) + + t.Run("team admin of another team", func(t *testing.T) { + userId := model.NewId() + session := model.Session{ + Roles: model.ROLE_SYSTEM_USER.Id, + TeamMembers: []*model.TeamMember{ + { + UserId: userId, + TeamId: model.NewId(), + Roles: model.ROLE_TEAM_USER.Id + " " + model.ROLE_TEAM_ADMIN.Id, + }, + }, + } + + sanitized := SanitizeTeam(session, copyTeam()) + if sanitized.Email != "" && sanitized.AllowedDomains != "" { + t.Fatal("should've sanitized team") + } + }) + + t.Run("system admin, not a user of team", func(t *testing.T) { + userId := model.NewId() + session := model.Session{ + Roles: model.ROLE_SYSTEM_USER.Id + " " + model.ROLE_SYSTEM_ADMIN.Id, + TeamMembers: []*model.TeamMember{ + { + UserId: userId, + TeamId: model.NewId(), + Roles: model.ROLE_TEAM_USER.Id, + }, + }, + } + + sanitized := SanitizeTeam(session, copyTeam()) + if sanitized.Email == "" && sanitized.AllowedDomains == "" { + t.Fatal("shouldn't have sanitized team") + } + }) + + t.Run("system admin, user of team", func(t *testing.T) { + userId := model.NewId() + session := model.Session{ + Roles: model.ROLE_SYSTEM_USER.Id + " " + model.ROLE_SYSTEM_ADMIN.Id, + TeamMembers: []*model.TeamMember{ + { + UserId: userId, + TeamId: team.Id, + Roles: model.ROLE_TEAM_USER.Id, + }, + }, + } + + sanitized := SanitizeTeam(session, copyTeam()) + if sanitized.Email == "" && sanitized.AllowedDomains == "" { + t.Fatal("shouldn't have sanitized team") + } + }) +} + +func TestSanitizeTeams(t *testing.T) { + th := Setup() + defer th.TearDown() + + t.Run("not a system admin", func(t *testing.T) { + teams := []*model.Team{ + { + Id: model.NewId(), + Email: th.MakeEmail(), + AllowedDomains: "example.com", + }, + { + Id: model.NewId(), + Email: th.MakeEmail(), + AllowedDomains: "example.com", + }, + } + + userId := model.NewId() + session := model.Session{ + Roles: model.ROLE_SYSTEM_USER.Id, + TeamMembers: []*model.TeamMember{ + { + UserId: userId, + TeamId: teams[0].Id, + Roles: model.ROLE_TEAM_USER.Id, + }, + { + UserId: userId, + TeamId: teams[1].Id, + Roles: model.ROLE_TEAM_USER.Id + " " + model.ROLE_TEAM_ADMIN.Id, + }, + }, + } + + sanitized := SanitizeTeams(session, teams) + + if sanitized[0].Email != "" && sanitized[0].AllowedDomains != "" { + t.Fatal("should've sanitized first team") + } + + if sanitized[1].Email == "" && sanitized[1].AllowedDomains == "" { + t.Fatal("shouldn't have sanitized second team") + } + }) + + t.Run("system admin", func(t *testing.T) { + teams := []*model.Team{ + { + Id: model.NewId(), + Email: th.MakeEmail(), + AllowedDomains: "example.com", + }, + { + Id: model.NewId(), + Email: th.MakeEmail(), + AllowedDomains: "example.com", + }, + } + + userId := model.NewId() + session := model.Session{ + Roles: model.ROLE_SYSTEM_USER.Id + " " + model.ROLE_SYSTEM_ADMIN.Id, + TeamMembers: []*model.TeamMember{ + { + UserId: userId, + TeamId: teams[0].Id, + Roles: model.ROLE_TEAM_USER.Id, + }, + }, + } + + sanitized := SanitizeTeams(session, teams) + + if sanitized[0].Email == "" && sanitized[0].AllowedDomains == "" { + t.Fatal("shouldn't have sanitized first team") + } + + if sanitized[1].Email == "" && sanitized[1].AllowedDomains == "" { + t.Fatal("shouldn't have sanitized second team") + } + }) +} diff --git a/model/client.go b/model/client.go index 54d8fc859e..37f014e6be 100644 --- a/model/client.go +++ b/model/client.go @@ -429,7 +429,7 @@ func (c *Client) UpdateTeam(team *Team) (*Result, *AppError) { } else { defer closeBody(r) return &Result{r.Header.Get(HEADER_REQUEST_ID), - r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil + r.Header.Get(HEADER_ETAG_SERVER), TeamFromJson(r.Body)}, nil } } diff --git a/store/sqlstore/audit_store.go b/store/sqlstore/audit_store.go index 4910db79bf..3cc0758cc4 100644 --- a/store/sqlstore/audit_store.go +++ b/store/sqlstore/audit_store.go @@ -36,38 +36,21 @@ func (s SqlAuditStore) CreateIndexesIfNotExists() { } func (s SqlAuditStore) Save(audit *model.Audit) store.StoreChannel { - - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { audit.Id = model.NewId() audit.CreateAt = model.GetMillis() if err := s.GetMaster().Insert(audit); err != nil { result.Err = model.NewAppError("SqlAuditStore.Save", "store.sql_audit.save.saving.app_error", nil, "user_id="+audit.UserId+" action="+audit.Action, http.StatusInternalServerError) } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlAuditStore) Get(user_id string, offset int, limit int) store.StoreChannel { - - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { if limit > 1000 { limit = 1000 result.Err = model.NewAppError("SqlAuditStore.Get", "store.sql_audit.get.limit.app_error", nil, "user_id="+user_id, http.StatusBadRequest) - storeChannel <- result - close(storeChannel) return } @@ -85,39 +68,20 @@ func (s SqlAuditStore) Get(user_id string, offset int, limit int) store.StoreCha } else { result.Data = audits } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlAuditStore) PermanentDeleteByUser(userId string) store.StoreChannel { - - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { if _, err := s.GetMaster().Exec("DELETE FROM Audits WHERE UserId = :userId", map[string]interface{}{"userId": userId}); err != nil { result.Err = model.NewAppError("SqlAuditStore.Delete", "store.sql_audit.permanent_delete_by_user.app_error", nil, "user_id="+userId, http.StatusInternalServerError) } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlAuditStore) PermanentDeleteBatch(endTime int64, limit int64) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { var query string if *utils.Cfg.SqlSettings.DriverName == "postgres" { query = "DELETE from Audits WHERE Id = any (array (SELECT Id FROM Audits WHERE CreateAt < :EndTime LIMIT :Limit))" @@ -137,10 +101,5 @@ func (s SqlAuditStore) PermanentDeleteBatch(endTime int64, limit int64) store.St result.Data = rowsAffected } } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } diff --git a/store/sqlstore/channel_store.go b/store/sqlstore/channel_store.go index c9a4f695e9..1ddc887bd0 100644 --- a/store/sqlstore/channel_store.go +++ b/store/sqlstore/channel_store.go @@ -92,17 +92,14 @@ func (s SqlChannelStore) CreateIndexesIfNotExists() { } func (s SqlChannelStore) Save(channel *model.Channel) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - var result store.StoreResult + return store.Do(func(result *store.StoreResult) { if channel.Type == model.CHANNEL_DIRECT { result.Err = model.NewAppError("SqlChannelStore.Save", "store.sql_channel.save.direct_channel.app_error", nil, "", http.StatusBadRequest) } else { if transaction, err := s.GetMaster().Begin(); err != nil { result.Err = model.NewAppError("SqlChannelStore.Save", "store.sql_channel.save.open_transaction.app_error", nil, err.Error(), http.StatusInternalServerError) } else { - result = s.saveChannelT(transaction, channel) + *result = s.saveChannelT(transaction, channel) if result.Err != nil { transaction.Rollback() } else { @@ -112,12 +109,7 @@ func (s SqlChannelStore) Save(channel *model.Channel) store.StoreChannel { } } } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlChannelStore) CreateDirectChannel(userId string, otherUserId string) store.StoreChannel { @@ -144,11 +136,7 @@ func (s SqlChannelStore) CreateDirectChannel(userId string, otherUserId string) } func (s SqlChannelStore) SaveDirectChannel(directchannel *model.Channel, member1 *model.ChannelMember, member2 *model.ChannelMember) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - var result store.StoreResult - + return store.Do(func(result *store.StoreResult) { if directchannel.Type != model.CHANNEL_DIRECT { result.Err = model.NewAppError("SqlChannelStore.SaveDirectChannel", "store.sql_channel.save_direct_channel.not_direct.app_error", nil, "", http.StatusBadRequest) } else { @@ -185,18 +173,13 @@ func (s SqlChannelStore) SaveDirectChannel(directchannel *model.Channel, member1 if err := transaction.Commit(); err != nil { result.Err = model.NewAppError("SqlChannelStore.SaveDirectChannel", "store.sql_channel.save_direct_channel.commit.app_error", nil, err.Error(), http.StatusInternalServerError) } else { - result = channelResult + *result = channelResult } } } } } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlChannelStore) saveChannelT(transaction *gorp.Transaction, channel *model.Channel) store.StoreResult { @@ -243,17 +226,10 @@ func (s SqlChannelStore) saveChannelT(transaction *gorp.Transaction, channel *mo } func (s SqlChannelStore) Update(channel *model.Channel) store.StoreChannel { - - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { channel.PreUpdate() if result.Err = channel.IsValid(); result.Err != nil { - storeChannel <- result - close(storeChannel) return } @@ -274,20 +250,11 @@ func (s SqlChannelStore) Update(channel *model.Channel) store.StoreChannel { } else { result.Data = channel } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlChannelStore) extraUpdated(channel *model.Channel) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { channel.ExtraUpdated() _, err := s.GetMaster().Exec( @@ -302,20 +269,11 @@ func (s SqlChannelStore) extraUpdated(channel *model.Channel) store.StoreChannel if err != nil { result.Err = model.NewAppError("SqlChannelStore.extraUpdated", "store.sql_channel.extra_updated.app_error", nil, "id="+channel.Id+", "+err.Error(), http.StatusInternalServerError) } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlChannelStore) GetChannelUnread(channelId, userId string) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { var unreadChannel model.ChannelUnread err := s.GetReplica().SelectOne(&unreadChannel, `SELECT @@ -337,12 +295,7 @@ func (s SqlChannelStore) GetChannelUnread(channelId, userId string) store.StoreC } else { result.Data = &unreadChannel } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (us SqlChannelStore) InvalidateChannel(id string) { @@ -358,10 +311,7 @@ func (s SqlChannelStore) Get(id string, allowFromCache bool) store.StoreChannel } func (s SqlChannelStore) GetPinnedPosts(channelId string) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} + return store.Do(func(result *store.StoreResult) { pl := model.NewPostList() var posts []*model.Post @@ -375,12 +325,7 @@ func (s SqlChannelStore) GetPinnedPosts(channelId string) store.StoreChannel { } result.Data = pl - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlChannelStore) GetFromMaster(id string) store.StoreChannel { @@ -388,11 +333,7 @@ func (s SqlChannelStore) GetFromMaster(id string) store.StoreChannel { } func (s SqlChannelStore) get(id string, master bool, allowFromCache bool) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { var db *gorp.DbMap if master { db = s.GetMaster() @@ -406,8 +347,6 @@ func (s SqlChannelStore) get(id string, master bool, allowFromCache bool) store. s.metrics.IncrementMemCacheHitCounter("Channel") } result.Data = (cacheItem.(*model.Channel)).DeepCopy() - storeChannel <- result - close(storeChannel) return } else { if s.metrics != nil { @@ -428,12 +367,7 @@ func (s SqlChannelStore) get(id string, master bool, allowFromCache bool) store. result.Data = obj.(*model.Channel) channelCache.AddWithExpiresInSecs(id, obj.(*model.Channel), CHANNEL_CACHE_SEC) } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlChannelStore) Delete(channelId string, time int64) store.StoreChannel { @@ -445,73 +379,37 @@ func (s SqlChannelStore) Restore(channelId string, time int64) store.StoreChanne } func (s SqlChannelStore) SetDeleteAt(channelId string, deleteAt int64, updateAt int64) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { _, err := s.GetMaster().Exec("Update Channels SET DeleteAt = :DeleteAt, UpdateAt = :UpdateAt WHERE Id = :ChannelId", map[string]interface{}{"DeleteAt": deleteAt, "UpdateAt": updateAt, "ChannelId": channelId}) if err != nil { result.Err = model.NewAppError("SqlChannelStore.Delete", "store.sql_channel.delete.channel.app_error", nil, "id="+channelId+", err="+err.Error(), http.StatusInternalServerError) } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlChannelStore) PermanentDeleteByTeam(teamId string) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { if _, err := s.GetMaster().Exec("DELETE FROM Channels WHERE TeamId = :TeamId", map[string]interface{}{"TeamId": teamId}); err != nil { result.Err = model.NewAppError("SqlChannelStore.PermanentDeleteByTeam", "store.sql_channel.permanent_delete_by_team.app_error", nil, "teamId="+teamId+", "+err.Error(), http.StatusInternalServerError) } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlChannelStore) PermanentDelete(channelId string) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { if _, err := s.GetMaster().Exec("DELETE FROM Channels WHERE Id = :ChannelId", map[string]interface{}{"ChannelId": channelId}); err != nil { result.Err = model.NewAppError("SqlChannelStore.PermanentDelete", "store.sql_channel.permanent_delete.app_error", nil, "channel_id="+channelId+", "+err.Error(), http.StatusInternalServerError) } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlChannelStore) PermanentDeleteMembersByChannel(channelId string) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { _, err := s.GetMaster().Exec("DELETE FROM ChannelMembers WHERE ChannelId = :ChannelId", map[string]interface{}{"ChannelId": channelId}) if err != nil { result.Err = model.NewAppError("SqlChannelStore.RemoveAllMembersByChannel", "store.sql_channel.remove_member.app_error", nil, "channel_id="+channelId+", "+err.Error(), http.StatusInternalServerError) } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } type channelWithMember struct { @@ -520,11 +418,7 @@ type channelWithMember struct { } func (s SqlChannelStore) GetChannels(teamId string, userId string) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { data := &model.ChannelList{} _, err := s.GetReplica().Select(data, "SELECT Channels.* 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}) @@ -537,20 +431,11 @@ func (s SqlChannelStore) GetChannels(teamId string, userId string) store.StoreCh result.Data = data } } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlChannelStore) GetMoreChannels(teamId string, userId string, offset int, limit int) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { data := &model.ChannelList{} _, err := s.GetReplica().Select(data, `SELECT @@ -581,20 +466,11 @@ func (s SqlChannelStore) GetMoreChannels(teamId string, userId string, offset in } else { result.Data = data } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlChannelStore) GetPublicChannelsForTeam(teamId string, offset int, limit int) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { data := &model.ChannelList{} _, err := s.GetReplica().Select(data, `SELECT @@ -615,20 +491,11 @@ func (s SqlChannelStore) GetPublicChannelsForTeam(teamId string, offset int, lim } else { result.Data = data } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlChannelStore) GetPublicChannelsByIdsForTeam(teamId string, channelIds []string) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { props := make(map[string]interface{}) props["teamId"] = teamId @@ -666,11 +533,7 @@ func (s SqlChannelStore) GetPublicChannelsByIdsForTeam(teamId string, channelIds } result.Data = data - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } type channelIdWithCountAndUpdateAt struct { @@ -680,11 +543,7 @@ type channelIdWithCountAndUpdateAt struct { } func (s SqlChannelStore) GetChannelCounts(teamId string, userId string) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.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 OR TeamId = '') AND DeleteAt = 0 ORDER BY DisplayName", map[string]interface{}{"TeamId": teamId, "UserId": userId}) @@ -700,20 +559,11 @@ func (s SqlChannelStore) GetChannelCounts(teamId string, userId string) store.St result.Data = counts } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlChannelStore) GetTeamChannels(teamId string) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { data := &model.ChannelList{} _, err := s.GetReplica().Select(data, "SELECT * FROM Channels WHERE TeamId = :TeamId And Type != 'D' ORDER BY DisplayName", map[string]interface{}{"TeamId": teamId}) @@ -726,12 +576,7 @@ func (s SqlChannelStore) GetTeamChannels(teamId string) store.StoreChannel { result.Data = data } } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlChannelStore) GetByName(teamId string, name string, allowFromCache bool) store.StoreChannel { @@ -743,18 +588,13 @@ func (s SqlChannelStore) GetByNameIncludeDeleted(teamId string, name string, all } func (s SqlChannelStore) getByName(teamId string, name string, includeDeleted bool, allowFromCache bool) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - var query string if includeDeleted { query = "SELECT * FROM Channels WHERE (TeamId = :TeamId OR TeamId = '') AND Name = :Name" } else { query = "SELECT * FROM Channels WHERE (TeamId = :TeamId OR TeamId = '') AND Name = :Name AND DeleteAt = 0" } - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { channel := model.Channel{} if allowFromCache { @@ -763,8 +603,6 @@ func (s SqlChannelStore) getByName(teamId string, name string, includeDeleted bo s.metrics.IncrementMemCacheHitCounter("Channel By Name") } result.Data = cacheItem.(*model.Channel) - storeChannel <- result - close(storeChannel) return } else { if s.metrics != nil { @@ -782,20 +620,11 @@ func (s SqlChannelStore) getByName(teamId string, name string, includeDeleted bo result.Data = &channel channelByNameCache.AddWithExpiresInSecs(teamId+name, &channel, CHANNEL_CACHE_SEC) } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlChannelStore) GetDeletedByName(teamId string, name string) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { channel := model.Channel{} 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 { @@ -807,20 +636,11 @@ func (s SqlChannelStore) GetDeletedByName(teamId string, name string) store.Stor } else { result.Data = &channel } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlChannelStore) GetDeleted(teamId string, offset int, limit int) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { channels := &model.ChannelList{} if _, err := s.GetReplica().Select(channels, "SELECT * FROM Channels WHERE (TeamId = :TeamId OR TeamId = '') AND DeleteAt != 0 ORDER BY DisplayName LIMIT :Limit OFFSET :Offset", map[string]interface{}{"TeamId": teamId, "Limit": limit, "Offset": offset}); err != nil { @@ -832,19 +652,11 @@ func (s SqlChannelStore) GetDeleted(teamId string, offset int, limit int) store. } else { result.Data = channels } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlChannelStore) SaveMember(member *model.ChannelMember) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - var result store.StoreResult + return store.Do(func(result *store.StoreResult) { // Grab the channel we are saving this member to if cr := <-s.GetFromMaster(member.ChannelId); cr.Err != nil { result.Err = cr.Err @@ -854,7 +666,7 @@ func (s SqlChannelStore) SaveMember(member *model.ChannelMember) store.StoreChan if transaction, err := s.GetMaster().Begin(); err != nil { result.Err = model.NewAppError("SqlChannelStore.SaveMember", "store.sql_channel.save_member.open_transaction.app_error", nil, err.Error(), http.StatusInternalServerError) } else { - result = s.saveMemberT(transaction, member, channel) + *result = s.saveMemberT(transaction, member, channel) if result.Err != nil { transaction.Rollback() } else { @@ -870,12 +682,7 @@ func (s SqlChannelStore) SaveMember(member *model.ChannelMember) store.StoreChan } s.InvalidateAllChannelMembersForUser(member.UserId) - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlChannelStore) saveMemberT(transaction *gorp.Transaction, member *model.ChannelMember, channel *model.Channel) store.StoreResult { @@ -900,16 +707,10 @@ func (s SqlChannelStore) saveMemberT(transaction *gorp.Transaction, member *mode } func (s SqlChannelStore) UpdateMember(member *model.ChannelMember) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { member.PreUpdate() if result.Err = member.IsValid(); result.Err != nil { - storeChannel <- result - close(storeChannel) return } @@ -918,20 +719,11 @@ func (s SqlChannelStore) UpdateMember(member *model.ChannelMember) store.StoreCh } else { result.Data = member } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlChannelStore) GetMembers(channelId string, offset, limit int) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { var members model.ChannelMembers _, err := s.GetReplica().Select(&members, "SELECT * FROM ChannelMembers WHERE ChannelId = :ChannelId LIMIT :Limit OFFSET :Offset", map[string]interface{}{"ChannelId": channelId, "Limit": limit, "Offset": offset}) if err != nil { @@ -939,20 +731,11 @@ func (s SqlChannelStore) GetMembers(channelId string, offset, limit int) store.S } else { result.Data = &members } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlChannelStore) GetMember(channelId string, userId string) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { var member model.ChannelMember if err := s.GetReplica().SelectOne(&member, "SELECT * FROM ChannelMembers WHERE ChannelId = :ChannelId AND UserId = :UserId", map[string]interface{}{"ChannelId": channelId, "UserId": userId}); err != nil { @@ -964,12 +747,7 @@ func (s SqlChannelStore) GetMember(channelId string, userId string) store.StoreC } else { result.Data = &member } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (us SqlChannelStore) InvalidateAllChannelMembersForUser(userId string) { @@ -1007,11 +785,7 @@ func (us SqlChannelStore) IsUserInChannelUseCache(userId string, channelId strin } func (s SqlChannelStore) GetMemberForPost(postId string, userId string) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { member := &model.ChannelMember{} if err := s.GetReplica().SelectOne( member, @@ -1028,12 +802,7 @@ func (s SqlChannelStore) GetMemberForPost(postId string, userId string) store.St } else { result.Data = member } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } type allChannelMember struct { @@ -1042,19 +811,13 @@ type allChannelMember struct { } func (s SqlChannelStore) GetAllChannelMembersForUser(userId string, allowFromCache bool) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { if allowFromCache { if cacheItem, ok := allChannelMembersForUserCache.Get(userId); ok { if s.metrics != nil { s.metrics.IncrementMemCacheHitCounter("All Channel Members for User") } result.Data = cacheItem.(map[string]string) - storeChannel <- result - close(storeChannel) return } else { if s.metrics != nil { @@ -1085,12 +848,7 @@ func (s SqlChannelStore) GetAllChannelMembersForUser(userId string, allowFromCac allChannelMembersForUserCache.AddWithExpiresInSecs(userId, ids, ALL_CHANNEL_MEMBERS_FOR_USER_CACHE_SEC) } } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (us SqlChannelStore) InvalidateCacheForChannelMembersNotifyProps(channelId string) { @@ -1103,19 +861,13 @@ type allChannelMemberNotifyProps struct { } func (s SqlChannelStore) GetAllChannelMembersNotifyPropsForChannel(channelId string, allowFromCache bool) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { if allowFromCache { if cacheItem, ok := allChannelMembersNotifyPropsForChannelCache.Get(channelId); ok { if s.metrics != nil { s.metrics.IncrementMemCacheHitCounter("All Channel Members Notify Props for Channel") } result.Data = cacheItem.(map[string]model.StringMap) - storeChannel <- result - close(storeChannel) return } else { if s.metrics != nil { @@ -1147,12 +899,7 @@ func (s SqlChannelStore) GetAllChannelMembersNotifyPropsForChannel(channelId str allChannelMembersNotifyPropsForChannelCache.AddWithExpiresInSecs(channelId, props, ALL_CHANNEL_MEMBERS_NOTIFY_PROPS_FOR_CHANNEL_CACHE_SEC) } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (us SqlChannelStore) InvalidateMemberCount(channelId string) { @@ -1179,19 +926,13 @@ func (s SqlChannelStore) GetMemberCountFromCache(channelId string) int64 { } func (s SqlChannelStore) GetMemberCount(channelId string, allowFromCache bool) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { if allowFromCache { if cacheItem, ok := channelMemberCountsCache.Get(channelId); ok { if s.metrics != nil { s.metrics.IncrementMemCacheHitCounter("Channel Member Counts") } result.Data = cacheItem.(int64) - storeChannel <- result - close(storeChannel) return } else { if s.metrics != nil { @@ -1223,20 +964,11 @@ func (s SqlChannelStore) GetMemberCount(channelId string, allowFromCache bool) s channelMemberCountsCache.AddWithExpiresInSecs(channelId, count, CHANNEL_MEMBERS_COUNTS_CACHE_SEC) } } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlChannelStore) RemoveMember(channelId string, userId string) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { // Grab the channel we are saving this member to if cr := <-s.Get(channelId, true); cr.Err != nil { result.Err = cr.Err @@ -1253,37 +985,19 @@ func (s SqlChannelStore) RemoveMember(channelId string, userId string) store.Sto } } } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlChannelStore) PermanentDeleteMembersByUser(userId string) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { if _, err := s.GetMaster().Exec("DELETE FROM ChannelMembers WHERE UserId = :UserId", map[string]interface{}{"UserId": userId}); err != nil { result.Err = model.NewAppError("SqlChannelStore.RemoveMember", "store.sql_channel.permanent_delete_members_by_user.app_error", nil, "user_id="+userId+", "+err.Error(), http.StatusInternalServerError) } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlChannelStore) UpdateLastViewedAt(channelIds []string, userId string) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { props := make(map[string]interface{}) updateIdQuery := "" @@ -1308,8 +1022,6 @@ func (s SqlChannelStore) UpdateLastViewedAt(channelIds []string, userId string) if _, err := s.GetMaster().Select(&lastPostAtTimes, selectQuery, props); err != nil { result.Err = model.NewAppError("SqlChannelStore.UpdateLastViewedAt", "store.sql_channel.update_last_viewed_at.app_error", nil, "channel_ids="+strings.Join(channelIds, ",")+", user_id="+userId+", "+err.Error(), http.StatusInternalServerError) - storeChannel <- result - close(storeChannel) return } @@ -1361,20 +1073,11 @@ func (s SqlChannelStore) UpdateLastViewedAt(channelIds []string, userId string) } else { result.Data = times } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlChannelStore) IncrementMentionCount(channelId string, userId string) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { _, err := s.GetMaster().Exec( `UPDATE ChannelMembers @@ -1388,20 +1091,11 @@ func (s SqlChannelStore) IncrementMentionCount(channelId string, userId string) if err != nil { result.Err = model.NewAppError("SqlChannelStore.IncrementMentionCount", "store.sql_channel.increment_mention_count.app_error", nil, "channel_id="+channelId+", user_id="+userId+", "+err.Error(), http.StatusInternalServerError) } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlChannelStore) GetAll(teamId string) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { var data []*model.Channel _, err := s.GetReplica().Select(&data, "SELECT * FROM Channels WHERE TeamId = :TeamId AND Type != 'D' ORDER BY Name", map[string]interface{}{"TeamId": teamId}) @@ -1410,20 +1104,11 @@ func (s SqlChannelStore) GetAll(teamId string) store.StoreChannel { } else { result.Data = data } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlChannelStore) GetForPost(postId string) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { channel := &model.Channel{} if err := s.GetReplica().SelectOne( channel, @@ -1439,20 +1124,11 @@ func (s SqlChannelStore) GetForPost(postId string) store.StoreChannel { } else { result.Data = channel } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlChannelStore) AnalyticsTypeCount(teamId string, channelType string) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { query := "SELECT COUNT(Id) AS Value FROM Channels WHERE Type = :ChannelType" if len(teamId) > 0 { @@ -1465,20 +1141,11 @@ func (s SqlChannelStore) AnalyticsTypeCount(teamId string, channelType string) s } else { result.Data = v } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlChannelStore) AnalyticsDeletedTypeCount(teamId string, channelType string) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { query := "SELECT COUNT(Id) AS Value FROM Channels WHERE Type = :ChannelType AND DeleteAt > 0" if len(teamId) > 0 { @@ -1491,20 +1158,11 @@ func (s SqlChannelStore) AnalyticsDeletedTypeCount(teamId string, channelType st } else { result.Data = v } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlChannelStore) ExtraUpdateByUser(userId string, time int64) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { _, err := s.GetMaster().Exec( `UPDATE Channels SET ExtraUpdateAt = :Time WHERE Id IN (SELECT ChannelId FROM ChannelMembers WHERE UserId = :UserId);`, @@ -1513,20 +1171,11 @@ func (s SqlChannelStore) ExtraUpdateByUser(userId string, time int64) store.Stor if err != nil { result.Err = model.NewAppError("SqlChannelStore.extraUpdated", "store.sql_channel.extra_updated.app_error", nil, "user_id="+userId+", "+err.Error(), http.StatusInternalServerError) } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlChannelStore) GetMembersForUser(teamId string, userId string) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { members := &model.ChannelMembers{} _, err := s.GetReplica().Select(members, ` SELECT cm.* @@ -1543,18 +1192,11 @@ func (s SqlChannelStore) GetMembersForUser(teamId string, userId string) store.S } else { result.Data = members } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlChannelStore) SearchInTeam(teamId string, term string) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { + return store.Do(func(result *store.StoreResult) { searchQuery := ` SELECT * @@ -1568,17 +1210,12 @@ func (s SqlChannelStore) SearchInTeam(teamId string, term string) store.StoreCha ORDER BY DisplayName LIMIT 100` - storeChannel <- s.performSearch(searchQuery, term, map[string]interface{}{"TeamId": teamId}) - close(storeChannel) - }() - - return storeChannel + *result = s.performSearch(searchQuery, term, map[string]interface{}{"TeamId": teamId}) + }) } func (s SqlChannelStore) SearchMore(userId string, teamId string, term string) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { + return store.Do(func(result *store.StoreResult) { searchQuery := ` SELECT * @@ -1602,11 +1239,8 @@ func (s SqlChannelStore) SearchMore(userId string, teamId string, term string) s ORDER BY DisplayName LIMIT 100` - storeChannel <- s.performSearch(searchQuery, term, map[string]interface{}{"TeamId": teamId, "UserId": userId}) - close(storeChannel) - }() - - return storeChannel + *result = s.performSearch(searchQuery, term, map[string]interface{}{"TeamId": teamId, "UserId": userId}) + }) } func (s SqlChannelStore) performSearch(searchQuery string, term string, parameters map[string]interface{}) store.StoreResult { @@ -1659,11 +1293,7 @@ func (s SqlChannelStore) performSearch(searchQuery string, term string, paramete } func (s SqlChannelStore) GetMembersByIds(channelId string, userIds []string) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { var members model.ChannelMembers props := make(map[string]interface{}) idQuery := "" @@ -1685,10 +1315,5 @@ func (s SqlChannelStore) GetMembersByIds(channelId string, userIds []string) sto result.Data = &members } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } diff --git a/store/sqlstore/cluster_discovery_store.go b/store/sqlstore/cluster_discovery_store.go index 4c7d2706b0..94639f74ca 100644 --- a/store/sqlstore/cluster_discovery_store.go +++ b/store/sqlstore/cluster_discovery_store.go @@ -29,35 +29,20 @@ func NewSqlClusterDiscoveryStore(sqlStore SqlStore) store.ClusterDiscoveryStore } func (s sqlClusterDiscoveryStore) Save(ClusterDiscovery *model.ClusterDiscovery) store.StoreChannel { - - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { ClusterDiscovery.PreSave() if result.Err = ClusterDiscovery.IsValid(); result.Err != nil { - storeChannel <- result - close(storeChannel) return } if err := s.GetMaster().Insert(ClusterDiscovery); err != nil { result.Err = model.NewAppError("SqlClusterDiscoveryStore.Save", "Failed to save ClusterDiscovery row", nil, err.Error(), http.StatusInternalServerError) } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s sqlClusterDiscoveryStore) Delete(ClusterDiscovery *model.ClusterDiscovery) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} + return store.Do(func(result *store.StoreResult) { result.Data = false if count, err := s.GetMaster().SelectInt( @@ -82,19 +67,11 @@ func (s sqlClusterDiscoveryStore) Delete(ClusterDiscovery *model.ClusterDiscover result.Data = true } } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s sqlClusterDiscoveryStore) Exists(ClusterDiscovery *model.ClusterDiscovery) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} + return store.Do(func(result *store.StoreResult) { result.Data = false if count, err := s.GetMaster().SelectInt( @@ -120,21 +97,11 @@ func (s sqlClusterDiscoveryStore) Exists(ClusterDiscovery *model.ClusterDiscover result.Data = true } } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s sqlClusterDiscoveryStore) GetAll(ClusterDiscoveryType, clusterName string) store.StoreChannel { - - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { lastPingAt := model.GetMillis() - model.CDS_OFFLINE_AFTER_MILLIS var list []*model.ClusterDiscovery @@ -160,20 +127,11 @@ func (s sqlClusterDiscoveryStore) GetAll(ClusterDiscoveryType, clusterName strin } else { result.Data = list } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s sqlClusterDiscoveryStore) SetLastPingAt(ClusterDiscovery *model.ClusterDiscovery) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { if _, err := s.GetMaster().Exec( ` UPDATE ClusterDiscovery @@ -193,21 +151,11 @@ func (s sqlClusterDiscoveryStore) SetLastPingAt(ClusterDiscovery *model.ClusterD ); err != nil { result.Err = model.NewAppError("SqlClusterDiscoveryStore.GetAllForType", "Failed to update last ping at", nil, err.Error(), http.StatusInternalServerError) } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s sqlClusterDiscoveryStore) Cleanup() store.StoreChannel { - - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { if _, err := s.GetMaster().Exec( ` DELETE FROM ClusterDiscovery @@ -220,10 +168,5 @@ func (s sqlClusterDiscoveryStore) Cleanup() store.StoreChannel { ); err != nil { result.Err = model.NewAppError("SqlClusterDiscoveryStore.Save", "Failed to save ClusterDiscovery row", nil, err.Error(), http.StatusInternalServerError) } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } diff --git a/store/sqlstore/cluster_discovery_store_test.go b/store/sqlstore/cluster_discovery_store_test.go index 35207cd562..ce361d59d1 100644 --- a/store/sqlstore/cluster_discovery_store_test.go +++ b/store/sqlstore/cluster_discovery_store_test.go @@ -9,7 +9,7 @@ import ( "time" "github.com/mattermost/mattermost-server/model" -"github.com/mattermost/mattermost-server/store" + "github.com/mattermost/mattermost-server/store" ) func TestSqlClusterDiscoveryStore(t *testing.T) { diff --git a/store/sqlstore/command_store.go b/store/sqlstore/command_store.go index 8284f889bd..d7c53e7e28 100644 --- a/store/sqlstore/command_store.go +++ b/store/sqlstore/command_store.go @@ -45,22 +45,14 @@ func (s SqlCommandStore) CreateIndexesIfNotExists() { } func (s SqlCommandStore) Save(command *model.Command) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { if len(command.Id) > 0 { result.Err = model.NewAppError("SqlCommandStore.Save", "store.sql_command.save.saving_overwrite.app_error", nil, "id="+command.Id, http.StatusBadRequest) - storeChannel <- result - close(storeChannel) return } command.PreSave() if result.Err = command.IsValid(); result.Err != nil { - storeChannel <- result - close(storeChannel) return } @@ -69,20 +61,11 @@ func (s SqlCommandStore) Save(command *model.Command) store.StoreChannel { } else { result.Data = command } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlCommandStore) Get(id string) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { var command model.Command if err := s.GetReplica().SelectOne(&command, "SELECT * FROM Commands WHERE Id = :Id AND DeleteAt = 0", map[string]interface{}{"Id": id}); err != nil { @@ -90,20 +73,11 @@ func (s SqlCommandStore) Get(id string) store.StoreChannel { } result.Data = &command - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlCommandStore) GetByTeam(teamId string) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { var commands []*model.Command if _, err := s.GetReplica().Select(&commands, "SELECT * FROM Commands WHERE TeamId = :TeamId AND DeleteAt = 0", map[string]interface{}{"TeamId": teamId}); err != nil { @@ -111,20 +85,11 @@ func (s SqlCommandStore) GetByTeam(teamId string) store.StoreChannel { } result.Data = commands - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlCommandStore) GetByTrigger(teamId string, trigger string) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { var command model.Command if err := s.GetReplica().SelectOne(&command, "SELECT * FROM Commands WHERE TeamId = :TeamId AND `Trigger` = :Trigger AND DeleteAt = 0", map[string]interface{}{"TeamId": teamId, "Trigger": trigger}); err != nil { @@ -132,74 +97,38 @@ func (s SqlCommandStore) GetByTrigger(teamId string, trigger string) store.Store } result.Data = &command - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlCommandStore) Delete(commandId string, time int64) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { _, err := s.GetMaster().Exec("Update Commands SET DeleteAt = :DeleteAt, UpdateAt = :UpdateAt WHERE Id = :Id", map[string]interface{}{"DeleteAt": time, "UpdateAt": time, "Id": commandId}) if err != nil { result.Err = model.NewAppError("SqlCommandStore.Delete", "store.sql_command.save.delete.app_error", nil, "id="+commandId+", err="+err.Error(), http.StatusInternalServerError) } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlCommandStore) PermanentDeleteByTeam(teamId string) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { _, err := s.GetMaster().Exec("DELETE FROM Commands WHERE TeamId = :TeamId", map[string]interface{}{"TeamId": teamId}) if err != nil { result.Err = model.NewAppError("SqlCommandStore.DeleteByTeam", "store.sql_command.save.delete_perm.app_error", nil, "id="+teamId+", err="+err.Error(), http.StatusInternalServerError) } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlCommandStore) PermanentDeleteByUser(userId string) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { _, err := s.GetMaster().Exec("DELETE FROM Commands WHERE CreatorId = :UserId", map[string]interface{}{"UserId": userId}) if err != nil { result.Err = model.NewAppError("SqlCommandStore.DeleteByUser", "store.sql_command.save.delete_perm.app_error", nil, "id="+userId+", err="+err.Error(), http.StatusInternalServerError) } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlCommandStore) Update(cmd *model.Command) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { cmd.UpdateAt = model.GetMillis() if _, err := s.GetMaster().Update(cmd); err != nil { @@ -207,20 +136,11 @@ func (s SqlCommandStore) Update(cmd *model.Command) store.StoreChannel { } else { result.Data = cmd } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlCommandStore) AnalyticsCommandCount(teamId string) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { query := `SELECT COUNT(*) @@ -238,10 +158,5 @@ func (s SqlCommandStore) AnalyticsCommandCount(teamId string) store.StoreChannel } else { result.Data = c } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } diff --git a/store/sqlstore/command_webhook_store.go b/store/sqlstore/command_webhook_store.go index dc1ad0732a..40fa8577c2 100644 --- a/store/sqlstore/command_webhook_store.go +++ b/store/sqlstore/command_webhook_store.go @@ -38,22 +38,14 @@ func (s SqlCommandWebhookStore) CreateIndexesIfNotExists() { } func (s SqlCommandWebhookStore) Save(webhook *model.CommandWebhook) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { if len(webhook.Id) > 0 { result.Err = model.NewAppError("SqlCommandWebhookStore.Save", "store.sql_command_webhooks.save.existing.app_error", nil, "id="+webhook.Id, http.StatusBadRequest) - storeChannel <- result - close(storeChannel) return } webhook.PreSave() if result.Err = webhook.IsValid(); result.Err != nil { - storeChannel <- result - close(storeChannel) return } @@ -62,20 +54,11 @@ func (s SqlCommandWebhookStore) Save(webhook *model.CommandWebhook) store.StoreC } else { result.Data = webhook } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlCommandWebhookStore) Get(id string) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { var webhook model.CommandWebhook exptime := model.GetMillis() - model.COMMAND_WEBHOOK_LIFETIME @@ -87,20 +70,11 @@ func (s SqlCommandWebhookStore) Get(id string) store.StoreChannel { } result.Data = &webhook - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlCommandWebhookStore) TryUse(id string, limit int) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { if sqlResult, err := s.GetMaster().Exec("UPDATE CommandWebhooks SET UseCount = UseCount + 1 WHERE Id = :Id AND UseCount < :UseLimit", map[string]interface{}{"Id": id, "UseLimit": limit}); err != nil { result.Err = model.NewAppError("SqlCommandWebhookStore.TryUse", "store.sql_command_webhooks.try_use.app_error", nil, "id="+id+", err="+err.Error(), http.StatusInternalServerError) } else if rows, _ := sqlResult.RowsAffected(); rows == 0 { @@ -108,12 +82,7 @@ func (s SqlCommandWebhookStore) TryUse(id string, limit int) store.StoreChannel } result.Data = id - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlCommandWebhookStore) Cleanup() { diff --git a/store/sqlstore/compliance_store.go b/store/sqlstore/compliance_store.go index 95da946739..3d638b1fd8 100644 --- a/store/sqlstore/compliance_store.go +++ b/store/sqlstore/compliance_store.go @@ -37,16 +37,9 @@ func (s SqlComplianceStore) CreateIndexesIfNotExists() { } func (s SqlComplianceStore) Save(compliance *model.Compliance) store.StoreChannel { - - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { compliance.PreSave() if result.Err = compliance.IsValid(); result.Err != nil { - storeChannel <- result - close(storeChannel) return } @@ -55,24 +48,12 @@ func (s SqlComplianceStore) Save(compliance *model.Compliance) store.StoreChanne } else { result.Data = compliance } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (us SqlComplianceStore) Update(compliance *model.Compliance) store.StoreChannel { - - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { if result.Err = compliance.IsValid(); result.Err != nil { - storeChannel <- result - close(storeChannel) return } @@ -81,21 +62,11 @@ func (us SqlComplianceStore) Update(compliance *model.Compliance) store.StoreCha } else { result.Data = compliance } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlComplianceStore) GetAll(offset, limit int) store.StoreChannel { - - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { query := "SELECT * FROM Compliances ORDER BY CreateAt DESC LIMIT :Limit OFFSET :Offset" var compliances model.Compliances @@ -104,21 +75,11 @@ func (s SqlComplianceStore) GetAll(offset, limit int) store.StoreChannel { } else { result.Data = compliances } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (us SqlComplianceStore) Get(id string) store.StoreChannel { - - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { if obj, err := us.GetReplica().Get(model.Compliance{}, id); err != nil { result.Err = model.NewAppError("SqlComplianceStore.Get", "store.sql_compliance.get.finding.app_error", nil, err.Error(), http.StatusInternalServerError) } else if obj == nil { @@ -126,21 +87,11 @@ func (us SqlComplianceStore) Get(id string) store.StoreChannel { } else { result.Data = obj.(*model.Compliance) } - - storeChannel <- result - close(storeChannel) - - }() - - return storeChannel + }) } func (s SqlComplianceStore) ComplianceExport(job *model.Compliance) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { props := map[string]interface{}{"StartTime": job.StartAt, "EndTime": job.EndAt} keywordQuery := "" @@ -258,10 +209,5 @@ func (s SqlComplianceStore) ComplianceExport(job *model.Compliance) store.StoreC } else { result.Data = cposts } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } diff --git a/store/sqlstore/compliance_store_test.go b/store/sqlstore/compliance_store_test.go index 7c7bfaf8fc..16d5e18b3c 100644 --- a/store/sqlstore/compliance_store_test.go +++ b/store/sqlstore/compliance_store_test.go @@ -8,7 +8,7 @@ import ( "time" "github.com/mattermost/mattermost-server/model" -"github.com/mattermost/mattermost-server/store" + "github.com/mattermost/mattermost-server/store" ) func TestSqlComplianceStore(t *testing.T) { diff --git a/store/sqlstore/emoji_store.go b/store/sqlstore/emoji_store.go index 5842af2f3b..9ef071f02c 100644 --- a/store/sqlstore/emoji_store.go +++ b/store/sqlstore/emoji_store.go @@ -49,15 +49,9 @@ func (es SqlEmojiStore) CreateIndexesIfNotExists() { } func (es SqlEmojiStore) Save(emoji *model.Emoji) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { emoji.PreSave() if result.Err = emoji.IsValid(); result.Err != nil { - storeChannel <- result - close(storeChannel) return } @@ -66,28 +60,17 @@ func (es SqlEmojiStore) Save(emoji *model.Emoji) store.StoreChannel { } else { result.Data = emoji } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (es SqlEmojiStore) Get(id string, allowFromCache bool) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { if allowFromCache { if cacheItem, ok := emojiCache.Get(id); ok { if es.metrics != nil { es.metrics.IncrementMemCacheHitCounter("Emoji") } result.Data = cacheItem.(*model.Emoji) - storeChannel <- result - close(storeChannel) return } else { if es.metrics != nil { @@ -118,20 +101,11 @@ func (es SqlEmojiStore) Get(id string, allowFromCache bool) store.StoreChannel { emojiCache.AddWithExpiresInSecs(id, emoji, EMOJI_CACHE_SEC) } } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (es SqlEmojiStore) GetByName(name string) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { var emoji *model.Emoji if err := es.GetReplica().SelectOne(&emoji, @@ -146,20 +120,11 @@ func (es SqlEmojiStore) GetByName(name string) store.StoreChannel { } else { result.Data = emoji } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (es SqlEmojiStore) GetList(offset, limit int) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { var emoji []*model.Emoji if _, err := es.GetReplica().Select(&emoji, @@ -174,20 +139,11 @@ func (es SqlEmojiStore) GetList(offset, limit int) store.StoreChannel { } else { result.Data = emoji } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (es SqlEmojiStore) Delete(id string, time int64) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { if sqlResult, err := es.GetMaster().Exec( `Update Emoji @@ -203,10 +159,5 @@ func (es SqlEmojiStore) Delete(id string, time int64) store.StoreChannel { } emojiCache.Remove(id) - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } diff --git a/store/sqlstore/emoji_store_test.go b/store/sqlstore/emoji_store_test.go index 39673a503e..9754e2b479 100644 --- a/store/sqlstore/emoji_store_test.go +++ b/store/sqlstore/emoji_store_test.go @@ -8,7 +8,7 @@ import ( "time" "github.com/mattermost/mattermost-server/model" -"github.com/mattermost/mattermost-server/store" + "github.com/mattermost/mattermost-server/store" ) func TestEmojiSaveDelete(t *testing.T) { diff --git a/store/sqlstore/file_info_store.go b/store/sqlstore/file_info_store.go index cc8b4fb2f3..18e3a2a1c3 100644 --- a/store/sqlstore/file_info_store.go +++ b/store/sqlstore/file_info_store.go @@ -58,15 +58,9 @@ func (fs SqlFileInfoStore) CreateIndexesIfNotExists() { } func (fs SqlFileInfoStore) Save(info *model.FileInfo) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { info.PreSave() if result.Err = info.IsValid(); result.Err != nil { - storeChannel <- result - close(storeChannel) return } @@ -75,20 +69,11 @@ func (fs SqlFileInfoStore) Save(info *model.FileInfo) store.StoreChannel { } else { result.Data = info } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (fs SqlFileInfoStore) Get(id string) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { info := &model.FileInfo{} if err := fs.GetReplica().SelectOne(info, @@ -107,20 +92,11 @@ func (fs SqlFileInfoStore) Get(id string) store.StoreChannel { } else { result.Data = info } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (fs SqlFileInfoStore) GetByPath(path string) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { info := &model.FileInfo{} if err := fs.GetReplica().SelectOne(info, @@ -136,12 +112,7 @@ func (fs SqlFileInfoStore) GetByPath(path string) store.StoreChannel { } else { result.Data = info } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (fs SqlFileInfoStore) InvalidateFileInfosForPostCache(postId string) { @@ -149,11 +120,7 @@ func (fs SqlFileInfoStore) InvalidateFileInfosForPostCache(postId string) { } func (fs SqlFileInfoStore) GetForPost(postId string, readFromMaster bool, allowFromCache bool) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { if allowFromCache { if cacheItem, ok := fileInfoCache.Get(postId); ok { if fs.metrics != nil { @@ -161,8 +128,6 @@ func (fs SqlFileInfoStore) GetForPost(postId string, readFromMaster bool, allowF } result.Data = cacheItem.([]*model.FileInfo) - storeChannel <- result - close(storeChannel) return } else { if fs.metrics != nil { @@ -202,20 +167,11 @@ func (fs SqlFileInfoStore) GetForPost(postId string, readFromMaster bool, allowF result.Data = infos } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (fs SqlFileInfoStore) AttachToPost(fileId, postId string) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { if _, err := fs.GetMaster().Exec( `UPDATE FileInfo @@ -227,20 +183,11 @@ func (fs SqlFileInfoStore) AttachToPost(fileId, postId string) store.StoreChanne result.Err = model.NewAppError("SqlFileInfoStore.AttachToPost", "store.sql_file_info.attach_to_post.app_error", nil, "post_id="+postId+", file_id="+fileId+", err="+err.Error(), http.StatusInternalServerError) } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (fs SqlFileInfoStore) DeleteForPost(postId string) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { if _, err := fs.GetMaster().Exec( `UPDATE FileInfo @@ -253,20 +200,11 @@ func (fs SqlFileInfoStore) DeleteForPost(postId string) store.StoreChannel { } else { result.Data = postId } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (fs SqlFileInfoStore) PermanentDelete(fileId string) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { if _, err := fs.GetMaster().Exec( `DELETE FROM FileInfo @@ -275,20 +213,11 @@ func (fs SqlFileInfoStore) PermanentDelete(fileId string) store.StoreChannel { result.Err = model.NewAppError("SqlFileInfoStore.PermanentDelete", "store.sql_file_info.permanent_delete.app_error", nil, "file_id="+fileId+", err="+err.Error(), http.StatusInternalServerError) } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlFileInfoStore) PermanentDeleteBatch(endTime int64, limit int64) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { var query string if *utils.Cfg.SqlSettings.DriverName == "postgres" { query = "DELETE from FileInfo WHERE Id = any (array (SELECT Id FROM FileInfo WHERE CreateAt < :EndTime LIMIT :Limit))" @@ -308,10 +237,5 @@ func (s SqlFileInfoStore) PermanentDeleteBatch(endTime int64, limit int64) store result.Data = rowsAffected } } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } diff --git a/store/sqlstore/file_info_store_test.go b/store/sqlstore/file_info_store_test.go index 626fe8c6a2..8ddf34e190 100644 --- a/store/sqlstore/file_info_store_test.go +++ b/store/sqlstore/file_info_store_test.go @@ -8,7 +8,7 @@ import ( "testing" "github.com/mattermost/mattermost-server/model" -"github.com/mattermost/mattermost-server/store" + "github.com/mattermost/mattermost-server/store" ) func TestFileInfoSaveGet(t *testing.T) { @@ -267,21 +267,21 @@ func TestFileInfoPermanentDeleteBatch(t *testing.T) { PostId: postId, CreatorId: model.NewId(), Path: "file.txt", - CreateAt: 1000, + CreateAt: 1000, })) store.Must(ss.FileInfo().Save(&model.FileInfo{ PostId: postId, CreatorId: model.NewId(), Path: "file.txt", - CreateAt: 1200, + CreateAt: 1200, })) store.Must(ss.FileInfo().Save(&model.FileInfo{ PostId: postId, CreatorId: model.NewId(), Path: "file.txt", - CreateAt: 2000, + CreateAt: 2000, })) if result := <-ss.FileInfo().GetForPost(postId, true, false); result.Err != nil { diff --git a/store/sqlstore/job_store.go b/store/sqlstore/job_store.go index 8cd9212179..691b096385 100644 --- a/store/sqlstore/job_store.go +++ b/store/sqlstore/job_store.go @@ -35,29 +35,17 @@ func (jss SqlJobStore) CreateIndexesIfNotExists() { } func (jss SqlJobStore) Save(job *model.Job) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} + return store.Do(func(result *store.StoreResult) { if err := jss.GetMaster().Insert(job); err != nil { result.Err = model.NewAppError("SqlJobStore.Save", "store.sql_job.save.app_error", nil, "id="+job.Id+", "+err.Error(), http.StatusInternalServerError) } else { result.Data = job } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (jss SqlJobStore) UpdateOptimistically(job *model.Job, currentStatus string) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { if sqlResult, err := jss.GetMaster().Exec( `UPDATE Jobs @@ -92,20 +80,11 @@ func (jss SqlJobStore) UpdateOptimistically(job *model.Job, currentStatus string } } } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (jss SqlJobStore) UpdateStatus(id string, status string) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { job := &model.Job{ Id: id, Status: status, @@ -121,20 +100,11 @@ func (jss SqlJobStore) UpdateStatus(id string, status string) store.StoreChannel if result.Err == nil { result.Data = job } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (jss SqlJobStore) UpdateStatusOptimistically(id string, currentStatus string, newStatus string) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { var startAtClause string if newStatus == model.JOB_STATUS_IN_PROGRESS { startAtClause = `StartAt = :StartAt,` @@ -164,20 +134,11 @@ func (jss SqlJobStore) UpdateStatusOptimistically(id string, currentStatus strin } } } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (jss SqlJobStore) Get(id string) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { var status *model.Job if err := jss.GetReplica().SelectOne(&status, @@ -195,20 +156,11 @@ func (jss SqlJobStore) Get(id string) store.StoreChannel { } else { result.Data = status } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (jss SqlJobStore) GetAllPage(offset int, limit int) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { var statuses []*model.Job if _, err := jss.GetReplica().Select(&statuses, @@ -226,20 +178,11 @@ func (jss SqlJobStore) GetAllPage(offset int, limit int) store.StoreChannel { } else { result.Data = statuses } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (jss SqlJobStore) GetAllByType(jobType string) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { var statuses []*model.Job if _, err := jss.GetReplica().Select(&statuses, @@ -255,20 +198,11 @@ func (jss SqlJobStore) GetAllByType(jobType string) store.StoreChannel { } else { result.Data = statuses } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (jss SqlJobStore) GetAllByTypePage(jobType string, offset int, limit int) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { var statuses []*model.Job if _, err := jss.GetReplica().Select(&statuses, @@ -288,20 +222,11 @@ func (jss SqlJobStore) GetAllByTypePage(jobType string, offset int, limit int) s } else { result.Data = statuses } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (jss SqlJobStore) GetAllByStatus(status string) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { var statuses []*model.Job if _, err := jss.GetReplica().Select(&statuses, @@ -317,20 +242,11 @@ func (jss SqlJobStore) GetAllByStatus(status string) store.StoreChannel { } else { result.Data = statuses } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (jss SqlJobStore) GetNewestJobByStatusAndType(status string, jobType string) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { var job *model.Job if err := jss.GetReplica().SelectOne(&job, @@ -349,20 +265,11 @@ func (jss SqlJobStore) GetNewestJobByStatusAndType(status string, jobType string } else { result.Data = job } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (jss SqlJobStore) GetCountByStatusAndType(status string, jobType string) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { if count, err := jss.GetReplica().SelectInt(`SELECT COUNT(*) FROM @@ -375,20 +282,11 @@ func (jss SqlJobStore) GetCountByStatusAndType(status string, jobType string) st } else { result.Data = count } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (jss SqlJobStore) Delete(id string) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { if _, err := jss.GetMaster().Exec( `DELETE FROM Jobs @@ -398,10 +296,5 @@ func (jss SqlJobStore) Delete(id string) store.StoreChannel { } else { result.Data = id } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } diff --git a/store/sqlstore/license_store.go b/store/sqlstore/license_store.go index 5f3e91e88e..0a1293deeb 100644 --- a/store/sqlstore/license_store.go +++ b/store/sqlstore/license_store.go @@ -30,16 +30,9 @@ func (ls SqlLicenseStore) CreateIndexesIfNotExists() { } func (ls SqlLicenseStore) Save(license *model.LicenseRecord) store.StoreChannel { - - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { license.PreSave() if result.Err = license.IsValid(); result.Err != nil { - storeChannel <- result - close(storeChannel) return } @@ -51,21 +44,11 @@ func (ls SqlLicenseStore) Save(license *model.LicenseRecord) store.StoreChannel result.Data = license } } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (ls SqlLicenseStore) Get(id string) store.StoreChannel { - - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { if obj, err := ls.GetReplica().Get(model.LicenseRecord{}, id); err != nil { result.Err = model.NewAppError("SqlLicenseStore.Get", "store.sql_license.get.app_error", nil, "license_id="+id+", "+err.Error(), http.StatusInternalServerError) } else if obj == nil { @@ -73,11 +56,5 @@ func (ls SqlLicenseStore) Get(id string) store.StoreChannel { } else { result.Data = obj.(*model.LicenseRecord) } - - storeChannel <- result - close(storeChannel) - - }() - - return storeChannel + }) } diff --git a/store/sqlstore/license_store_test.go b/store/sqlstore/license_store_test.go index 053b0ede16..99b13a423e 100644 --- a/store/sqlstore/license_store_test.go +++ b/store/sqlstore/license_store_test.go @@ -7,7 +7,7 @@ import ( "testing" "github.com/mattermost/mattermost-server/model" -"github.com/mattermost/mattermost-server/store" + "github.com/mattermost/mattermost-server/store" ) func TestLicenseStoreSave(t *testing.T) { diff --git a/store/sqlstore/oauth_store.go b/store/sqlstore/oauth_store.go index f93f478213..7644ac5dc4 100644 --- a/store/sqlstore/oauth_store.go +++ b/store/sqlstore/oauth_store.go @@ -61,23 +61,14 @@ func (as SqlOAuthStore) CreateIndexesIfNotExists() { } func (as SqlOAuthStore) SaveApp(app *model.OAuthApp) store.StoreChannel { - - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { if len(app.Id) > 0 { result.Err = model.NewAppError("SqlOAuthStore.SaveApp", "store.sql_oauth.save_app.existing.app_error", nil, "app_id="+app.Id, http.StatusBadRequest) - storeChannel <- result - close(storeChannel) return } app.PreSave() if result.Err = app.IsValid(); result.Err != nil { - storeChannel <- result - close(storeChannel) return } @@ -86,26 +77,14 @@ func (as SqlOAuthStore) SaveApp(app *model.OAuthApp) store.StoreChannel { } else { result.Data = app } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (as SqlOAuthStore) UpdateApp(app *model.OAuthApp) store.StoreChannel { - - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { app.PreUpdate() if result.Err = app.IsValid(); result.Err != nil { - storeChannel <- result - close(storeChannel) return } @@ -126,21 +105,11 @@ func (as SqlOAuthStore) UpdateApp(app *model.OAuthApp) store.StoreChannel { result.Data = [2]*model.OAuthApp{app, oldApp} } } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (as SqlOAuthStore) GetApp(id string) store.StoreChannel { - - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { if obj, err := as.GetReplica().Get(model.OAuthApp{}, id); err != nil { result.Err = model.NewAppError("SqlOAuthStore.GetApp", "store.sql_oauth.get_app.finding.app_error", nil, "app_id="+id+", "+err.Error(), http.StatusInternalServerError) } else if obj == nil { @@ -148,22 +117,11 @@ func (as SqlOAuthStore) GetApp(id string) store.StoreChannel { } else { result.Data = obj.(*model.OAuthApp) } - - storeChannel <- result - close(storeChannel) - - }() - - return storeChannel + }) } func (as SqlOAuthStore) GetAppByUser(userId string, offset, limit int) store.StoreChannel { - - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { var apps []*model.OAuthApp if _, err := as.GetReplica().Select(&apps, "SELECT * FROM OAuthApps WHERE CreatorId = :UserId LIMIT :Limit OFFSET :Offset", map[string]interface{}{"UserId": userId, "Offset": offset, "Limit": limit}); err != nil { @@ -171,21 +129,11 @@ func (as SqlOAuthStore) GetAppByUser(userId string, offset, limit int) store.Sto } result.Data = apps - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (as SqlOAuthStore) GetApps(offset, limit int) store.StoreChannel { - - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { var apps []*model.OAuthApp if _, err := as.GetReplica().Select(&apps, "SELECT * FROM OAuthApps LIMIT :Limit OFFSET :Offset", map[string]interface{}{"Offset": offset, "Limit": limit}); err != nil { @@ -193,20 +141,11 @@ func (as SqlOAuthStore) GetApps(offset, limit int) store.StoreChannel { } result.Data = apps - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (as SqlOAuthStore) GetAuthorizedApps(userId string, offset, limit int) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { var apps []*model.OAuthApp if _, err := as.GetReplica().Select(&apps, @@ -216,27 +155,18 @@ func (as SqlOAuthStore) GetAuthorizedApps(userId string, offset, limit int) stor } result.Data = apps - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (as SqlOAuthStore) DeleteApp(id string) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { // wrap in a transaction so that if one fails, everything fails transaction, err := as.GetMaster().Begin() if err != nil { result.Err = model.NewAppError("SqlOAuthStore.DeleteApp", "store.sql_oauth.delete.open_transaction.app_error", nil, err.Error(), http.StatusInternalServerError) } else { if extrasResult := as.deleteApp(transaction, id); extrasResult.Err != nil { - result = extrasResult + *result = extrasResult } if result.Err == nil { @@ -250,24 +180,12 @@ func (as SqlOAuthStore) DeleteApp(id string) store.StoreChannel { } } } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (as SqlOAuthStore) SaveAccessData(accessData *model.AccessData) store.StoreChannel { - - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { if result.Err = accessData.IsValid(); result.Err != nil { - storeChannel <- result - close(storeChannel) return } @@ -276,21 +194,11 @@ func (as SqlOAuthStore) SaveAccessData(accessData *model.AccessData) store.Store } else { result.Data = accessData } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (as SqlOAuthStore) GetAccessData(token string) store.StoreChannel { - - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { accessData := model.AccessData{} if err := as.GetReplica().SelectOne(&accessData, "SELECT * FROM OAuthAccessData WHERE Token = :Token", map[string]interface{}{"Token": token}); err != nil { @@ -298,22 +206,11 @@ func (as SqlOAuthStore) GetAccessData(token string) store.StoreChannel { } else { result.Data = &accessData } - - storeChannel <- result - close(storeChannel) - - }() - - return storeChannel + }) } func (as SqlOAuthStore) GetAccessDataByUserForApp(userId, clientId string) store.StoreChannel { - - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { var accessData []*model.AccessData if _, err := as.GetReplica().Select(&accessData, @@ -323,22 +220,11 @@ func (as SqlOAuthStore) GetAccessDataByUserForApp(userId, clientId string) store } else { result.Data = accessData } - - storeChannel <- result - close(storeChannel) - - }() - - return storeChannel + }) } func (as SqlOAuthStore) GetAccessDataByRefreshToken(token string) store.StoreChannel { - - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { accessData := model.AccessData{} if err := as.GetReplica().SelectOne(&accessData, "SELECT * FROM OAuthAccessData WHERE RefreshToken = :Token", map[string]interface{}{"Token": token}); err != nil { @@ -346,22 +232,11 @@ func (as SqlOAuthStore) GetAccessDataByRefreshToken(token string) store.StoreCha } else { result.Data = &accessData } - - storeChannel <- result - close(storeChannel) - - }() - - return storeChannel + }) } func (as SqlOAuthStore) GetPreviousAccessData(userId, clientId string) store.StoreChannel { - - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { accessData := model.AccessData{} if err := as.GetReplica().SelectOne(&accessData, "SELECT * FROM OAuthAccessData WHERE ClientId = :ClientId AND UserId = :UserId", @@ -374,24 +249,12 @@ func (as SqlOAuthStore) GetPreviousAccessData(userId, clientId string) store.Sto } else { result.Data = &accessData } - - storeChannel <- result - close(storeChannel) - - }() - - return storeChannel + }) } func (as SqlOAuthStore) UpdateAccessData(accessData *model.AccessData) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { if result.Err = accessData.IsValid(); result.Err != nil { - storeChannel <- result - close(storeChannel) return } @@ -402,42 +265,21 @@ func (as SqlOAuthStore) UpdateAccessData(accessData *model.AccessData) store.Sto } else { result.Data = accessData } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (as SqlOAuthStore) RemoveAccessData(token string) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { if _, err := as.GetMaster().Exec("DELETE FROM OAuthAccessData WHERE Token = :Token", map[string]interface{}{"Token": token}); err != nil { result.Err = model.NewAppError("SqlOAuthStore.RemoveAccessData", "store.sql_oauth.remove_access_data.app_error", nil, "err="+err.Error(), http.StatusInternalServerError) } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (as SqlOAuthStore) SaveAuthData(authData *model.AuthData) store.StoreChannel { - - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { authData.PreSave() if result.Err = authData.IsValid(); result.Err != nil { - storeChannel <- result - close(storeChannel) return } @@ -446,21 +288,11 @@ func (as SqlOAuthStore) SaveAuthData(authData *model.AuthData) store.StoreChanne } else { result.Data = authData } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (as SqlOAuthStore) GetAuthData(code string) store.StoreChannel { - - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { if obj, err := as.GetReplica().Get(model.AuthData{}, code); err != nil { result.Err = model.NewAppError("SqlOAuthStore.GetAuthData", "store.sql_oauth.get_auth_data.finding.app_error", nil, err.Error(), http.StatusInternalServerError) } else if obj == nil { @@ -468,49 +300,25 @@ func (as SqlOAuthStore) GetAuthData(code string) store.StoreChannel { } else { result.Data = obj.(*model.AuthData) } - - storeChannel <- result - close(storeChannel) - - }() - - return storeChannel + }) } func (as SqlOAuthStore) RemoveAuthData(code string) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { _, err := as.GetMaster().Exec("DELETE FROM OAuthAuthData WHERE Code = :Code", map[string]interface{}{"Code": code}) if err != nil { result.Err = model.NewAppError("SqlOAuthStore.RemoveAuthData", "store.sql_oauth.remove_auth_data.app_error", nil, "err="+err.Error(), http.StatusInternalServerError) } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (as SqlOAuthStore) PermanentDeleteAuthDataByUser(userId string) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { _, err := as.GetMaster().Exec("DELETE FROM OAuthAccessData WHERE UserId = :UserId", map[string]interface{}{"UserId": userId}) if err != nil { result.Err = model.NewAppError("SqlOAuthStore.RemoveAuthDataByUserId", "store.sql_oauth.permanent_delete_auth_data_by_user.app_error", nil, "err="+err.Error(), http.StatusInternalServerError) } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (as SqlOAuthStore) deleteApp(transaction *gorp.Transaction, clientId string) store.StoreResult { diff --git a/store/sqlstore/oauth_store_test.go b/store/sqlstore/oauth_store_test.go index 1e4aacfe5f..b79414abfd 100644 --- a/store/sqlstore/oauth_store_test.go +++ b/store/sqlstore/oauth_store_test.go @@ -7,7 +7,7 @@ import ( "testing" "github.com/mattermost/mattermost-server/model" -"github.com/mattermost/mattermost-server/store" + "github.com/mattermost/mattermost-server/store" ) func TestOAuthStoreSaveApp(t *testing.T) { diff --git a/store/sqlstore/post_store.go b/store/sqlstore/post_store.go index b3e0bdbb08..53af44ca1b 100644 --- a/store/sqlstore/post_store.go +++ b/store/sqlstore/post_store.go @@ -78,22 +78,14 @@ func (s SqlPostStore) CreateIndexesIfNotExists() { } func (s SqlPostStore) Save(post *model.Post) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { if len(post.Id) > 0 { result.Err = model.NewAppError("SqlPostStore.Save", "store.sql_post.save.existing.app_error", nil, "id="+post.Id, http.StatusBadRequest) - storeChannel <- result - close(storeChannel) return } post.PreSave() if result.Err = post.IsValid(); result.Err != nil { - storeChannel <- result - close(storeChannel) return } @@ -116,20 +108,11 @@ func (s SqlPostStore) Save(post *model.Post) store.StoreChannel { result.Data = post } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlPostStore) Update(newPost *model.Post, oldPost *model.Post) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { newPost.UpdateAt = model.GetMillis() newPost.PreCommit() @@ -140,8 +123,6 @@ func (s SqlPostStore) Update(newPost *model.Post, oldPost *model.Post) store.Sto oldPost.PreCommit() if result.Err = newPost.IsValid(); result.Err != nil { - storeChannel <- result - close(storeChannel) return } @@ -160,25 +141,14 @@ func (s SqlPostStore) Update(newPost *model.Post, oldPost *model.Post) store.Sto result.Data = newPost } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlPostStore) Overwrite(post *model.Post) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { post.UpdateAt = model.GetMillis() if result.Err = post.IsValid(); result.Err != nil { - storeChannel <- result - close(storeChannel) return } @@ -187,18 +157,11 @@ func (s SqlPostStore) Overwrite(post *model.Post) store.StoreChannel { } else { result.Data = post } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlPostStore) GetFlaggedPosts(userId string, offset int, limit int) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - go func() { - result := store.StoreResult{} + return store.Do(func(result *store.StoreResult) { pl := model.NewPostList() var posts []*model.Post @@ -212,18 +175,11 @@ func (s SqlPostStore) GetFlaggedPosts(userId string, offset int, limit int) stor } result.Data = pl - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlPostStore) GetFlaggedPostsForTeam(userId, teamId string, offset int, limit int) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - go func() { - result := store.StoreResult{} + return store.Do(func(result *store.StoreResult) { pl := model.NewPostList() var posts []*model.Post @@ -264,18 +220,11 @@ func (s SqlPostStore) GetFlaggedPostsForTeam(userId, teamId string, offset int, } result.Data = pl - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlPostStore) GetFlaggedPostsForChannel(userId, channelId string, offset int, limit int) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - go func() { - result := store.StoreResult{} + return store.Do(func(result *store.StoreResult) { pl := model.NewPostList() var posts []*model.Post @@ -300,25 +249,15 @@ func (s SqlPostStore) GetFlaggedPostsForChannel(userId, channelId string, offset } result.Data = pl - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlPostStore) Get(id string) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} + return store.Do(func(result *store.StoreResult) { pl := model.NewPostList() if len(id) == 0 { result.Err = model.NewAppError("SqlPostStore.GetPost", "store.sql_post.get.app_error", nil, "id="+id, http.StatusBadRequest) - storeChannel <- result - close(storeChannel) return } @@ -326,8 +265,6 @@ func (s SqlPostStore) Get(id string) store.StoreChannel { err := s.GetReplica().SelectOne(&post, "SELECT * FROM Posts WHERE Id = :Id AND DeleteAt = 0", map[string]interface{}{"Id": id}) if err != nil { result.Err = model.NewAppError("SqlPostStore.GetPost", "store.sql_post.get.app_error", nil, "id="+id+err.Error(), http.StatusNotFound) - storeChannel <- result - close(storeChannel) return } @@ -342,8 +279,6 @@ func (s SqlPostStore) Get(id string) store.StoreChannel { if len(rootId) == 0 { result.Err = model.NewAppError("SqlPostStore.GetPost", "store.sql_post.get.app_error", nil, "root_id="+rootId, http.StatusInternalServerError) - storeChannel <- result - close(storeChannel) return } @@ -351,8 +286,6 @@ func (s SqlPostStore) Get(id string) store.StoreChannel { _, err = s.GetReplica().Select(&posts, "SELECT * FROM Posts WHERE (Id = :Id OR RootId = :RootId) AND DeleteAt = 0", map[string]interface{}{"Id": rootId, "RootId": rootId}) if err != nil { result.Err = model.NewAppError("SqlPostStore.GetPost", "store.sql_post.get.app_error", nil, "root_id="+rootId+err.Error(), http.StatusInternalServerError) - storeChannel <- result - close(storeChannel) return } else { for _, p := range posts { @@ -361,20 +294,11 @@ func (s SqlPostStore) Get(id string) store.StoreChannel { } result.Data = pl - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlPostStore) GetSingle(id string) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { var post model.Post err := s.GetReplica().SelectOne(&post, "SELECT * FROM Posts WHERE Id = :Id AND DeleteAt = 0", map[string]interface{}{"Id": id}) if err != nil { @@ -382,12 +306,7 @@ func (s SqlPostStore) GetSingle(id string) store.StoreChannel { } result.Data = &post - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } type etagPosts struct { @@ -401,19 +320,13 @@ func (s SqlPostStore) InvalidateLastPostTimeCache(channelId string) { } func (s SqlPostStore) GetEtag(channelId string, allowFromCache bool) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { if allowFromCache { if cacheItem, ok := lastPostTimeCache.Get(channelId); ok { if s.metrics != nil { s.metrics.IncrementMemCacheHitCounter("Last Post Time") } result.Data = fmt.Sprintf("%v.%v", model.CurrentVersion, cacheItem.(int64)) - storeChannel <- result - close(storeChannel) return } else { if s.metrics != nil { @@ -435,79 +348,41 @@ func (s SqlPostStore) GetEtag(channelId string, allowFromCache bool) store.Store } lastPostTimeCache.AddWithExpiresInSecs(channelId, et.UpdateAt, LAST_POST_TIME_CACHE_SEC) - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlPostStore) Delete(postId string, time int64) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { _, err := s.GetMaster().Exec("Update Posts SET DeleteAt = :DeleteAt, UpdateAt = :UpdateAt WHERE Id = :Id OR RootId = :RootId", map[string]interface{}{"DeleteAt": time, "UpdateAt": time, "Id": postId, "RootId": postId}) if err != nil { result.Err = model.NewAppError("SqlPostStore.Delete", "store.sql_post.delete.app_error", nil, "id="+postId+", err="+err.Error(), http.StatusInternalServerError) } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlPostStore) permanentDelete(postId string) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { _, err := s.GetMaster().Exec("DELETE FROM Posts WHERE Id = :Id OR RootId = :RootId", map[string]interface{}{"Id": postId, "RootId": postId}) if err != nil { result.Err = model.NewAppError("SqlPostStore.Delete", "store.sql_post.permanent_delete.app_error", nil, "id="+postId+", err="+err.Error(), http.StatusInternalServerError) } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlPostStore) permanentDeleteAllCommentByUser(userId string) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { _, err := s.GetMaster().Exec("DELETE FROM Posts WHERE UserId = :UserId AND RootId != ''", map[string]interface{}{"UserId": userId}) if err != nil { result.Err = model.NewAppError("SqlPostStore.permanentDeleteAllCommentByUser", "store.sql_post.permanent_delete_all_comments_by_user.app_error", nil, "userId="+userId+", err="+err.Error(), http.StatusInternalServerError) } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlPostStore) PermanentDeleteByUser(userId string) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { // First attempt to delete all the comments for a user if r := <-s.permanentDeleteAllCommentByUser(userId); r.Err != nil { result.Err = r.Err - storeChannel <- result - close(storeChannel) return } @@ -521,8 +396,6 @@ func (s SqlPostStore) PermanentDeleteByUser(userId string) store.StoreChannel { _, err := s.GetMaster().Select(&ids, "SELECT Id FROM Posts WHERE UserId = :UserId LIMIT 1000", map[string]interface{}{"UserId": userId}) if err != nil { result.Err = model.NewAppError("SqlPostStore.PermanentDeleteByUser.select", "store.sql_post.permanent_delete_by_user.app_error", nil, "userId="+userId+", err="+err.Error(), http.StatusInternalServerError) - storeChannel <- result - close(storeChannel) return } else { found = false @@ -530,8 +403,6 @@ func (s SqlPostStore) PermanentDeleteByUser(userId string) store.StoreChannel { found = true if r := <-s.permanentDelete(id); r.Err != nil { result.Err = r.Err - storeChannel <- result - close(storeChannel) return } } @@ -541,46 +412,24 @@ func (s SqlPostStore) PermanentDeleteByUser(userId string) store.StoreChannel { count = count + 1 if count >= 10 { result.Err = model.NewAppError("SqlPostStore.PermanentDeleteByUser.toolarge", "store.sql_post.permanent_delete_by_user.too_many.app_error", nil, "userId="+userId, http.StatusInternalServerError) - storeChannel <- result - close(storeChannel) return } } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlPostStore) PermanentDeleteByChannel(channelId string) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { if _, err := s.GetMaster().Exec("DELETE FROM Posts WHERE ChannelId = :ChannelId", map[string]interface{}{"ChannelId": channelId}); err != nil { result.Err = model.NewAppError("SqlPostStore.PermanentDeleteByChannel", "store.sql_post.permanent_delete_by_channel.app_error", nil, "channel_id="+channelId+", "+err.Error(), http.StatusInternalServerError) } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlPostStore) GetPosts(channelId string, offset int, limit int, allowFromCache bool) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { if limit > 1000 { result.Err = model.NewAppError("SqlPostStore.GetLinearPosts", "store.sql_post.get_posts.app_error", nil, "channelId="+channelId, http.StatusBadRequest) - storeChannel <- result - close(storeChannel) return } @@ -591,8 +440,6 @@ func (s SqlPostStore) GetPosts(channelId string, offset int, limit int, allowFro } result.Data = cacheItem.(*model.PostList) - storeChannel <- result - close(storeChannel) return } else { if s.metrics != nil { @@ -635,20 +482,11 @@ func (s SqlPostStore) GetPosts(channelId string, offset int, limit int, allowFro result.Data = list } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlPostStore) GetPostsSince(channelId string, time int64, allowFromCache bool) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { if allowFromCache { // If the last post in the channel's time is less than or equal to the time we are getting posts since, // we can safely return no posts. @@ -658,8 +496,6 @@ func (s SqlPostStore) GetPostsSince(channelId string, time int64, allowFromCache } list := model.NewPostList() result.Data = list - storeChannel <- result - close(storeChannel) return } else { if s.metrics != nil { @@ -723,12 +559,7 @@ func (s SqlPostStore) GetPostsSince(channelId string, time int64, allowFromCache result.Data = list } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlPostStore) GetPostsBefore(channelId string, postId string, numPosts int, offset int) store.StoreChannel { @@ -740,11 +571,7 @@ func (s SqlPostStore) GetPostsAfter(channelId string, postId string, numPosts in } func (s SqlPostStore) getPostsAround(channelId string, postId string, numPosts int, offset int, before bool) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { var direction string var sort string if before { @@ -821,20 +648,11 @@ func (s SqlPostStore) getPostsAround(channelId string, postId string, numPosts i result.Data = list } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlPostStore) getRootPosts(channelId string, offset int, limit int) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { var posts []*model.Post _, err := s.GetReplica().Select(&posts, "SELECT * FROM Posts WHERE ChannelId = :ChannelId AND DeleteAt = 0 ORDER BY CreateAt DESC LIMIT :Limit OFFSET :Offset", map[string]interface{}{"ChannelId": channelId, "Offset": offset, "Limit": limit}) if err != nil { @@ -842,20 +660,11 @@ func (s SqlPostStore) getRootPosts(channelId string, offset int, limit int) stor } else { result.Data = posts } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlPostStore) getParentsPosts(channelId string, offset int, limit int) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { var posts []*model.Post _, err := s.GetReplica().Select(&posts, `SELECT @@ -887,12 +696,7 @@ func (s SqlPostStore) getParentsPosts(channelId string, offset int, limit int) s } else { result.Data = posts } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } var specialSearchChar = []string{ @@ -908,18 +712,12 @@ var specialSearchChar = []string{ } func (s SqlPostStore) Search(teamId string, userId string, params *model.SearchParams) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { if !*utils.Cfg.ServiceSettings.EnablePostSearch { list := model.NewPostList() result.Data = list result.Err = model.NewAppError("SqlPostStore.Search", "store.sql_post.search.disabled", nil, fmt.Sprintf("teamId=%v userId=%v params=%v", teamId, userId, params.ToJson()), http.StatusNotImplemented) - storeChannel <- result - close(storeChannel) return } @@ -933,8 +731,6 @@ func (s SqlPostStore) Search(teamId string, userId string, params *model.SearchP if terms == "" && len(params.InChannels) == 0 && len(params.FromUsers) == 0 { result.Data = []*model.Post{} - storeChannel <- result - close(storeChannel) return } @@ -1094,20 +890,11 @@ func (s SqlPostStore) Search(teamId string, userId string, params *model.SearchP list.MakeNonNil() result.Data = list - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlPostStore) AnalyticsUserCountsWithPostsByDay(teamId string) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { query := `SELECT DISTINCT DATE(FROM_UNIXTIME(Posts.CreateAt / 1000)) AS Name, @@ -1156,20 +943,11 @@ func (s SqlPostStore) AnalyticsUserCountsWithPostsByDay(teamId string) store.Sto } else { result.Data = rows } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlPostStore) AnalyticsPostCountsByDay(teamId string) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { query := `SELECT DATE(FROM_UNIXTIME(Posts.CreateAt / 1000)) AS Name, @@ -1220,20 +998,11 @@ func (s SqlPostStore) AnalyticsPostCountsByDay(teamId string) store.StoreChannel } else { result.Data = rows } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlPostStore) AnalyticsPostCount(teamId string, mustHaveFile bool, mustHaveHashtag bool) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { query := `SELECT COUNT(Posts.Id) AS Value @@ -1260,20 +1029,11 @@ func (s SqlPostStore) AnalyticsPostCount(teamId string, mustHaveFile bool, mustH } else { result.Data = v } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlPostStore) GetPostsCreatedAt(channelId string, time int64) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { query := `SELECT * FROM Posts WHERE CreateAt = :CreateAt` var posts []*model.Post @@ -1284,20 +1044,11 @@ func (s SqlPostStore) GetPostsCreatedAt(channelId string, time int64) store.Stor } else { result.Data = posts } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlPostStore) GetPostsByIds(postIds []string) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { keys := bytes.Buffer{} params := make(map[string]interface{}) for i, postId := range postIds { @@ -1317,24 +1068,15 @@ func (s SqlPostStore) GetPostsByIds(postIds []string) store.StoreChannel { if err != nil { l4g.Error(err) - result.Err = model.NewAppError("SqlPostStore.GetPostsCreatedAt", "store.sql_post.get_posts_by_ids.app_error", nil, "", http.StatusInternalServerError) + result.Err = model.NewAppError("SqlPostStore.GetPostsByIds", "store.sql_post.get_posts_by_ids.app_error", nil, "", http.StatusInternalServerError) } else { result.Data = posts } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlPostStore) GetPostsBatchForIndexing(startTime int64, limit int) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { var posts []*model.PostForIndexing _, err1 := s.GetSearchReplica().Select(&posts, `(SELECT @@ -1362,20 +1104,11 @@ func (s SqlPostStore) GetPostsBatchForIndexing(startTime int64, limit int) store } else { result.Data = posts } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlPostStore) PermanentDeleteBatch(endTime int64, limit int64) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { var query string if *utils.Cfg.SqlSettings.DriverName == "postgres" { query = "DELETE from Posts WHERE Id = any (array (SELECT Id FROM Posts WHERE CreateAt < :EndTime LIMIT :Limit))" @@ -1395,10 +1128,5 @@ func (s SqlPostStore) PermanentDeleteBatch(endTime int64, limit int64) store.Sto result.Data = rowsAffected } } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } diff --git a/store/sqlstore/post_store_test.go b/store/sqlstore/post_store_test.go index 7be37584ba..aa70f1fc7c 100644 --- a/store/sqlstore/post_store_test.go +++ b/store/sqlstore/post_store_test.go @@ -10,7 +10,7 @@ import ( "time" "github.com/mattermost/mattermost-server/model" -"github.com/mattermost/mattermost-server/store" + "github.com/mattermost/mattermost-server/store" "github.com/mattermost/mattermost-server/utils" ) diff --git a/store/sqlstore/preference_store.go b/store/sqlstore/preference_store.go index 2aab913861..6765a74f82 100644 --- a/store/sqlstore/preference_store.go +++ b/store/sqlstore/preference_store.go @@ -60,11 +60,7 @@ func (s SqlPreferenceStore) DeleteUnusedFeatures() { } func (s SqlPreferenceStore) Save(preferences *model.Preferences) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { // wrap in a transaction so that if one fails, everything fails transaction, err := s.GetMaster().Begin() if err != nil { @@ -72,7 +68,7 @@ func (s SqlPreferenceStore) Save(preferences *model.Preferences) store.StoreChan } else { for _, preference := range *preferences { if upsertResult := s.save(transaction, &preference); upsertResult.Err != nil { - result = upsertResult + *result = upsertResult break } } @@ -90,12 +86,7 @@ func (s SqlPreferenceStore) Save(preferences *model.Preferences) store.StoreChan } } } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlPreferenceStore) save(transaction *gorp.Transaction, preference *model.Preference) store.StoreResult { @@ -181,11 +172,7 @@ func (s SqlPreferenceStore) update(transaction *gorp.Transaction, preference *mo } func (s SqlPreferenceStore) Get(userId string, category string, name string) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { var preference model.Preference if err := s.GetReplica().SelectOne(&preference, @@ -201,20 +188,11 @@ func (s SqlPreferenceStore) Get(userId string, category string, name string) sto } else { result.Data = preference } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlPreferenceStore) GetCategory(userId string, category string) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { var preferences model.Preferences if _, err := s.GetReplica().Select(&preferences, @@ -229,20 +207,11 @@ func (s SqlPreferenceStore) GetCategory(userId string, category string) store.St } else { result.Data = preferences } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlPreferenceStore) GetAll(userId string) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { var preferences model.Preferences if _, err := s.GetReplica().Select(&preferences, @@ -256,37 +225,20 @@ func (s SqlPreferenceStore) GetAll(userId string) store.StoreChannel { } else { result.Data = preferences } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlPreferenceStore) PermanentDeleteByUser(userId string) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { if _, err := s.GetMaster().Exec( `DELETE FROM Preferences WHERE UserId = :UserId`, map[string]interface{}{"UserId": userId}); err != nil { result.Err = model.NewAppError("SqlPreferenceStore.Delete", "store.sql_preference.permanent_delete_by_user.app_error", nil, err.Error(), http.StatusInternalServerError) } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlPreferenceStore) IsFeatureEnabled(feature, userId string) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} + return store.Do(func(result *store.StoreResult) { if value, err := s.GetReplica().SelectStr(`SELECT value FROM @@ -299,20 +251,11 @@ func (s SqlPreferenceStore) IsFeatureEnabled(feature, userId string) store.Store } else { result.Data = value == "true" } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlPreferenceStore) Delete(userId, category, name string) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { if _, err := s.GetMaster().Exec( `DELETE FROM Preferences @@ -322,20 +265,11 @@ func (s SqlPreferenceStore) Delete(userId, category, name string) store.StoreCha AND Name = :Name`, map[string]interface{}{"UserId": userId, "Category": category, "Name": name}); err != nil { result.Err = model.NewAppError("SqlPreferenceStore.Delete", "store.sql_preference.delete.app_error", nil, err.Error(), http.StatusInternalServerError) } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlPreferenceStore) DeleteCategory(userId string, category string) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { if _, err := s.GetMaster().Exec( `DELETE FROM Preferences @@ -344,20 +278,11 @@ func (s SqlPreferenceStore) DeleteCategory(userId string, category string) store AND Category = :Category`, map[string]interface{}{"UserId": userId, "Category": category}); err != nil { result.Err = model.NewAppError("SqlPreferenceStore.DeleteCategory", "store.sql_preference.delete.app_error", nil, err.Error(), http.StatusInternalServerError) } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlPreferenceStore) DeleteCategoryAndName(category string, name string) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { if _, err := s.GetMaster().Exec( `DELETE FROM Preferences @@ -366,20 +291,11 @@ func (s SqlPreferenceStore) DeleteCategoryAndName(category string, name string) AND Category = :Category`, map[string]interface{}{"Name": name, "Category": category}); err != nil { result.Err = model.NewAppError("SqlPreferenceStore.DeleteCategoryAndName", "store.sql_preference.delete.app_error", nil, err.Error(), http.StatusInternalServerError) } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlPreferenceStore) CleanupFlagsBatch(limit int64) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { query := `DELETE FROM Preferences @@ -418,10 +334,5 @@ func (s SqlPreferenceStore) CleanupFlagsBatch(limit int64) store.StoreChannel { result.Data = rowsAffected } } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } diff --git a/store/sqlstore/preference_store_test.go b/store/sqlstore/preference_store_test.go index f1cebf379d..ff415038d9 100644 --- a/store/sqlstore/preference_store_test.go +++ b/store/sqlstore/preference_store_test.go @@ -9,7 +9,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/mattermost/mattermost-server/model" -"github.com/mattermost/mattermost-server/store" + "github.com/mattermost/mattermost-server/store" ) func TestPreferenceSave(t *testing.T) { diff --git a/store/sqlstore/reaction_store_test.go b/store/sqlstore/reaction_store_test.go index 276bcbffa0..28338307b5 100644 --- a/store/sqlstore/reaction_store_test.go +++ b/store/sqlstore/reaction_store_test.go @@ -7,7 +7,7 @@ import ( "testing" "github.com/mattermost/mattermost-server/model" -"github.com/mattermost/mattermost-server/store" + "github.com/mattermost/mattermost-server/store" ) func TestReactionSave(t *testing.T) { diff --git a/store/sqlstore/session_store.go b/store/sqlstore/session_store.go index 09193f595b..1f8799cdf8 100644 --- a/store/sqlstore/session_store.go +++ b/store/sqlstore/session_store.go @@ -42,16 +42,9 @@ func (me SqlSessionStore) CreateIndexesIfNotExists() { } func (me SqlSessionStore) Save(session *model.Session) store.StoreChannel { - - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { if len(session.Id) > 0 { result.Err = model.NewAppError("SqlSessionStore.Save", "store.sql_session.save.existing.app_error", nil, "id="+session.Id, http.StatusBadRequest) - storeChannel <- result - close(storeChannel) return } @@ -82,21 +75,11 @@ func (me SqlSessionStore) Save(session *model.Session) store.StoreChannel { } } } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (me SqlSessionStore) Get(sessionIdOrToken string) store.StoreChannel { - - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { var sessions []*model.Session if _, err := me.GetReplica().Select(&sessions, "SELECT * FROM Sessions WHERE Token = :Token OR Id = :Id LIMIT 1", map[string]interface{}{"Token": sessionIdOrToken, "Id": sessionIdOrToken}); err != nil { @@ -120,25 +103,15 @@ func (me SqlSessionStore) Get(sessionIdOrToken string) store.StoreChannel { } } } - - storeChannel <- result - close(storeChannel) - - }() - - return storeChannel + }) } func (me SqlSessionStore) GetSessions(userId string) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - + return store.Do(func(result *store.StoreResult) { if cur := <-me.CleanUpExpiredSessions(userId); cur.Err != nil { l4g.Error(utils.T("store.sql_session.get_sessions.error"), cur.Err) } - result := store.StoreResult{} var sessions []*model.Session tcs := me.Team().GetTeamsForUser(userId) @@ -164,20 +137,11 @@ func (me SqlSessionStore) GetSessions(userId string) store.StoreChannel { } } } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (me SqlSessionStore) GetSessionsWithActiveDeviceIds(userId string) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - - result := store.StoreResult{} + return store.Do(func(result *store.StoreResult) { var sessions []*model.Session if _, err := me.GetReplica().Select(&sessions, "SELECT * FROM Sessions WHERE UserId = :UserId AND ExpiresAt != 0 AND :ExpiresAt <= ExpiresAt AND DeviceId != ''", map[string]interface{}{"UserId": userId, "ExpiresAt": model.GetMillis()}); err != nil { @@ -186,148 +150,78 @@ func (me SqlSessionStore) GetSessionsWithActiveDeviceIds(userId string) store.St result.Data = sessions } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (me SqlSessionStore) Remove(sessionIdOrToken string) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { _, err := me.GetMaster().Exec("DELETE FROM Sessions WHERE Id = :Id Or Token = :Token", map[string]interface{}{"Id": sessionIdOrToken, "Token": sessionIdOrToken}) if err != nil { result.Err = model.NewAppError("SqlSessionStore.RemoveSession", "store.sql_session.remove.app_error", nil, "id="+sessionIdOrToken+", err="+err.Error(), http.StatusInternalServerError) } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (me SqlSessionStore) RemoveAllSessions() store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { _, err := me.GetMaster().Exec("DELETE FROM Sessions") if err != nil { result.Err = model.NewAppError("SqlSessionStore.RemoveAllSessions", "store.sql_session.remove_all_sessions_for_team.app_error", nil, err.Error(), http.StatusInternalServerError) } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (me SqlSessionStore) PermanentDeleteSessionsByUser(userId string) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { _, err := me.GetMaster().Exec("DELETE FROM Sessions WHERE UserId = :UserId", map[string]interface{}{"UserId": userId}) if err != nil { result.Err = model.NewAppError("SqlSessionStore.RemoveAllSessionsForUser", "store.sql_session.permanent_delete_sessions_by_user.app_error", nil, "id="+userId+", err="+err.Error(), http.StatusInternalServerError) } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (me SqlSessionStore) CleanUpExpiredSessions(userId string) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { if _, err := me.GetMaster().Exec("DELETE FROM Sessions WHERE UserId = :UserId AND ExpiresAt != 0 AND :ExpiresAt > ExpiresAt", map[string]interface{}{"UserId": userId, "ExpiresAt": model.GetMillis()}); err != nil { result.Err = model.NewAppError("SqlSessionStore.CleanUpExpiredSessions", "store.sql_session.cleanup_expired_sessions.app_error", nil, err.Error(), http.StatusInternalServerError) } else { result.Data = userId } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (me SqlSessionStore) UpdateLastActivityAt(sessionId string, time int64) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { if _, err := me.GetMaster().Exec("UPDATE Sessions SET LastActivityAt = :LastActivityAt WHERE Id = :Id", map[string]interface{}{"LastActivityAt": time, "Id": sessionId}); err != nil { result.Err = model.NewAppError("SqlSessionStore.UpdateLastActivityAt", "store.sql_session.update_last_activity.app_error", nil, "sessionId="+sessionId, http.StatusInternalServerError) } else { result.Data = sessionId } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (me SqlSessionStore) UpdateRoles(userId, roles string) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} + return store.Do(func(result *store.StoreResult) { if _, err := me.GetMaster().Exec("UPDATE Sessions SET Roles = :Roles WHERE UserId = :UserId", map[string]interface{}{"Roles": roles, "UserId": userId}); err != nil { result.Err = model.NewAppError("SqlSessionStore.UpdateRoles", "store.sql_session.update_roles.app_error", nil, "userId="+userId, http.StatusInternalServerError) } else { result.Data = userId } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (me SqlSessionStore) UpdateDeviceId(id string, deviceId string, expiresAt int64) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} + return store.Do(func(result *store.StoreResult) { if _, err := me.GetMaster().Exec("UPDATE Sessions SET DeviceId = :DeviceId, ExpiresAt = :ExpiresAt WHERE Id = :Id", map[string]interface{}{"DeviceId": deviceId, "Id": id, "ExpiresAt": expiresAt}); err != nil { result.Err = model.NewAppError("SqlSessionStore.UpdateDeviceId", "store.sql_session.update_device_id.app_error", nil, err.Error(), http.StatusInternalServerError) } else { result.Data = deviceId } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (me SqlSessionStore) AnalyticsSessionCount() store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { query := `SELECT COUNT(*) @@ -340,10 +234,5 @@ func (me SqlSessionStore) AnalyticsSessionCount() store.StoreChannel { } else { result.Data = c } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } diff --git a/store/sqlstore/session_store_test.go b/store/sqlstore/session_store_test.go index ab6ffec955..1eed17b517 100644 --- a/store/sqlstore/session_store_test.go +++ b/store/sqlstore/session_store_test.go @@ -7,7 +7,7 @@ import ( "testing" "github.com/mattermost/mattermost-server/model" -"github.com/mattermost/mattermost-server/store" + "github.com/mattermost/mattermost-server/store" ) func TestSessionStoreSave(t *testing.T) { diff --git a/store/sqlstore/status_store.go b/store/sqlstore/status_store.go index 43dab0c34d..94e324c11f 100644 --- a/store/sqlstore/status_store.go +++ b/store/sqlstore/status_store.go @@ -40,11 +40,7 @@ func (s SqlStatusStore) CreateIndexesIfNotExists() { } func (s SqlStatusStore) SaveOrUpdate(status *model.Status) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { if err := s.GetReplica().SelectOne(&model.Status{}, "SELECT * FROM Status WHERE UserId = :UserId", map[string]interface{}{"UserId": status.UserId}); err == nil { if _, err := s.GetMaster().Update(status); err != nil { result.Err = model.NewAppError("SqlStatusStore.SaveOrUpdate", "store.sql_status.update.app_error", nil, err.Error(), http.StatusInternalServerError) @@ -56,20 +52,11 @@ func (s SqlStatusStore) SaveOrUpdate(status *model.Status) store.StoreChannel { } } } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlStatusStore) Get(userId string) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { var status model.Status if err := s.GetReplica().SelectOne(&status, @@ -87,20 +74,11 @@ func (s SqlStatusStore) Get(userId string) store.StoreChannel { } else { result.Data = &status } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlStatusStore) GetByIds(userIds []string) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { props := make(map[string]interface{}) idQuery := "" @@ -119,60 +97,33 @@ func (s SqlStatusStore) GetByIds(userIds []string) store.StoreChannel { } else { result.Data = statuses } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlStatusStore) GetOnlineAway() store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { var statuses []*model.Status if _, err := s.GetReplica().Select(&statuses, "SELECT * FROM Status WHERE Status = :Online OR Status = :Away LIMIT 300", map[string]interface{}{"Online": model.STATUS_ONLINE, "Away": model.STATUS_AWAY}); err != nil { result.Err = model.NewAppError("SqlStatusStore.GetOnlineAway", "store.sql_status.get_online_away.app_error", nil, err.Error(), http.StatusInternalServerError) } else { result.Data = statuses } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlStatusStore) GetOnline() store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { var statuses []*model.Status if _, err := s.GetReplica().Select(&statuses, "SELECT * FROM Status WHERE Status = :Online", map[string]interface{}{"Online": model.STATUS_ONLINE}); err != nil { result.Err = model.NewAppError("SqlStatusStore.GetOnline", "store.sql_status.get_online.app_error", nil, err.Error(), http.StatusInternalServerError) } else { result.Data = statuses } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlStatusStore) GetAllFromTeam(teamId string) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { var statuses []*model.Status if _, err := s.GetReplica().Select(&statuses, `SELECT s.* FROM Status AS s INNER JOIN @@ -181,37 +132,19 @@ func (s SqlStatusStore) GetAllFromTeam(teamId string) store.StoreChannel { } else { result.Data = statuses } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlStatusStore) ResetAll() store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { if _, err := s.GetMaster().Exec("UPDATE Status SET Status = :Status WHERE Manual = false", map[string]interface{}{"Status": model.STATUS_OFFLINE}); err != nil { result.Err = model.NewAppError("SqlStatusStore.ResetAll", "store.sql_status.reset_all.app_error", nil, "", http.StatusInternalServerError) } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlStatusStore) GetTotalActiveUsersCount() store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { time := model.GetMillis() - (1000 * 60 * 60 * 24) if count, err := s.GetReplica().SelectInt("SELECT COUNT(UserId) FROM Status WHERE LastActivityAt > :Time", map[string]interface{}{"Time": time}); err != nil { @@ -219,27 +152,13 @@ func (s SqlStatusStore) GetTotalActiveUsersCount() store.StoreChannel { } else { result.Data = count } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlStatusStore) UpdateLastActivityAt(userId string, lastActivityAt int64) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { if _, err := s.GetMaster().Exec("UPDATE Status SET LastActivityAt = :Time WHERE UserId = :UserId", map[string]interface{}{"UserId": userId, "Time": lastActivityAt}); err != nil { result.Err = model.NewAppError("SqlStatusStore.UpdateLastActivityAt", "store.sql_status.update_last_activity_at.app_error", nil, "", http.StatusInternalServerError) } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } diff --git a/store/sqlstore/status_store_test.go b/store/sqlstore/status_store_test.go index 3f3a99837f..92374ff7a7 100644 --- a/store/sqlstore/status_store_test.go +++ b/store/sqlstore/status_store_test.go @@ -7,7 +7,7 @@ import ( "testing" "github.com/mattermost/mattermost-server/model" -"github.com/mattermost/mattermost-server/store" + "github.com/mattermost/mattermost-server/store" ) func TestSqlStatusStore(t *testing.T) { diff --git a/store/sqlstore/system_store.go b/store/sqlstore/system_store.go index 8d863701ad..496ff2ced5 100644 --- a/store/sqlstore/system_store.go +++ b/store/sqlstore/system_store.go @@ -30,30 +30,15 @@ func (s SqlSystemStore) CreateIndexesIfNotExists() { } func (s SqlSystemStore) Save(system *model.System) store.StoreChannel { - - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { if err := s.GetMaster().Insert(system); err != nil { result.Err = model.NewAppError("SqlSystemStore.Save", "store.sql_system.save.app_error", nil, err.Error(), http.StatusInternalServerError) } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlSystemStore) SaveOrUpdate(system *model.System) store.StoreChannel { - - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { if err := s.GetReplica().SelectOne(&model.System{}, "SELECT * FROM Systems WHERE Name = :Name", map[string]interface{}{"Name": system.Name}); err == nil { if _, err := s.GetMaster().Update(system); err != nil { result.Err = model.NewAppError("SqlSystemStore.SaveOrUpdate", "store.sql_system.update.app_error", nil, "", http.StatusInternalServerError) @@ -63,39 +48,19 @@ func (s SqlSystemStore) SaveOrUpdate(system *model.System) store.StoreChannel { result.Err = model.NewAppError("SqlSystemStore.SaveOrUpdate", "store.sql_system.save.app_error", nil, "", http.StatusInternalServerError) } } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlSystemStore) Update(system *model.System) store.StoreChannel { - - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { if _, err := s.GetMaster().Update(system); err != nil { result.Err = model.NewAppError("SqlSystemStore.Update", "store.sql_system.update.app_error", nil, "", http.StatusInternalServerError) } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlSystemStore) Get() store.StoreChannel { - - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { var systems []model.System props := make(model.StringMap) if _, err := s.GetReplica().Select(&systems, "SELECT * FROM Systems"); err != nil { @@ -107,31 +72,16 @@ func (s SqlSystemStore) Get() store.StoreChannel { result.Data = props } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlSystemStore) GetByName(name string) store.StoreChannel { - - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { var system model.System if err := s.GetReplica().SelectOne(&system, "SELECT * FROM Systems WHERE Name = :Name", map[string]interface{}{"Name": name}); err != nil { result.Err = model.NewAppError("SqlSystemStore.GetByName", "store.sql_system.get_by_name.app_error", nil, "", http.StatusInternalServerError) } result.Data = &system - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } diff --git a/store/sqlstore/system_store_test.go b/store/sqlstore/system_store_test.go index 752a4daf4a..3a0b593d95 100644 --- a/store/sqlstore/system_store_test.go +++ b/store/sqlstore/system_store_test.go @@ -7,7 +7,7 @@ import ( "testing" "github.com/mattermost/mattermost-server/model" -"github.com/mattermost/mattermost-server/store" + "github.com/mattermost/mattermost-server/store" ) func TestSqlSystemStore(t *testing.T) { diff --git a/store/sqlstore/team_store.go b/store/sqlstore/team_store.go index 1b899da469..c819ec61a7 100644 --- a/store/sqlstore/team_store.go +++ b/store/sqlstore/team_store.go @@ -58,24 +58,16 @@ func (s SqlTeamStore) CreateIndexesIfNotExists() { } func (s SqlTeamStore) Save(team *model.Team) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { if len(team.Id) > 0 { result.Err = model.NewAppError("SqlTeamStore.Save", "store.sql_team.save.existing.app_error", nil, "id="+team.Id, http.StatusBadRequest) - storeChannel <- result - close(storeChannel) return } team.PreSave() if result.Err = team.IsValid(); result.Err != nil { - storeChannel <- result - close(storeChannel) return } @@ -88,26 +80,14 @@ func (s SqlTeamStore) Save(team *model.Team) store.StoreChannel { } else { result.Data = team } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlTeamStore) Update(team *model.Team) store.StoreChannel { - - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { team.PreUpdate() if result.Err = team.IsValid(); result.Err != nil { - storeChannel <- result - close(storeChannel) return } @@ -129,40 +109,21 @@ func (s SqlTeamStore) Update(team *model.Team) store.StoreChannel { result.Data = team } } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlTeamStore) UpdateDisplayName(name string, teamId string) store.StoreChannel { - - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { if _, err := s.GetMaster().Exec("UPDATE Teams SET DisplayName = :Name WHERE Id = :Id", map[string]interface{}{"Name": name, "Id": teamId}); err != nil { result.Err = model.NewAppError("SqlTeamStore.UpdateName", "store.sql_team.update_display_name.app_error", nil, "team_id="+teamId, http.StatusInternalServerError) } else { result.Data = teamId } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlTeamStore) Get(id string) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { if obj, err := s.GetReplica().Get(model.Team{}, id); err != nil { result.Err = model.NewAppError("SqlTeamStore.Get", "store.sql_team.get.finding.app_error", nil, "id="+id+", "+err.Error(), http.StatusInternalServerError) } else if obj == nil { @@ -175,20 +136,11 @@ func (s SqlTeamStore) Get(id string) store.StoreChannel { result.Data = team } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlTeamStore) GetByInviteId(inviteId string) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { team := model.Team{} if err := s.GetReplica().SelectOne(&team, "SELECT * FROM Teams WHERE Id = :InviteId OR InviteId = :InviteId", map[string]interface{}{"InviteId": inviteId}); err != nil { @@ -204,20 +156,11 @@ func (s SqlTeamStore) GetByInviteId(inviteId string) store.StoreChannel { } result.Data = &team - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlTeamStore) GetByName(name string) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { team := model.Team{} if err := s.GetReplica().SelectOne(&team, "SELECT * FROM Teams WHERE Name = :Name", map[string]interface{}{"Name": name}); err != nil { @@ -229,20 +172,11 @@ func (s SqlTeamStore) GetByName(name string) store.StoreChannel { } result.Data = &team - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlTeamStore) SearchByName(name string) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { var teams []*model.Team if _, err := s.GetReplica().Select(&teams, "SELECT * FROM Teams WHERE Name LIKE :Name", map[string]interface{}{"Name": name + "%"}); err != nil { @@ -250,20 +184,11 @@ func (s SqlTeamStore) SearchByName(name string) store.StoreChannel { } result.Data = teams - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlTeamStore) SearchAll(term string) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { var teams []*model.Team if _, err := s.GetReplica().Select(&teams, "SELECT * FROM Teams WHERE Name LIKE :Term OR DisplayName LIKE :Term", map[string]interface{}{"Term": term + "%"}); err != nil { @@ -271,20 +196,11 @@ func (s SqlTeamStore) SearchAll(term string) store.StoreChannel { } result.Data = teams - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlTeamStore) SearchOpen(term string) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { var teams []*model.Team if _, err := s.GetReplica().Select(&teams, "SELECT * FROM Teams WHERE Type = 'O' AND AllowOpenInvite = true AND (Name LIKE :Term OR DisplayName LIKE :Term)", map[string]interface{}{"Term": term + "%"}); err != nil { @@ -292,20 +208,11 @@ func (s SqlTeamStore) SearchOpen(term string) store.StoreChannel { } result.Data = teams - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlTeamStore) GetAll() store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { var data []*model.Team if _, err := s.GetReplica().Select(&data, "SELECT * FROM Teams"); err != nil { result.Err = model.NewAppError("SqlTeamStore.GetAllTeams", "store.sql_team.get_all.app_error", nil, err.Error(), http.StatusInternalServerError) @@ -318,20 +225,11 @@ func (s SqlTeamStore) GetAll() store.StoreChannel { } result.Data = data - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlTeamStore) GetAllPage(offset int, limit int) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { var data []*model.Team if _, err := s.GetReplica().Select(&data, "SELECT * FROM Teams LIMIT :Limit OFFSET :Offset", map[string]interface{}{"Offset": offset, "Limit": limit}); err != nil { result.Err = model.NewAppError("SqlTeamStore.GetAllTeams", "store.sql_team.get_all.app_error", nil, err.Error(), http.StatusInternalServerError) @@ -344,20 +242,11 @@ func (s SqlTeamStore) GetAllPage(offset int, limit int) store.StoreChannel { } result.Data = data - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlTeamStore) GetTeamsByUserId(userId string) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { var data []*model.Team if _, err := s.GetReplica().Select(&data, "SELECT Teams.* FROM Teams, TeamMembers WHERE TeamMembers.TeamId = Teams.Id AND TeamMembers.UserId = :UserId AND TeamMembers.DeleteAt = 0 AND Teams.DeleteAt = 0", map[string]interface{}{"UserId": userId}); err != nil { result.Err = model.NewAppError("SqlTeamStore.GetTeamsByUserId", "store.sql_team.get_all.app_error", nil, err.Error(), http.StatusInternalServerError) @@ -370,20 +259,11 @@ func (s SqlTeamStore) GetTeamsByUserId(userId string) store.StoreChannel { } result.Data = data - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlTeamStore) GetAllTeamListing() store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { query := "SELECT * FROM Teams WHERE AllowOpenInvite = 1" if *utils.Cfg.SqlSettings.DriverName == model.DATABASE_DRIVER_POSTGRES { @@ -402,20 +282,11 @@ func (s SqlTeamStore) GetAllTeamListing() store.StoreChannel { } result.Data = data - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlTeamStore) GetAllTeamPageListing(offset int, limit int) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { query := "SELECT * FROM Teams WHERE AllowOpenInvite = 1 LIMIT :Limit OFFSET :Offset" if *utils.Cfg.SqlSettings.DriverName == model.DATABASE_DRIVER_POSTGRES { @@ -434,59 +305,30 @@ func (s SqlTeamStore) GetAllTeamPageListing(offset int, limit int) store.StoreCh } result.Data = data - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlTeamStore) PermanentDelete(teamId string) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { if _, err := s.GetMaster().Exec("DELETE FROM Teams WHERE Id = :TeamId", map[string]interface{}{"TeamId": teamId}); err != nil { result.Err = model.NewAppError("SqlTeamStore.Delete", "store.sql_team.permanent_delete.app_error", nil, "teamId="+teamId+", "+err.Error(), http.StatusInternalServerError) } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlTeamStore) AnalyticsTeamCount() store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { if c, err := s.GetReplica().SelectInt("SELECT COUNT(*) FROM Teams WHERE DeleteAt = 0", map[string]interface{}{}); err != nil { result.Err = model.NewAppError("SqlTeamStore.AnalyticsTeamCount", "store.sql_team.analytics_team_count.app_error", nil, err.Error(), http.StatusInternalServerError) } else { result.Data = c } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlTeamStore) SaveMember(member *model.TeamMember) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { if result.Err = member.IsValid(); result.Err != nil { - storeChannel <- result - close(storeChannel) return } @@ -504,13 +346,9 @@ func (s SqlTeamStore) SaveMember(member *model.TeamMember) store.StoreChannel { AND TeamMembers.DeleteAt = 0 AND Users.DeleteAt = 0`, map[string]interface{}{"TeamId": member.TeamId}); err != nil { result.Err = model.NewAppError("SqlUserStore.Save", "store.sql_user.save.member_count.app_error", nil, "teamId="+member.TeamId+", "+err.Error(), http.StatusInternalServerError) - storeChannel <- result - close(storeChannel) return } else if int(count) >= *utils.Cfg.TeamSettings.MaxUsersPerTeam { result.Err = model.NewAppError("SqlUserStore.Save", "store.sql_user.save.max_accounts.app_error", nil, "teamId="+member.TeamId, http.StatusBadRequest) - storeChannel <- result - close(storeChannel) return } @@ -523,25 +361,14 @@ func (s SqlTeamStore) SaveMember(member *model.TeamMember) store.StoreChannel { } else { result.Data = member } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlTeamStore) UpdateMember(member *model.TeamMember) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { member.PreUpdate() if result.Err = member.IsValid(); result.Err != nil { - storeChannel <- result - close(storeChannel) return } @@ -550,20 +377,11 @@ func (s SqlTeamStore) UpdateMember(member *model.TeamMember) store.StoreChannel } else { result.Data = member } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlTeamStore) GetMember(teamId string, userId string) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { var member model.TeamMember err := s.GetReplica().SelectOne(&member, "SELECT * FROM TeamMembers WHERE TeamId = :TeamId AND UserId = :UserId", map[string]interface{}{"TeamId": teamId, "UserId": userId}) if err != nil { @@ -575,20 +393,11 @@ func (s SqlTeamStore) GetMember(teamId string, userId string) store.StoreChannel } else { result.Data = &member } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlTeamStore) GetMembers(teamId string, offset int, limit int) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { var members []*model.TeamMember _, err := s.GetReplica().Select(&members, "SELECT * FROM TeamMembers WHERE TeamId = :TeamId AND DeleteAt = 0 LIMIT :Limit OFFSET :Offset", map[string]interface{}{"TeamId": teamId, "Offset": offset, "Limit": limit}) if err != nil { @@ -596,20 +405,11 @@ func (s SqlTeamStore) GetMembers(teamId string, offset int, limit int) store.Sto } else { result.Data = members } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlTeamStore) GetTotalMemberCount(teamId string) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { count, err := s.GetReplica().SelectInt(` SELECT count(*) @@ -625,20 +425,11 @@ func (s SqlTeamStore) GetTotalMemberCount(teamId string) store.StoreChannel { } else { result.Data = count } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlTeamStore) GetActiveMemberCount(teamId string) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { count, err := s.GetReplica().SelectInt(` SELECT count(*) @@ -655,20 +446,11 @@ func (s SqlTeamStore) GetActiveMemberCount(teamId string) store.StoreChannel { } else { result.Data = count } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlTeamStore) GetMembersByIds(teamId string, userIds []string) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { var members []*model.TeamMember props := make(map[string]interface{}) idQuery := "" @@ -689,20 +471,11 @@ func (s SqlTeamStore) GetMembersByIds(teamId string, userIds []string) store.Sto } else { result.Data = members } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlTeamStore) GetTeamsForUser(userId string) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { var members []*model.TeamMember _, err := s.GetReplica().Select(&members, "SELECT * FROM TeamMembers WHERE UserId = :UserId", map[string]interface{}{"UserId": userId}) if err != nil { @@ -710,20 +483,11 @@ func (s SqlTeamStore) GetTeamsForUser(userId string) store.StoreChannel { } else { result.Data = members } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlTeamStore) GetChannelUnreadsForAllTeams(excludeTeamId, userId string) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { var data []*model.ChannelUnread _, err := s.GetReplica().Select(&data, `SELECT @@ -742,20 +506,11 @@ func (s SqlTeamStore) GetChannelUnreadsForAllTeams(excludeTeamId, userId string) } else { result.Data = data } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlTeamStore) GetChannelUnreadsForTeam(teamId, userId string) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { var data []*model.ChannelUnread _, err := s.GetReplica().Select(&data, `SELECT @@ -774,64 +529,32 @@ func (s SqlTeamStore) GetChannelUnreadsForTeam(teamId, userId string) store.Stor } else { result.Data = data } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlTeamStore) RemoveMember(teamId string, userId string) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { _, err := s.GetMaster().Exec("DELETE FROM TeamMembers WHERE TeamId = :TeamId AND UserId = :UserId", map[string]interface{}{"TeamId": teamId, "UserId": userId}) if err != nil { result.Err = model.NewAppError("SqlChannelStore.RemoveMember", "store.sql_team.remove_member.app_error", nil, "team_id="+teamId+", user_id="+userId+", "+err.Error(), http.StatusInternalServerError) } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlTeamStore) RemoveAllMembersByTeam(teamId string) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { _, err := s.GetMaster().Exec("DELETE FROM TeamMembers WHERE TeamId = :TeamId", map[string]interface{}{"TeamId": teamId}) if err != nil { result.Err = model.NewAppError("SqlChannelStore.RemoveMember", "store.sql_team.remove_member.app_error", nil, "team_id="+teamId+", "+err.Error(), http.StatusInternalServerError) } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlTeamStore) RemoveAllMembersByUser(userId string) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { _, err := s.GetMaster().Exec("DELETE FROM TeamMembers WHERE UserId = :UserId", map[string]interface{}{"UserId": userId}) if err != nil { result.Err = model.NewAppError("SqlChannelStore.RemoveMember", "store.sql_team.remove_member.app_error", nil, "user_id="+userId+", "+err.Error(), http.StatusInternalServerError) } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } diff --git a/store/sqlstore/team_store_test.go b/store/sqlstore/team_store_test.go index 0cfe483f7d..9ba9da97a3 100644 --- a/store/sqlstore/team_store_test.go +++ b/store/sqlstore/team_store_test.go @@ -8,7 +8,7 @@ import ( "time" "github.com/mattermost/mattermost-server/model" -"github.com/mattermost/mattermost-server/store" + "github.com/mattermost/mattermost-server/store" "github.com/mattermost/mattermost-server/utils" ) diff --git a/store/sqlstore/tokens_store.go b/store/sqlstore/tokens_store.go index 31e39f1fe1..ccb58cef1b 100644 --- a/store/sqlstore/tokens_store.go +++ b/store/sqlstore/tokens_store.go @@ -34,54 +34,27 @@ func (s SqlTokenStore) CreateIndexesIfNotExists() { } func (s SqlTokenStore) Save(token *model.Token) store.StoreChannel { - - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { if result.Err = token.IsValid(); result.Err != nil { - storeChannel <- result - close(storeChannel) return } if err := s.GetMaster().Insert(token); err != nil { result.Err = model.NewAppError("SqlTokenStore.Save", "store.sql_recover.save.app_error", nil, "", http.StatusInternalServerError) } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlTokenStore) Delete(token string) store.StoreChannel { - - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { if _, err := s.GetMaster().Exec("DELETE FROM Tokens WHERE Token = :Token", map[string]interface{}{"Token": token}); err != nil { result.Err = model.NewAppError("SqlTokenStore.Delete", "store.sql_recover.delete.app_error", nil, "", http.StatusInternalServerError) } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlTokenStore) GetByToken(tokenString string) store.StoreChannel { - - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { token := model.Token{} if err := s.GetReplica().SelectOne(&token, "SELECT * FROM Tokens WHERE Token = :Token", map[string]interface{}{"Token": tokenString}); err != nil { @@ -93,12 +66,7 @@ func (s SqlTokenStore) GetByToken(tokenString string) store.StoreChannel { } result.Data = &token - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlTokenStore) Cleanup() { diff --git a/store/sqlstore/upgrade.go b/store/sqlstore/upgrade.go index 64d5b07630..657cc31e6a 100644 --- a/store/sqlstore/upgrade.go +++ b/store/sqlstore/upgrade.go @@ -15,6 +15,7 @@ import ( ) const ( + VERSION_4_4_0 = "4.4.0" VERSION_4_3_0 = "4.3.0" VERSION_4_2_0 = "4.2.0" VERSION_4_1_0 = "4.1.0" @@ -56,6 +57,7 @@ func UpgradeDatabase(sqlStore SqlStore) { UpgradeDatabaseToVersion41(sqlStore) UpgradeDatabaseToVersion42(sqlStore) UpgradeDatabaseToVersion43(sqlStore) + UpgradeDatabaseToVersion44(sqlStore) // If the SchemaVersion is empty this this is the first time it has ran // so lets set it to the current version. @@ -308,3 +310,10 @@ func UpgradeDatabaseToVersion43(sqlStore SqlStore) { saveSchemaVersion(sqlStore, VERSION_4_3_0) } } + +func UpgradeDatabaseToVersion44(sqlStore SqlStore) { + if shouldPerformUpgrade(sqlStore, VERSION_4_3_0, VERSION_4_4_0) { + // TODO: Uncomment following when version 4.4.0 is released + //saveSchemaVersion(sqlStore, VERSION_4_4_0) + } +} diff --git a/store/sqlstore/user_access_token_store.go b/store/sqlstore/user_access_token_store.go index 5186ead41e..558b01cd6f 100644 --- a/store/sqlstore/user_access_token_store.go +++ b/store/sqlstore/user_access_token_store.go @@ -37,17 +37,10 @@ func (s SqlUserAccessTokenStore) CreateIndexesIfNotExists() { } func (s SqlUserAccessTokenStore) Save(token *model.UserAccessToken) store.StoreChannel { - - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { token.PreSave() if result.Err = token.IsValid(); result.Err != nil { - storeChannel <- result - close(storeChannel) return } @@ -56,27 +49,17 @@ func (s SqlUserAccessTokenStore) Save(token *model.UserAccessToken) store.StoreC } else { result.Data = token } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlUserAccessTokenStore) Delete(tokenId string) store.StoreChannel { - - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { transaction, err := s.GetMaster().Begin() if err != nil { result.Err = model.NewAppError("SqlUserAccessTokenStore.Delete", "store.sql_user_access_token.delete.app_error", nil, err.Error(), http.StatusInternalServerError) } else { if extrasResult := s.deleteSessionsAndTokensById(transaction, tokenId); extrasResult.Err != nil { - result = extrasResult + *result = extrasResult } if result.Err == nil { @@ -90,12 +73,7 @@ func (s SqlUserAccessTokenStore) Delete(tokenId string) store.StoreChannel { } } } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlUserAccessTokenStore) deleteSessionsAndTokensById(transaction *gorp.Transaction, tokenId string) store.StoreResult { @@ -127,18 +105,13 @@ func (s SqlUserAccessTokenStore) deleteTokensById(transaction *gorp.Transaction, } func (s SqlUserAccessTokenStore) DeleteAllForUser(userId string) store.StoreChannel { - - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { transaction, err := s.GetMaster().Begin() if err != nil { result.Err = model.NewAppError("SqlUserAccessTokenStore.DeleteAllForUser", "store.sql_user_access_token.delete.app_error", nil, err.Error(), http.StatusInternalServerError) } else { if extrasResult := s.deleteSessionsandTokensByUser(transaction, userId); extrasResult.Err != nil { - result = extrasResult + *result = extrasResult } if result.Err == nil { @@ -152,12 +125,7 @@ func (s SqlUserAccessTokenStore) DeleteAllForUser(userId string) store.StoreChan } } } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlUserAccessTokenStore) deleteSessionsandTokensByUser(transaction *gorp.Transaction, userId string) store.StoreResult { @@ -189,12 +157,7 @@ func (s SqlUserAccessTokenStore) deleteTokensByUser(transaction *gorp.Transactio } func (s SqlUserAccessTokenStore) Get(tokenId string) store.StoreChannel { - - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { token := model.UserAccessToken{} if err := s.GetReplica().SelectOne(&token, "SELECT * FROM UserAccessTokens WHERE Id = :Id", map[string]interface{}{"Id": tokenId}); err != nil { @@ -206,21 +169,11 @@ func (s SqlUserAccessTokenStore) Get(tokenId string) store.StoreChannel { } result.Data = &token - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlUserAccessTokenStore) GetByToken(tokenString string) store.StoreChannel { - - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { token := model.UserAccessToken{} if err := s.GetReplica().SelectOne(&token, "SELECT * FROM UserAccessTokens WHERE Token = :Token", map[string]interface{}{"Token": tokenString}); err != nil { @@ -232,21 +185,11 @@ func (s SqlUserAccessTokenStore) GetByToken(tokenString string) store.StoreChann } result.Data = &token - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlUserAccessTokenStore) GetByUser(userId string, offset, limit int) store.StoreChannel { - - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { tokens := []*model.UserAccessToken{} if _, err := s.GetReplica().Select(&tokens, "SELECT * FROM UserAccessTokens WHERE UserId = :UserId LIMIT :Limit OFFSET :Offset", map[string]interface{}{"UserId": userId, "Offset": offset, "Limit": limit}); err != nil { @@ -254,10 +197,5 @@ func (s SqlUserAccessTokenStore) GetByUser(userId string, offset, limit int) sto } result.Data = tokens - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } diff --git a/store/sqlstore/user_access_token_store_test.go b/store/sqlstore/user_access_token_store_test.go index e160ddfa13..74ce53b647 100644 --- a/store/sqlstore/user_access_token_store_test.go +++ b/store/sqlstore/user_access_token_store_test.go @@ -7,7 +7,7 @@ import ( "testing" "github.com/mattermost/mattermost-server/model" -"github.com/mattermost/mattermost-server/store" + "github.com/mattermost/mattermost-server/store" ) func TestUserAccessTokenSaveGetDelete(t *testing.T) { diff --git a/store/sqlstore/user_store.go b/store/sqlstore/user_store.go index abc2d2d28b..5d0e1c50dd 100644 --- a/store/sqlstore/user_store.go +++ b/store/sqlstore/user_store.go @@ -93,23 +93,14 @@ func (us SqlUserStore) CreateIndexesIfNotExists() { } func (us SqlUserStore) Save(user *model.User) store.StoreChannel { - - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { if len(user.Id) > 0 { result.Err = model.NewAppError("SqlUserStore.Save", "store.sql_user.save.existing.app_error", nil, "user_id="+user.Id, http.StatusBadRequest) - storeChannel <- result - close(storeChannel) return } user.PreSave() if result.Err = user.IsValid(); result.Err != nil { - storeChannel <- result - close(storeChannel) return } @@ -124,25 +115,14 @@ func (us SqlUserStore) Save(user *model.User) store.StoreChannel { } else { result.Data = user } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (us SqlUserStore) Update(user *model.User, trustedUpdateData bool) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { user.PreUpdate() if result.Err = user.IsValid(); result.Err != nil { - storeChannel <- result - close(storeChannel) return } @@ -176,8 +156,6 @@ func (us SqlUserStore) Update(user *model.User, trustedUpdateData bool) store.St if user.Username != oldUser.Username || user.Email != oldUser.Email { result.Err = model.NewAppError("SqlUserStore.Update", "store.sql_user.update.can_not_change_ldap.app_error", nil, "user_id="+user.Id, http.StatusBadRequest) - storeChannel <- result - close(storeChannel) return } } else if user.Email != oldUser.Email { @@ -204,20 +182,11 @@ func (us SqlUserStore) Update(user *model.User, trustedUpdateData bool) store.St result.Data = [2]*model.User{user, oldUser} } } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (us SqlUserStore) UpdateLastPictureUpdate(userId string) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { curTime := model.GetMillis() if _, err := us.GetMaster().Exec("UPDATE Users SET LastPictureUpdate = :Time, UpdateAt = :Time WHERE Id = :UserId", map[string]interface{}{"Time": curTime, "UserId": userId}); err != nil { @@ -225,20 +194,11 @@ func (us SqlUserStore) UpdateLastPictureUpdate(userId string) store.StoreChannel } else { result.Data = userId } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (us SqlUserStore) UpdateUpdateAt(userId string) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { curTime := model.GetMillis() if _, err := us.GetMaster().Exec("UPDATE Users SET UpdateAt = :Time WHERE Id = :UserId", map[string]interface{}{"Time": curTime, "UserId": userId}); err != nil { @@ -246,21 +206,11 @@ func (us SqlUserStore) UpdateUpdateAt(userId string) store.StoreChannel { } else { result.Data = userId } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (us SqlUserStore) UpdatePassword(userId, hashedPassword string) store.StoreChannel { - - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { updateAt := model.GetMillis() if _, err := us.GetMaster().Exec("UPDATE Users SET Password = :Password, LastPasswordUpdate = :LastPasswordUpdate, UpdateAt = :UpdateAt, AuthData = NULL, AuthService = '', EmailVerified = true, FailedAttempts = 0 WHERE Id = :UserId", map[string]interface{}{"Password": hashedPassword, "LastPasswordUpdate": updateAt, "UpdateAt": updateAt, "UserId": userId}); err != nil { @@ -268,40 +218,21 @@ func (us SqlUserStore) UpdatePassword(userId, hashedPassword string) store.Store } else { result.Data = userId } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (us SqlUserStore) UpdateFailedPasswordAttempts(userId string, attempts int) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { if _, err := us.GetMaster().Exec("UPDATE Users SET FailedAttempts = :FailedAttempts WHERE Id = :UserId", map[string]interface{}{"FailedAttempts": attempts, "UserId": userId}); err != nil { result.Err = model.NewAppError("SqlUserStore.UpdateFailedPasswordAttempts", "store.sql_user.update_failed_pwd_attempts.app_error", nil, "user_id="+userId, http.StatusInternalServerError) } else { result.Data = userId } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (us SqlUserStore) UpdateAuthData(userId string, service string, authData *string, email string, resetMfa bool) store.StoreChannel { - - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { email = strings.ToLower(email) updateAt := model.GetMillis() @@ -336,21 +267,11 @@ func (us SqlUserStore) UpdateAuthData(userId string, service string, authData *s } else { result.Data = userId } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (us SqlUserStore) UpdateMfaSecret(userId, secret string) store.StoreChannel { - - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { updateAt := model.GetMillis() if _, err := us.GetMaster().Exec("UPDATE Users SET MfaSecret = :Secret, UpdateAt = :UpdateAt WHERE Id = :UserId", map[string]interface{}{"Secret": secret, "UpdateAt": updateAt, "UserId": userId}); err != nil { @@ -358,21 +279,11 @@ func (us SqlUserStore) UpdateMfaSecret(userId, secret string) store.StoreChannel } else { result.Data = userId } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (us SqlUserStore) UpdateMfaActive(userId string, active bool) store.StoreChannel { - - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { updateAt := model.GetMillis() if _, err := us.GetMaster().Exec("UPDATE Users SET MfaActive = :Active, UpdateAt = :UpdateAt WHERE Id = :UserId", map[string]interface{}{"Active": active, "UpdateAt": updateAt, "UserId": userId}); err != nil { @@ -380,21 +291,11 @@ func (us SqlUserStore) UpdateMfaActive(userId string, active bool) store.StoreCh } else { result.Data = userId } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (us SqlUserStore) Get(id string) store.StoreChannel { - - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { if obj, err := us.GetReplica().Get(model.User{}, id); err != nil { result.Err = model.NewAppError("SqlUserStore.Get", "store.sql_user.get.app_error", nil, "user_id="+id+", "+err.Error(), http.StatusInternalServerError) } else if obj == nil { @@ -402,64 +303,33 @@ func (us SqlUserStore) Get(id string) store.StoreChannel { } else { result.Data = obj.(*model.User) } - - storeChannel <- result - close(storeChannel) - - }() - - return storeChannel + }) } func (us SqlUserStore) GetAll() store.StoreChannel { - - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { var data []*model.User if _, err := us.GetReplica().Select(&data, "SELECT * FROM Users"); err != nil { result.Err = model.NewAppError("SqlUserStore.GetAll", "store.sql_user.get.app_error", nil, err.Error(), http.StatusInternalServerError) } result.Data = data - - storeChannel <- result - close(storeChannel) - - }() - - return storeChannel + }) } func (s SqlUserStore) GetEtagForAllProfiles() store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { updateAt, err := s.GetReplica().SelectInt("SELECT UpdateAt FROM Users ORDER BY UpdateAt DESC LIMIT 1") if err != nil { result.Data = fmt.Sprintf("%v.%v.%v.%v", model.CurrentVersion, model.GetMillis(), utils.Cfg.PrivacySettings.ShowFullName, utils.Cfg.PrivacySettings.ShowEmailAddress) } else { result.Data = fmt.Sprintf("%v.%v.%v.%v", model.CurrentVersion, updateAt, utils.Cfg.PrivacySettings.ShowFullName, utils.Cfg.PrivacySettings.ShowEmailAddress) } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (us SqlUserStore) GetAllProfiles(offset int, limit int) store.StoreChannel { - - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { var users []*model.User if _, err := us.GetReplica().Select(&users, "SELECT * FROM Users ORDER BY Username ASC LIMIT :Limit OFFSET :Offset", map[string]interface{}{"Offset": offset, "Limit": limit}); err != nil { @@ -472,41 +342,22 @@ func (us SqlUserStore) GetAllProfiles(offset int, limit int) store.StoreChannel result.Data = users } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlUserStore) GetEtagForProfiles(teamId string) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { 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.%v.%v", model.CurrentVersion, model.GetMillis(), utils.Cfg.PrivacySettings.ShowFullName, utils.Cfg.PrivacySettings.ShowEmailAddress) } else { result.Data = fmt.Sprintf("%v.%v.%v.%v", model.CurrentVersion, updateAt, utils.Cfg.PrivacySettings.ShowFullName, utils.Cfg.PrivacySettings.ShowEmailAddress) } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (us SqlUserStore) GetProfiles(teamId string, offset int, limit int) store.StoreChannel { - - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { var users []*model.User if _, err := us.GetReplica().Select(&users, "SELECT Users.* FROM Users, TeamMembers WHERE TeamMembers.TeamId = :TeamId AND Users.Id = TeamMembers.UserId AND TeamMembers.DeleteAt = 0 ORDER BY Users.Username ASC LIMIT :Limit OFFSET :Offset", map[string]interface{}{"TeamId": teamId, "Offset": offset, "Limit": limit}); err != nil { @@ -519,12 +370,7 @@ func (us SqlUserStore) GetProfiles(teamId string, offset int, limit int) store.S result.Data = users } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (us SqlUserStore) InvalidateProfilesInChannelCacheByUser(userId string) { @@ -545,12 +391,7 @@ func (us SqlUserStore) InvalidateProfilesInChannelCache(channelId string) { } func (us SqlUserStore) GetProfilesInChannel(channelId string, offset int, limit int) store.StoreChannel { - - storeChannel := make(store.StoreChannel) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { var users []*model.User query := "SELECT Users.* FROM Users, ChannelMembers WHERE ChannelMembers.ChannelId = :ChannelId AND Users.Id = ChannelMembers.UserId ORDER BY Users.Username ASC LIMIT :Limit OFFSET :Offset" @@ -565,29 +406,17 @@ func (us SqlUserStore) GetProfilesInChannel(channelId string, offset int, limit result.Data = users } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (us SqlUserStore) GetAllProfilesInChannel(channelId string, allowFromCache bool) store.StoreChannel { - - storeChannel := make(store.StoreChannel) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { if allowFromCache { if cacheItem, ok := profilesInChannelCache.Get(channelId); ok { if us.metrics != nil { us.metrics.IncrementMemCacheHitCounter("Profiles in Channel") } result.Data = cacheItem.(map[string]*model.User) - storeChannel <- result - close(storeChannel) return } else { if us.metrics != nil { @@ -621,21 +450,11 @@ func (us SqlUserStore) GetAllProfilesInChannel(channelId string, allowFromCache profilesInChannelCache.AddWithExpiresInSecs(channelId, userMap, PROFILES_IN_CHANNEL_CACHE_SEC) } } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (us SqlUserStore) GetProfilesNotInChannel(teamId string, channelId string, offset int, limit int) store.StoreChannel { - - storeChannel := make(store.StoreChannel) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { var users []*model.User if _, err := us.GetReplica().Select(&users, ` @@ -662,20 +481,11 @@ func (us SqlUserStore) GetProfilesNotInChannel(teamId string, channelId string, result.Data = users } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (us SqlUserStore) GetProfilesWithoutTeam(offset int, limit int) store.StoreChannel { - storeChannel := make(store.StoreChannel) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { var users []*model.User query := ` @@ -708,20 +518,11 @@ func (us SqlUserStore) GetProfilesWithoutTeam(offset int, limit int) store.Store result.Data = users } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (us SqlUserStore) GetProfilesByUsernames(usernames []string, teamId string) store.StoreChannel { - storeChannel := make(store.StoreChannel) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { var users []*model.User props := make(map[string]interface{}) idQuery := "" @@ -749,12 +550,7 @@ func (us SqlUserStore) GetProfilesByUsernames(usernames []string, teamId string) } else { result.Data = users } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } type UserWithLastActivityAt struct { @@ -763,12 +559,7 @@ type UserWithLastActivityAt struct { } func (us SqlUserStore) GetRecentlyActiveUsersForTeam(teamId string, offset, limit int) store.StoreChannel { - - storeChannel := make(store.StoreChannel) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { var users []*UserWithLastActivityAt if _, err := us.GetReplica().Select(&users, ` @@ -796,21 +587,11 @@ func (us SqlUserStore) GetRecentlyActiveUsersForTeam(teamId string, offset, limi result.Data = userList } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (us SqlUserStore) GetNewUsersForTeam(teamId string, offset, limit int) store.StoreChannel { - - storeChannel := make(store.StoreChannel) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { var users []*model.User if _, err := us.GetReplica().Select(&users, ` @@ -830,21 +611,11 @@ func (us SqlUserStore) GetNewUsersForTeam(teamId string, offset, limit int) stor result.Data = users } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (us SqlUserStore) GetProfileByIds(userIds []string, allowFromCache bool) store.StoreChannel { - - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { users := []*model.User{} props := make(map[string]interface{}) idQuery := "" @@ -874,8 +645,6 @@ func (us SqlUserStore) GetProfileByIds(userIds []string, allowFromCache bool) st // If everything came from the cache then just return if len(remainingUserIds) == 0 { result.Data = users - storeChannel <- result - close(storeChannel) return } @@ -902,21 +671,11 @@ func (us SqlUserStore) GetProfileByIds(userIds []string, allowFromCache bool) st result.Data = users } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (us SqlUserStore) GetSystemAdminProfiles() store.StoreChannel { - - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { var users []*model.User if _, err := us.GetReplica().Select(&users, "SELECT * FROM Users WHERE Roles LIKE :Roles", map[string]interface{}{"Roles": "%system_admin%"}); err != nil { @@ -932,21 +691,11 @@ func (us SqlUserStore) GetSystemAdminProfiles() store.StoreChannel { result.Data = userMap } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (us SqlUserStore) GetByEmail(email string) store.StoreChannel { - - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { email = strings.ToLower(email) user := model.User{} @@ -956,25 +705,13 @@ func (us SqlUserStore) GetByEmail(email string) store.StoreChannel { } result.Data = &user - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (us SqlUserStore) GetByAuth(authData *string, authService string) store.StoreChannel { - - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { if authData == nil || *authData == "" { result.Err = model.NewAppError("SqlUserStore.GetByAuth", store.MISSING_AUTH_ACCOUNT_ERROR, nil, "authData='', authService="+authService, http.StatusBadRequest) - storeChannel <- result - close(storeChannel) return } @@ -989,20 +726,11 @@ func (us SqlUserStore) GetByAuth(authData *string, authService string) store.Sto } result.Data = &user - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (us SqlUserStore) GetAllUsingAuthService(authService string) store.StoreChannel { - - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} + return store.Do(func(result *store.StoreResult) { var data []*model.User if _, err := us.GetReplica().Select(&data, "SELECT * FROM Users WHERE AuthService = :AuthService", map[string]interface{}{"AuthService": authService}); err != nil { @@ -1010,21 +738,11 @@ func (us SqlUserStore) GetAllUsingAuthService(authService string) store.StoreCha } result.Data = data - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (us SqlUserStore) GetByUsername(username string) store.StoreChannel { - - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { user := model.User{} if err := us.GetReplica().SelectOne(&user, "SELECT * FROM Users WHERE Username = :Username", map[string]interface{}{"Username": username}); err != nil { @@ -1032,20 +750,11 @@ func (us SqlUserStore) GetByUsername(username string) store.StoreChannel { } result.Data = &user - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (us SqlUserStore) GetForLogin(loginId string, allowSignInWithUsername, allowSignInWithEmail, ldapEnabled bool) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { params := map[string]interface{}{ "LoginId": loginId, "AllowSignInWithUsername": allowSignInWithUsername, @@ -1073,77 +782,39 @@ func (us SqlUserStore) GetForLogin(loginId string, allowSignInWithUsername, allo } else { result.Err = model.NewAppError("SqlUserStore.GetForLogin", "store.sql_user.get_for_login.app_error", nil, "", http.StatusInternalServerError) } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (us SqlUserStore) VerifyEmail(userId string) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { if _, err := us.GetMaster().Exec("UPDATE Users SET EmailVerified = true WHERE Id = :UserId", map[string]interface{}{"UserId": userId}); err != nil { result.Err = model.NewAppError("SqlUserStore.VerifyEmail", "store.sql_user.verify_email.app_error", nil, "userId="+userId+", "+err.Error(), http.StatusInternalServerError) } result.Data = userId - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (us SqlUserStore) GetTotalUsersCount() store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { if count, err := us.GetReplica().SelectInt("SELECT COUNT(Id) FROM Users"); err != nil { result.Err = model.NewAppError("SqlUserStore.GetTotalUsersCount", "store.sql_user.get_total_users_count.app_error", nil, err.Error(), http.StatusInternalServerError) } else { result.Data = count } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (us SqlUserStore) PermanentDelete(userId string) store.StoreChannel { - - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { if _, err := us.GetMaster().Exec("DELETE FROM Users WHERE Id = :UserId", map[string]interface{}{"UserId": userId}); err != nil { result.Err = model.NewAppError("SqlUserStore.PermanentDelete", "store.sql_user.permanent_delete.app_error", nil, "userId="+userId+", "+err.Error(), http.StatusInternalServerError) } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (us SqlUserStore) AnalyticsUniqueUserCount(teamId string) store.StoreChannel { - - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { query := "" if len(teamId) > 0 { query = "SELECT COUNT(DISTINCT Users.Email) From Users, TeamMembers WHERE TeamMembers.TeamId = :TeamId AND Users.Id = TeamMembers.UserId AND TeamMembers.DeleteAt = 0 AND Users.DeleteAt = 0" @@ -1157,21 +828,11 @@ func (us SqlUserStore) AnalyticsUniqueUserCount(teamId string) store.StoreChanne } else { result.Data = v } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (us SqlUserStore) AnalyticsActiveCount(timePeriod int64) store.StoreChannel { - - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { time := model.GetMillis() - timePeriod query := "SELECT COUNT(*) FROM Status WHERE LastActivityAt > :Time" @@ -1182,20 +843,11 @@ func (us SqlUserStore) AnalyticsActiveCount(timePeriod int64) store.StoreChannel } else { result.Data = v } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (us SqlUserStore) GetUnreadCount(userId string) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { if count, err := us.GetReplica().SelectInt(` SELECT SUM(CASE WHEN c.Type = 'D' THEN (c.TotalMsgCount - cm.MsgCount) ELSE cm.MentionCount END) FROM Channels c @@ -1207,37 +859,21 @@ func (us SqlUserStore) GetUnreadCount(userId string) store.StoreChannel { } else { result.Data = count } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (us SqlUserStore) GetUnreadCountForChannel(userId string, channelId string) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { if count, err := us.GetReplica().SelectInt("SELECT SUM(CASE WHEN c.Type = 'D' THEN (c.TotalMsgCount - cm.MsgCount) ELSE cm.MentionCount END) FROM Channels c INNER JOIN ChannelMembers cm ON c.Id = :ChannelId AND cm.ChannelId = :ChannelId AND cm.UserId = :UserId", map[string]interface{}{"ChannelId": channelId, "UserId": userId}); err != nil { result.Err = model.NewAppError("SqlUserStore.GetMentionCountForChannel", "store.sql_user.get_unread_count_for_channel.app_error", nil, err.Error(), http.StatusInternalServerError) } else { result.Data = count } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (us SqlUserStore) Search(teamId string, term string, options map[string]bool) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { + return store.Do(func(result *store.StoreResult) { searchQuery := "" if teamId == "" { @@ -1270,18 +906,13 @@ func (us SqlUserStore) Search(teamId string, term string, options map[string]boo LIMIT 100` } - storeChannel <- us.performSearch(searchQuery, term, options, map[string]interface{}{"TeamId": teamId}) - close(storeChannel) + *result = us.performSearch(searchQuery, term, options, map[string]interface{}{"TeamId": teamId}) - }() - - return storeChannel + }) } func (us SqlUserStore) SearchWithoutTeam(term string, options map[string]bool) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { + return store.Do(func(result *store.StoreResult) { searchQuery := ` SELECT * @@ -1300,18 +931,13 @@ func (us SqlUserStore) SearchWithoutTeam(term string, options map[string]bool) s ORDER BY Username ASC LIMIT 100` - storeChannel <- us.performSearch(searchQuery, term, options, map[string]interface{}{}) - close(storeChannel) + *result = us.performSearch(searchQuery, term, options, map[string]interface{}{}) - }() - - return storeChannel + }) } func (us SqlUserStore) SearchNotInTeam(notInTeamId string, term string, options map[string]bool) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { + return store.Do(func(result *store.StoreResult) { searchQuery := ` SELECT Users.* @@ -1326,18 +952,13 @@ func (us SqlUserStore) SearchNotInTeam(notInTeamId string, term string, options ORDER BY Users.Username ASC LIMIT 100` - storeChannel <- us.performSearch(searchQuery, term, options, map[string]interface{}{"NotInTeamId": notInTeamId}) - close(storeChannel) + *result = us.performSearch(searchQuery, term, options, map[string]interface{}{"NotInTeamId": notInTeamId}) - }() - - return storeChannel + }) } func (us SqlUserStore) SearchNotInChannel(teamId string, channelId string, term string, options map[string]bool) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { + return store.Do(func(result *store.StoreResult) { searchQuery := "" if teamId == "" { searchQuery = ` @@ -1373,18 +994,13 @@ func (us SqlUserStore) SearchNotInChannel(teamId string, channelId string, term LIMIT 100` } - storeChannel <- us.performSearch(searchQuery, term, options, map[string]interface{}{"TeamId": teamId, "ChannelId": channelId}) - close(storeChannel) + *result = us.performSearch(searchQuery, term, options, map[string]interface{}{"TeamId": teamId, "ChannelId": channelId}) - }() - - return storeChannel + }) } func (us SqlUserStore) SearchInChannel(channelId string, term string, options map[string]bool) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { + return store.Do(func(result *store.StoreResult) { searchQuery := ` SELECT Users.* @@ -1398,12 +1014,9 @@ func (us SqlUserStore) SearchInChannel(channelId string, term string, options ma ORDER BY Users.Username ASC LIMIT 100` - storeChannel <- us.performSearch(searchQuery, term, options, map[string]interface{}{"ChannelId": channelId}) - close(storeChannel) + *result = us.performSearch(searchQuery, term, options, map[string]interface{}{"ChannelId": channelId}) - }() - - return storeChannel + }) } var escapeUserSearchChar = []string{ @@ -1483,51 +1096,27 @@ func (us SqlUserStore) performSearch(searchQuery string, term string, options ma } func (us SqlUserStore) AnalyticsGetInactiveUsersCount() store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { if count, err := us.GetReplica().SelectInt("SELECT COUNT(Id) FROM Users WHERE DeleteAt > 0"); err != nil { result.Err = model.NewAppError("SqlUserStore.AnalyticsGetInactiveUsersCount", "store.sql_user.analytics_get_inactive_users_count.app_error", nil, err.Error(), http.StatusInternalServerError) } else { result.Data = count } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (us SqlUserStore) AnalyticsGetSystemAdminCount() store.StoreChannel { - - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { if count, err := us.GetReplica().SelectInt("SELECT count(*) FROM Users WHERE Roles LIKE :Roles and DeleteAt = 0", map[string]interface{}{"Roles": "%system_admin%"}); err != nil { result.Err = model.NewAppError("SqlUserStore.AnalyticsGetSystemAdminCount", "store.sql_user.analytics_get_system_admin_count.app_error", nil, err.Error(), http.StatusInternalServerError) } else { result.Data = count } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (us SqlUserStore) GetProfilesNotInTeam(teamId string, offset int, limit int) store.StoreChannel { - - storeChannel := make(store.StoreChannel) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { var users []*model.User if _, err := us.GetReplica().Select(&users, ` @@ -1551,21 +1140,11 @@ func (us SqlUserStore) GetProfilesNotInTeam(teamId string, offset int, limit int result.Data = users } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (us SqlUserStore) GetEtagForProfilesNotInTeam(teamId string) store.StoreChannel { - - storeChannel := make(store.StoreChannel) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { updateAt, err := us.GetReplica().SelectInt(` SELECT u.UpdateAt @@ -1584,10 +1163,5 @@ func (us SqlUserStore) GetEtagForProfilesNotInTeam(teamId string) store.StoreCha } else { result.Data = fmt.Sprintf("%v.%v.%v.%v", model.CurrentVersion, updateAt, utils.Cfg.PrivacySettings.ShowFullName, utils.Cfg.PrivacySettings.ShowEmailAddress) } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } diff --git a/store/sqlstore/webhook_store.go b/store/sqlstore/webhook_store.go index 705cd40bcb..8a3720fa04 100644 --- a/store/sqlstore/webhook_store.go +++ b/store/sqlstore/webhook_store.go @@ -81,22 +81,14 @@ func (s SqlWebhookStore) InvalidateWebhookCache(webhookId string) { } func (s SqlWebhookStore) SaveIncoming(webhook *model.IncomingWebhook) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { if len(webhook.Id) > 0 { result.Err = model.NewAppError("SqlWebhookStore.SaveIncoming", "store.sql_webhooks.save_incoming.existing.app_error", nil, "id="+webhook.Id, http.StatusBadRequest) - storeChannel <- result - close(storeChannel) return } webhook.PreSave() if result.Err = webhook.IsValid(); result.Err != nil { - storeChannel <- result - close(storeChannel) return } @@ -105,20 +97,11 @@ func (s SqlWebhookStore) SaveIncoming(webhook *model.IncomingWebhook) store.Stor } else { result.Data = webhook } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlWebhookStore) UpdateIncoming(hook *model.IncomingWebhook) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { hook.UpdateAt = model.GetMillis() if _, err := s.GetMaster().Update(hook); err != nil { @@ -126,28 +109,17 @@ func (s SqlWebhookStore) UpdateIncoming(hook *model.IncomingWebhook) store.Store } else { result.Data = hook } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlWebhookStore) GetIncoming(id string, allowFromCache bool) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { if allowFromCache { if cacheItem, ok := webhookCache.Get(id); ok { if s.metrics != nil { s.metrics.IncrementMemCacheHitCounter("Webhook") } result.Data = cacheItem.(*model.IncomingWebhook) - storeChannel <- result - close(storeChannel) return } else { if s.metrics != nil { @@ -171,80 +143,44 @@ func (s SqlWebhookStore) GetIncoming(id string, allowFromCache bool) store.Store } result.Data = &webhook - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlWebhookStore) DeleteIncoming(webhookId string, time int64) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { _, err := s.GetMaster().Exec("Update IncomingWebhooks 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.DeleteIncoming", "store.sql_webhooks.delete_incoming.app_error", nil, "id="+webhookId+", err="+err.Error(), http.StatusInternalServerError) } s.InvalidateWebhookCache(webhookId) - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlWebhookStore) PermanentDeleteIncomingByUser(userId string) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { _, err := s.GetMaster().Exec("DELETE FROM IncomingWebhooks WHERE UserId = :UserId", map[string]interface{}{"UserId": userId}) if err != nil { result.Err = model.NewAppError("SqlWebhookStore.DeleteIncomingByUser", "store.sql_webhooks.permanent_delete_incoming_by_user.app_error", nil, "id="+userId+", err="+err.Error(), http.StatusInternalServerError) } ClearWebhookCaches() - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlWebhookStore) PermanentDeleteIncomingByChannel(channelId string) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { _, err := s.GetMaster().Exec("DELETE FROM IncomingWebhooks WHERE ChannelId = :ChannelId", map[string]interface{}{"ChannelId": channelId}) if err != nil { result.Err = model.NewAppError("SqlWebhookStore.DeleteIncomingByChannel", "store.sql_webhooks.permanent_delete_incoming_by_channel.app_error", nil, "id="+channelId+", err="+err.Error(), http.StatusInternalServerError) } ClearWebhookCaches() - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlWebhookStore) GetIncomingList(offset, limit int) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { var webhooks []*model.IncomingWebhook if _, err := s.GetReplica().Select(&webhooks, "SELECT * FROM IncomingWebhooks WHERE DeleteAt = 0 LIMIT :Limit OFFSET :Offset", map[string]interface{}{"Limit": limit, "Offset": offset}); err != nil { @@ -252,20 +188,11 @@ func (s SqlWebhookStore) GetIncomingList(offset, limit int) store.StoreChannel { } result.Data = webhooks - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlWebhookStore) GetIncomingByTeam(teamId string, offset, limit int) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { var webhooks []*model.IncomingWebhook if _, err := s.GetReplica().Select(&webhooks, "SELECT * FROM IncomingWebhooks WHERE TeamId = :TeamId AND DeleteAt = 0 LIMIT :Limit OFFSET :Offset", map[string]interface{}{"TeamId": teamId, "Limit": limit, "Offset": offset}); err != nil { @@ -273,20 +200,11 @@ func (s SqlWebhookStore) GetIncomingByTeam(teamId string, offset, limit int) sto } result.Data = webhooks - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlWebhookStore) GetIncomingByChannel(channelId string) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { var webhooks []*model.IncomingWebhook if _, err := s.GetReplica().Select(&webhooks, "SELECT * FROM IncomingWebhooks WHERE ChannelId = :ChannelId AND DeleteAt = 0", map[string]interface{}{"ChannelId": channelId}); err != nil { @@ -294,31 +212,18 @@ func (s SqlWebhookStore) GetIncomingByChannel(channelId string) store.StoreChann } result.Data = webhooks - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlWebhookStore) SaveOutgoing(webhook *model.OutgoingWebhook) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { if len(webhook.Id) > 0 { result.Err = model.NewAppError("SqlWebhookStore.SaveOutgoing", "store.sql_webhooks.save_outgoing.override.app_error", nil, "id="+webhook.Id, http.StatusBadRequest) - storeChannel <- result - close(storeChannel) return } webhook.PreSave() if result.Err = webhook.IsValid(); result.Err != nil { - storeChannel <- result - close(storeChannel) return } @@ -327,20 +232,11 @@ func (s SqlWebhookStore) SaveOutgoing(webhook *model.OutgoingWebhook) store.Stor } else { result.Data = webhook } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlWebhookStore) GetOutgoing(id string) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.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 { @@ -348,20 +244,11 @@ func (s SqlWebhookStore) GetOutgoing(id string) store.StoreChannel { } result.Data = &webhook - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlWebhookStore) GetOutgoingList(offset, limit int) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { var webhooks []*model.OutgoingWebhook if _, err := s.GetReplica().Select(&webhooks, "SELECT * FROM OutgoingWebhooks WHERE DeleteAt = 0 LIMIT :Limit OFFSET :Offset", map[string]interface{}{"Offset": offset, "Limit": limit}); err != nil { @@ -369,20 +256,11 @@ func (s SqlWebhookStore) GetOutgoingList(offset, limit int) store.StoreChannel { } result.Data = webhooks - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlWebhookStore) GetOutgoingByChannel(channelId string, offset, limit int) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { var webhooks []*model.OutgoingWebhook query := "" @@ -397,20 +275,11 @@ func (s SqlWebhookStore) GetOutgoingByChannel(channelId string, offset, limit in } result.Data = webhooks - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlWebhookStore) GetOutgoingByTeam(teamId string, offset, limit int) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { var webhooks []*model.OutgoingWebhook query := "" @@ -425,76 +294,40 @@ func (s SqlWebhookStore) GetOutgoingByTeam(teamId string, offset, limit int) sto } result.Data = webhooks - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlWebhookStore) DeleteOutgoing(webhookId string, time int64) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.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", "store.sql_webhooks.delete_outgoing.app_error", nil, "id="+webhookId+", err="+err.Error(), http.StatusInternalServerError) } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlWebhookStore) PermanentDeleteOutgoingByUser(userId string) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { _, err := s.GetMaster().Exec("DELETE FROM OutgoingWebhooks WHERE CreatorId = :UserId", map[string]interface{}{"UserId": userId}) if err != nil { result.Err = model.NewAppError("SqlWebhookStore.DeleteOutgoingByUser", "store.sql_webhooks.permanent_delete_outgoing_by_user.app_error", nil, "id="+userId+", err="+err.Error(), http.StatusInternalServerError) } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlWebhookStore) PermanentDeleteOutgoingByChannel(channelId string) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { _, err := s.GetMaster().Exec("DELETE FROM OutgoingWebhooks WHERE ChannelId = :ChannelId", map[string]interface{}{"ChannelId": channelId}) if err != nil { result.Err = model.NewAppError("SqlWebhookStore.DeleteOutgoingByChannel", "store.sql_webhooks.permanent_delete_outgoing_by_channel.app_error", nil, "id="+channelId+", err="+err.Error(), http.StatusInternalServerError) } ClearWebhookCaches() - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlWebhookStore) UpdateOutgoing(hook *model.OutgoingWebhook) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { hook.UpdateAt = model.GetMillis() if _, err := s.GetMaster().Update(hook); err != nil { @@ -502,20 +335,11 @@ func (s SqlWebhookStore) UpdateOutgoing(hook *model.OutgoingWebhook) store.Store } else { result.Data = hook } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlWebhookStore) AnalyticsIncomingCount(teamId string) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { query := `SELECT COUNT(*) @@ -533,20 +357,11 @@ func (s SqlWebhookStore) AnalyticsIncomingCount(teamId string) store.StoreChanne } else { result.Data = v } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } func (s SqlWebhookStore) AnalyticsOutgoingCount(teamId string) store.StoreChannel { - storeChannel := make(store.StoreChannel, 1) - - go func() { - result := store.StoreResult{} - + return store.Do(func(result *store.StoreResult) { query := `SELECT COUNT(*) @@ -564,10 +379,5 @@ func (s SqlWebhookStore) AnalyticsOutgoingCount(teamId string) store.StoreChanne } else { result.Data = v } - - storeChannel <- result - close(storeChannel) - }() - - return storeChannel + }) } From 7c4e338a5652835ba6de986c3d56525acffe7d47 Mon Sep 17 00:00:00 2001 From: enahum Date: Tue, 10 Oct 2017 15:50:26 -0300 Subject: [PATCH 4/8] translations PR 20171009 (#7598) --- i18n/de.json | 100 ++++++++++++++++++++++++++---------------------- i18n/en.json | 16 ++++---- i18n/es.json | 10 ++++- i18n/fr.json | 8 ++++ i18n/it.json | 10 ++++- i18n/ja.json | 10 ++++- i18n/ko.json | 8 ++++ i18n/nl.json | 8 ++++ i18n/pl.json | 74 +++++++++++++++++++---------------- i18n/pt-BR.json | 10 ++++- i18n/ru.json | 8 ++++ i18n/tr.json | 10 ++++- i18n/zh-CN.json | 42 ++++++++++++-------- i18n/zh-TW.json | 52 ++++++++++++++----------- 14 files changed, 235 insertions(+), 131 deletions(-) diff --git a/i18n/de.json b/i18n/de.json index c50ae29822..760986963c 100644 --- a/i18n/de.json +++ b/i18n/de.json @@ -2425,7 +2425,7 @@ }, { "id": "api.user.activate_mfa.email_and_ldap_only.app_error", - "translation": "MFA ist für diesen Accounttyp nicht verfügbar" + "translation": "MFA ist für diesen Kontotyp nicht verfügbar" }, { "id": "api.user.add_direct_channels_and_forget.failed.error", @@ -2465,7 +2465,7 @@ }, { "id": "api.user.check_user_login_attempts.too_many.app_error", - "translation": "Ihr Account ist gesperrt, da es zu viele fehlerhafte Passworteingaben gab. Bitte setzen Sie Ihr Passwort zurück." + "translation": "Ihr Konto ist gesperrt, da es zu viele fehlerhafte Passworteingaben gab. Bitte setzen Sie Ihr Passwort zurück." }, { "id": "api.user.check_user_mfa.bad_code.app_error", @@ -2493,11 +2493,11 @@ }, { "id": "api.user.create_oauth_user.already_attached.app_error", - "translation": "Mit dieser E-Mail-Adresse ist bereits ein Account verknüpft, der nicht die Anmeldemethode {{.Service}} verwendet. Bitte verwenden Sie {{.Auth}} zum Anmelden." + "translation": "Mit dieser E-Mail-Adresse ist bereits ein Konto verknüpft, das nicht die Anmeldemethode {{.Service}} verwendet. Bitte verwenden Sie {{.Auth}} zum Anmelden." }, { "id": "api.user.create_oauth_user.already_used.app_error", - "translation": "Dieser {{.Service}} Account wurde bereits zur Registrierung verwendet" + "translation": "Dieses {{.Service}} Konto wurde bereits zur Registrierung verwendet" }, { "id": "api.user.create_oauth_user.create.app_error", @@ -2597,7 +2597,7 @@ }, { "id": "api.user.ldap_to_email.not_ldap_account.app_error", - "translation": "Dieser Account verwendet kein AD/LDAP" + "translation": "Dieses Konto verwendet kein AD/LDAP" }, { "id": "api.user.login.blank_pwd.app_error", @@ -2605,7 +2605,7 @@ }, { "id": "api.user.login.inactive.app_error", - "translation": "Anmeldung nicht möglich, weil Ihr Account deaktiviert wurde. Bitte wenden Sie sich an einen Administrator." + "translation": "Anmeldung nicht möglich, weil Ihr Konto deaktiviert wurde. Bitte wenden Sie sich an einen Administrator." }, { "id": "api.user.login.invalid_credentials", @@ -2657,15 +2657,15 @@ }, { "id": "api.user.permanent_delete_user.attempting.warn", - "translation": "Versuche, Account %v id=%v permanent zu löschen" + "translation": "Versuche Konto %v id=%v permanent zu löschen" }, { "id": "api.user.permanent_delete_user.deleted.warn", - "translation": "Account permanent gelöscht %v id=%v" + "translation": "Konto permanent gelöscht %v id=%v" }, { "id": "api.user.permanent_delete_user.system_admin.warn", - "translation": "Sie möchten %v löschen, welcher ein Systemadministrator ist. Eventuell müssen Sie mithilfe der Kommandozeilentools einen anderen Account zum Systemadministrator machen." + "translation": "Sie möchten %v löschen, welcher ein Systemadministrator ist. Eventuell müssen Sie mithilfe der Kommandozeilentools ein anderes Konto zum Systemadministrator machen." }, { "id": "api.user.reset_password.invalid_link.app_error", @@ -2681,7 +2681,7 @@ }, { "id": "api.user.reset_password.sso.app_error", - "translation": "Kann Passwort für SSO-Accounts nicht zurücksetzen" + "translation": "Kann Passwort für SSO-Konten nicht zurücksetzen" }, { "id": "api.user.reset_password.wrong_team.app_error", @@ -2709,7 +2709,7 @@ }, { "id": "api.user.send_password_reset.find.app_error", - "translation": "Es konnte kein Account mit dieser Adresse gefunden werden." + "translation": "Es konnte kein Konto mit dieser Adresse gefunden werden." }, { "id": "api.user.send_password_reset.send.app_error", @@ -2717,7 +2717,7 @@ }, { "id": "api.user.send_password_reset.sso.app_error", - "translation": "Kann Passwort für SSO-Accounts nicht zurücksetzen" + "translation": "Kann Passwort für SSO-Konten nicht zurücksetzen" }, { "id": "api.user.send_sign_in_change_email_and_forget.error", @@ -2737,7 +2737,7 @@ }, { "id": "api.user.update_active.no_deactivate_ldap.app_error", - "translation": "Sie können den Aktivitätsstatus des AD-/LDAP-Accounts nicht ändern. Bitte ändern Sie diesen über den AD-/LDAP-Server." + "translation": "Sie können den Aktivitätsstatus des AD-/LDAP-Kontos nicht ändern. Bitte ändern Sie diesen über den AD-/LDAP-Server." }, { "id": "api.user.update_active.permissions.app_error", @@ -2761,7 +2761,7 @@ }, { "id": "api.user.update_password.incorrect.app_error", - "translation": "Das eingegebene \"Aktuelle Kennwort\" ist nicht korrekt. Bitte prüfen Sie, dass die Umschalt-Taste deaktiviert ist und versuchen es erneut." + "translation": "Das eingegebene \"Aktuelle Passwort\" ist nicht korrekt. Bitte prüfen Sie, dass die Umschalt-Taste deaktiviert ist und versuchen es erneut." }, { "id": "api.user.update_password.menu", @@ -2773,7 +2773,7 @@ }, { "id": "api.user.update_password.valid_account.app_error", - "translation": "Aktualisieren des Passworts fehlgeschlagen, da kein gültiger Account gefunden werden konnte" + "translation": "Aktualisieren des Passworts fehlgeschlagen, da kein gültiges Konto gefunden werden konnte" }, { "id": "api.user.update_roles.one_admin.app_error", @@ -3689,7 +3689,7 @@ }, { "id": "ent.data_retention.generic.license.error", - "translation": "License does not support Data Retention." + "translation": "Lizenz unterstützt keine Datenaufbewahrung." }, { "id": "ent.elasticsearch.aggregator_worker.create_index_job.error", @@ -3797,7 +3797,7 @@ }, { "id": "ent.ldap.create_fail", - "translation": "Konnte LDAP Benutzer nicht erstellen." + "translation": "Konnte LDAP-Benutzer nicht erstellen." }, { "id": "ent.ldap.disabled.app_error", @@ -3813,7 +3813,7 @@ }, { "id": "ent.ldap.do_login.licence_disable.app_error", - "translation": "AD/LDAP Funktionalität durch die aktuelle Lizenz deaktiviert. Bitte kontaktieren Sie Ihren Systemadministrator wegen eines Enterprise Lizenzupgrades." + "translation": "AD/LDAP-Funktionalität durch die aktuelle Lizenz deaktiviert. Bitte kontaktieren Sie ihren Systemadministrator wegen eines Upgrades ihrer Enterprise-Lizenz." }, { "id": "ent.ldap.do_login.matched_to_many_users.app_error", @@ -3833,7 +3833,7 @@ }, { "id": "ent.ldap.do_login.user_filtered.app_error", - "translation": "Ihr AD/LDAP Account hat keine Berechtigung diesen Mattermost Server zu benutzen. Bitte fragen Sie Ihren Systemadministrator, den AD/LDAP Benutzer Filter zu überprüfen." + "translation": "Ihr AD/LDAP-Konto hat keine Berechtigung diesen Mattermost-Server zu benutzen. Bitten Sie Ihren Systemadministrator den AD/LDAP-Benutzerfilter zu überprüfen." }, { "id": "ent.ldap.do_login.user_not_registered.app_error", @@ -3861,7 +3861,7 @@ }, { "id": "ent.ldap.validate_filter.app_error", - "translation": "Ungültiger AD/LDAP Filter" + "translation": "Ungültiger AD/LDAP-Filter" }, { "id": "ent.metrics.starting.info", @@ -4469,31 +4469,31 @@ }, { "id": "model.config.is_valid.ldap_basedn", - "translation": "AD/LDAP Feld \"BaseDN\" ist erforderlich." + "translation": "AD/LDAP-Feld \"BaseDN\" ist erforderlich." }, { "id": "model.config.is_valid.ldap_bind_password", - "translation": "AD/LDAP Feld \"Bind Passwort\" ist erforderlich." + "translation": "AD/LDAP-Feld \"Bind Passwort\" ist erforderlich." }, { "id": "model.config.is_valid.ldap_bind_username", - "translation": "AD/LDAP Feld \"Bind Benutzername\" ist erforderlich." + "translation": "AD/LDAP-Feld \"Bind Benutzername\" ist erforderlich." }, { "id": "model.config.is_valid.ldap_email", - "translation": "AD/LDAP Feld \"E-Mail Attribut\" ist erforderlich." + "translation": "AD/LDAP-Feld \"E-Mail Attribut\" ist erforderlich." }, { "id": "model.config.is_valid.ldap_firstname", - "translation": "AD/LDAP Feld \"Vornamenattribut\" ist erforderlich." + "translation": "AD/LDAP-Feld \"Vornamenattribut\" ist erforderlich." }, { "id": "model.config.is_valid.ldap_id", - "translation": "AD/LDAP Feld \"ID Attribut\" ist erforderlich." + "translation": "AD/LDAP-Feld \"ID Attribut\" ist erforderlich." }, { "id": "model.config.is_valid.ldap_lastname", - "translation": "AD/LDAP Feld \"Nachnameattribut\" ist erforderlich." + "translation": "AD/LDAP-Feld \"Nachnameattribut\" ist erforderlich." }, { "id": "model.config.is_valid.ldap_max_page_size.app_error", @@ -4501,15 +4501,15 @@ }, { "id": "model.config.is_valid.ldap_required.app_error", - "translation": "Notwendiges AD/LDAP Feld fehlt." + "translation": "Notwendiges AD/LDAP-Feld fehlt." }, { "id": "model.config.is_valid.ldap_required.app_error", - "translation": "Notwendiges AD/LDAP Feld fehlt." + "translation": "Notwendiges AD/LDAP-Feld fehlt." }, { "id": "model.config.is_valid.ldap_security.app_error", - "translation": "Ungültige Verbindungssicherheit in AD/LDAP Einstellungen. Muss '', 'TLS' oder 'STARTTLS' sein" + "translation": "Ungültige Verbindungssicherheit in AD/LDAP-Einstellungen. Muss '', 'TLS' oder 'STARTTLS' sein" }, { "id": "model.config.is_valid.ldap_server", @@ -4521,12 +4521,16 @@ }, { "id": "model.config.is_valid.ldap_username", - "translation": "AD/LDAP Feld \"Benutzername Attribut\" ist erforderlich." + "translation": "AD/LDAP-Feld \"Benutzername Attribut\" ist erforderlich." }, { "id": "model.config.is_valid.listen_address.app_error", "translation": "Ungültige Abhöradresse in Service Einstellungen. Muss gesetzt sein." }, + { + "id": "model.config.is_valid.localization.available_locales.app_error", + "translation": "Verfügbare Sprachen muss Standardsprache des Clients enthalten" + }, { "id": "model.config.is_valid.login_attempts.app_error", "translation": "Ungültige maximale Anzahl an Anmeldeversuchen in Service Einstellungen. Muss eine positive Zahl sein." @@ -5547,6 +5551,10 @@ "id": "store.sql_command.analytics_command_count.app_error", "translation": "Die Anzahl der Befehle konnte nicht gezählt werden" }, + { + "id": "store.sql_command.get_by_trigger.app_error", + "translation": "Der Befehl konnte nicht abgerufen werden" + }, { "id": "store.sql_command.save.delete.app_error", "translation": "Der Befehl konnte nicht gelöscht werden" @@ -6261,23 +6269,23 @@ }, { "id": "store.sql_user.get.app_error", - "translation": "Wir haben ein Problem beim Finden des Accounts" + "translation": "Wir haben ein Problem beim Finden des Kontos" }, { "id": "store.sql_user.get_all_using_auth_service.other.app_error", - "translation": "Es trat ein Fehler beim Suchen nach allen Accounts mit spezifischem Authentifizierungstyp auf." + "translation": "Es trat ein Fehler beim Suchen nach allen Konten mit einem spezifischem Authentifizierungstyp auf." }, { "id": "store.sql_user.get_by_auth.missing_account.app_error", - "translation": "Es konnte kein existierender Account entsprechend Ihres Authentifizierungstyps für dieses Team gefunden werden. Dieses Team erfordert eventuell eine Einladung vom Teambesitzer um beizutreten." + "translation": "Es konnte kein existierende Konto entsprechend Ihres Authentifizierungstyps für dieses Team gefunden werden. Dieses Team erfordert eventuell eine Einladung vom Teambesitzer, um beizutreten." }, { "id": "store.sql_user.get_by_auth.other.app_error", - "translation": "Es trat ein Fehler bei der Suche nach dem Account nach Authentifizierungstyp auf." + "translation": "Es trat ein Fehler bei der Suche nach dem Konto nach Authentifizierungstyp auf." }, { "id": "store.sql_user.get_by_username.app_error", - "translation": "Es konnte kein existierender Account entsprechend Ihres Benutzernamens für dieses Teams gefunden werden. Dieses Team erfordert eventuell eine Einladung vom Teambesitzer um beizutreten." + "translation": "Es konnte kein existierendes Konto entsprechend Ihres Benutzernamens für dieses Teams gefunden werden. Dieses Team erfordert eventuell eine Einladung vom Teambesitzer um beizutreten." }, { "id": "store.sql_user.get_for_login.app_error", @@ -6329,19 +6337,19 @@ }, { "id": "store.sql_user.save.app_error", - "translation": "Der Account konnte nicht gespeichert werden." + "translation": "Das Konto konnte nicht gespeichert werden." }, { "id": "store.sql_user.save.email_exists.app_error", - "translation": "Es gibt bereits einen Account mit dieser E-Mail-Adresse." + "translation": "Es gibt bereits ein Konto mit dieser E-Mail-Adresse." }, { "id": "store.sql_user.save.email_exists.ldap_app_error", - "translation": "Dieser Account verwendet keine AD/LDAP-Authentifizierung. Bitte melden Sie sich mit E-Mail-Adresse und Passwort an." + "translation": "Dieses Konto verwendet keine AD/LDAP-Authentifizierung. Bitte melden Sie sich mit E-Mail-Adresse und Passwort an." }, { "id": "store.sql_user.save.email_exists.saml_app_error", - "translation": "Dieser Account verwendet keine SAML-Authentifizierung. Bitte melden Sie sich mit E-Mail-Adresse und Passwort an." + "translation": "Dieses Konto verwendet keine SAML-Authentifizierung. Bitte melden Sie sich mit E-Mail-Adresse und Passwort an." }, { "id": "store.sql_user.save.existing.app_error", @@ -6349,7 +6357,7 @@ }, { "id": "store.sql_user.save.max_accounts.app_error", - "translation": "Dieses Team hat die maximale Anzahl an erlaubten Accounts erreicht. Kontaktieren Sie Ihren Systemadministrator um ein höheres Limit setzen zu lassen." + "translation": "Dieses Team hat die maximale Anzahl erlaubter Konten erreicht. Kontaktieren Sie Ihren Systemadministrator, um eine höhere Begrenzung setzen zu lassen." }, { "id": "store.sql_user.save.member_count.app_error", @@ -6357,15 +6365,15 @@ }, { "id": "store.sql_user.save.username_exists.app_error", - "translation": "Es gibt bereits einen Account mit diesem Benutzernamen." + "translation": "Es gibt bereits ein Konto mit diesem Benutzernamen." }, { "id": "store.sql_user.save.username_exists.ldap_app_error", - "translation": "Ein Account mit diesem Benutzernamen existiert bereits. Bitte kontaktieren Sie Ihren Administrator." + "translation": "Ein Konto mit diesem Benutzernamen existiert bereits. Bitte kontaktieren Sie Ihren Administrator." }, { "id": "store.sql_user.save.username_exists.saml_app_error", - "translation": "Ein Account mit diesem Benutzernamen existiert bereits. Bitte kontaktieren Sie Ihren Administrator." + "translation": "Ein Konto mit diesem Benutzernamen existiert bereits. Bitte kontaktieren Sie Ihren Administrator." }, { "id": "store.sql_user.update.app_error", @@ -6401,7 +6409,7 @@ }, { "id": "store.sql_user.update_auth_data.email_exists.app_error", - "translation": "Es war nicht möglich den Account zu {{.Service}} zu wechseln. Es existiert bereits ein Account mit der E-Mail-Adresse {{.Email}}." + "translation": "Es war nicht möglich, das Konto zu {{.Service}} zu wechseln. Es existiert bereits ein Konto mit der E-Mail-Adresse {{.Email}}." }, { "id": "store.sql_user.update_failed_pwd_attempts.app_error", @@ -6721,7 +6729,7 @@ }, { "id": "web.claim_account.title", - "translation": "Account beanspruchen" + "translation": "Konto beanspruchen" }, { "id": "web.claim_account.user.error", diff --git a/i18n/en.json b/i18n/en.json index df30fd9d5c..4c09b8ebae 100644 --- a/i18n/en.json +++ b/i18n/en.json @@ -4383,10 +4383,6 @@ "id": "model.config.is_valid.data_retention.message_retention_days_too_low.app_error", "translation": "Message retention must be one day or longer." }, - { - "id": "model.config.is_valid.localization.available_locales.app_error", - "translation": "Available Languages must contain Default Client Language" - }, { "id": "model.config.is_valid.elastic_search.aggregate_posts_after_days.app_error", "translation": "Elasticsearch AggregatePostsAfterDays setting must be a number greater than or equal to 1" @@ -4531,6 +4527,10 @@ "id": "model.config.is_valid.listen_address.app_error", "translation": "Invalid listen address for service settings Must be set." }, + { + "id": "model.config.is_valid.localization.available_locales.app_error", + "translation": "Available Languages must contain Default Client Language" + }, { "id": "model.config.is_valid.login_attempts.app_error", "translation": "Invalid maximum login attempts for service settings. Must be a positive number." @@ -5551,6 +5551,10 @@ "id": "store.sql_command.analytics_command_count.app_error", "translation": "We couldn't count the commands" }, + { + "id": "store.sql_command.get_by_trigger.app_error", + "translation": "We couldn't get the command" + }, { "id": "store.sql_command.save.delete.app_error", "translation": "We couldn't delete the command" @@ -5579,10 +5583,6 @@ "id": "store.sql_command.save.update.app_error", "translation": "We couldn't update the command" }, - { - "id": "store.sql_command.get_by_trigger.app_error", - "translation": "We couldn't get the command" - }, { "id": "store.sql_command_webhooks.get.app_error", "translation": "We couldn't get the webhook" diff --git a/i18n/es.json b/i18n/es.json index ba0e8fcbe8..9b1a82b32c 100644 --- a/i18n/es.json +++ b/i18n/es.json @@ -3689,7 +3689,7 @@ }, { "id": "ent.data_retention.generic.license.error", - "translation": "License does not support Data Retention." + "translation": "La licencia no admite la Retención de Datos." }, { "id": "ent.elasticsearch.aggregator_worker.create_index_job.error", @@ -4527,6 +4527,10 @@ "id": "model.config.is_valid.listen_address.app_error", "translation": "Dirección dónde se escuchará el servicio en la configuracón del servicio debe ser asignada." }, + { + "id": "model.config.is_valid.localization.available_locales.app_error", + "translation": "Los Idiomas disponibles debe contener el idioma del cliente predeterminado" + }, { "id": "model.config.is_valid.login_attempts.app_error", "translation": "Número inválido de máximos intentos de inició de sesión en la configuración del servicio. Debe ser un número positivo." @@ -5547,6 +5551,10 @@ "id": "store.sql_command.analytics_command_count.app_error", "translation": "No pudimos contar los comandos de barra" }, + { + "id": "store.sql_command.get_by_trigger.app_error", + "translation": "No pudimos obtener el comando" + }, { "id": "store.sql_command.save.delete.app_error", "translation": "No pudimos eliminar el comando" diff --git a/i18n/fr.json b/i18n/fr.json index d8b97ac5d7..890e16ac23 100644 --- a/i18n/fr.json +++ b/i18n/fr.json @@ -4527,6 +4527,10 @@ "id": "model.config.is_valid.listen_address.app_error", "translation": "Adresse d'écoute invalide dans les paramètres de service. Doit être renseignée." }, + { + "id": "model.config.is_valid.localization.available_locales.app_error", + "translation": "Available Languages must contain Default Client Language" + }, { "id": "model.config.is_valid.login_attempts.app_error", "translation": "Nombre maximum de tentatives de connexion invalide dans les paramètre de service. Doit être un entier positif." @@ -5547,6 +5551,10 @@ "id": "store.sql_command.analytics_command_count.app_error", "translation": "Impossible de compter les commandes" }, + { + "id": "store.sql_command.get_by_trigger.app_error", + "translation": "Impossible de récupérer la commande" + }, { "id": "store.sql_command.save.delete.app_error", "translation": "Impossible de supprimer la commande" diff --git a/i18n/it.json b/i18n/it.json index 8edcbbd47d..04657ff6d0 100644 --- a/i18n/it.json +++ b/i18n/it.json @@ -3689,7 +3689,7 @@ }, { "id": "ent.data_retention.generic.license.error", - "translation": "License does not support Data Retention." + "translation": "La licenza non supporta la ritenzione dei dati." }, { "id": "ent.elasticsearch.aggregator_worker.create_index_job.error", @@ -4527,6 +4527,10 @@ "id": "model.config.is_valid.listen_address.app_error", "translation": "Indirizzo di ascolto per i servizi non valido Deve essere impostato." }, + { + "id": "model.config.is_valid.localization.available_locales.app_error", + "translation": "Le Lingue Disponibile devono contenere la Lingua di Default per il Client" + }, { "id": "model.config.is_valid.login_attempts.app_error", "translation": "Numero massimo tentativi di login non valido. Deve essere un numero positivo." @@ -5547,6 +5551,10 @@ "id": "store.sql_command.analytics_command_count.app_error", "translation": "Impossibile contare comandi" }, + { + "id": "store.sql_command.get_by_trigger.app_error", + "translation": "Non è possibile trovare il comando" + }, { "id": "store.sql_command.save.delete.app_error", "translation": "Impossibile cancellare comando" diff --git a/i18n/ja.json b/i18n/ja.json index db0d221a8c..8cffb4ec3d 100644 --- a/i18n/ja.json +++ b/i18n/ja.json @@ -3689,7 +3689,7 @@ }, { "id": "ent.data_retention.generic.license.error", - "translation": "License does not support Data Retention." + "translation": "ライセンスはデータ保持をサポートしていません。" }, { "id": "ent.elasticsearch.aggregator_worker.create_index_job.error", @@ -4527,6 +4527,10 @@ "id": "model.config.is_valid.listen_address.app_error", "translation": "サービス設定の接続待ちアドレスが不正です。設定してください。" }, + { + "id": "model.config.is_valid.localization.available_locales.app_error", + "translation": "利用可能な言語はデフォルトのクライアント言語を含んでいなくてはなりません" + }, { "id": "model.config.is_valid.login_attempts.app_error", "translation": "サービス設定の最大ログイン試行回数が不正です。正の数を指定してください。" @@ -5547,6 +5551,10 @@ "id": "store.sql_command.analytics_command_count.app_error", "translation": "コマンド数を数えられませんでした" }, + { + "id": "store.sql_command.get_by_trigger.app_error", + "translation": "コマンドが取得できませんでした" + }, { "id": "store.sql_command.save.delete.app_error", "translation": "コマンドを削除できませんでした" diff --git a/i18n/ko.json b/i18n/ko.json index f39210511f..7baf1545db 100644 --- a/i18n/ko.json +++ b/i18n/ko.json @@ -4527,6 +4527,10 @@ "id": "model.config.is_valid.listen_address.app_error", "translation": "Invalid listen address for service settings Must be set." }, + { + "id": "model.config.is_valid.localization.available_locales.app_error", + "translation": "Available Languages must contain Default Client Language" + }, { "id": "model.config.is_valid.login_attempts.app_error", "translation": "Invalid maximum login attempts for service settings. Must be a positive number." @@ -5547,6 +5551,10 @@ "id": "store.sql_command.analytics_command_count.app_error", "translation": "채널을 찾을 수 없습니다" }, + { + "id": "store.sql_command.get_by_trigger.app_error", + "translation": "채널을 찾을 수 없습니다" + }, { "id": "store.sql_command.save.delete.app_error", "translation": "채널을 찾을 수 없습니다" diff --git a/i18n/nl.json b/i18n/nl.json index 25720589ba..223a2731fa 100644 --- a/i18n/nl.json +++ b/i18n/nl.json @@ -4527,6 +4527,10 @@ "id": "model.config.is_valid.listen_address.app_error", "translation": "Ongeldig luister adres bij de service instellingen. Deze moet geconfigureerd zijn." }, + { + "id": "model.config.is_valid.localization.available_locales.app_error", + "translation": "Available Languages must contain Default Client Language" + }, { "id": "model.config.is_valid.login_attempts.app_error", "translation": "Maximaal aantal inlog poging bij service instellingen. Moet een getal grote dan 0 zijn." @@ -5547,6 +5551,10 @@ "id": "store.sql_command.analytics_command_count.app_error", "translation": "We kunnen de opdrachten niet tellen" }, + { + "id": "store.sql_command.get_by_trigger.app_error", + "translation": "We kunnen de opdracht niet ophalen" + }, { "id": "store.sql_command.save.delete.app_error", "translation": "De opdracht kan niet verwijderd worden" diff --git a/i18n/pl.json b/i18n/pl.json index 8588e9cadd..ceecaeb76c 100644 --- a/i18n/pl.json +++ b/i18n/pl.json @@ -1,7 +1,7 @@ [ { "id": "April", - "translation": "kwiecień" + "translation": "Kwiecień" }, { "id": "August", @@ -185,11 +185,11 @@ }, { "id": "api.channel.can_manage_channel.private_restricted_system_admin.app_error", - "translation": "Zarządzanie i tworzenie kanałów prywatnych jest dostępne tylko dla Administratorów Systemu." + "translation": "Zarządzanie i tworzenie kanałów prywatnych jest dostępne tylko dla administratorów systemu." }, { "id": "api.channel.can_manage_channel.private_restricted_team_admin.app_error", - "translation": "Zarządzanie i tworzenie kanałów prywatnych jest dostępne tylko dla Zespołów i Administratorów Systemu." + "translation": "Zarządzanie i tworzenie kanałów prywatnych jest dostępne tylko dla administratorów systemu i zespołów." }, { "id": "api.channel.can_manage_channel.public_restricted_system_admin.app_error", @@ -861,7 +861,7 @@ }, { "id": "api.command_shortcuts.unsupported.app_error", - "translation": "Polecenie wyszukiwania nie jest wspierana na Twoim urządzeniu" + "translation": "Polecenie skrótu nie jest wspierane na Twoim urządzeniu" }, { "id": "api.command_shrug.desc", @@ -1103,7 +1103,7 @@ }, { "id": "api.file.get_file.public_disabled.app_error", - "translation": "Linki publiczne zapisu została wyłączona przez administratora systemu." + "translation": "Linki publiczne zostały wyłączone przez administratora systemu." }, { "id": "api.file.get_file.public_invalid.app_error", @@ -1587,7 +1587,7 @@ }, { "id": "api.post.do_action.action_id.app_error", - "translation": "Nieprawidłowy identyfikator klienta" + "translation": "Nieprawidłowe id akcji" }, { "id": "api.post.do_action.action_integration.app_error", @@ -1697,7 +1697,7 @@ }, { "id": "api.post.send_notifications_and_forget.push_mention_no_channel", - "translation": " wspomniał o Tobie w " + "translation": "wspomniał cię" }, { "id": "api.post.send_notifications_and_forget.push_message", @@ -1857,7 +1857,7 @@ }, { "id": "api.slackimport.slack_add_channels.added", - "translation": "\r\n kanały dodane \r\n" + "translation": "\r\nDodane kanały:\r\n" }, { "id": "api.slackimport.slack_add_channels.failed_to_add_user", @@ -1929,7 +1929,7 @@ }, { "id": "api.slackimport.slack_add_users.created", - "translation": "\r\n użytkowników zostało utworzonych\r\n" + "translation": "\r\nUtworzeni użytkownicy:\r\n" }, { "id": "api.slackimport.slack_add_users.email_pwd", @@ -1945,7 +1945,7 @@ }, { "id": "api.slackimport.slack_add_users.missing_email_address", - "translation": "Użytkownik {{.Username}} nie posiada adresu email w Slack export. Użyto {{.Email}} jako zastępnik. Użytkownik powinien zaktualizować adres email po zalogowaniu do systemu.\r\n" + "translation": "Użytkownik {{.Username}} nie ma adresu e-mail w eksporcie Slacka. Użyto {{.Email}} jako placeholdera. Użytkownik powinien zaktualizować adres po zalogowaniu.\r\n" }, { "id": "api.slackimport.slack_add_users.missing_email_address.warn", @@ -1953,7 +1953,7 @@ }, { "id": "api.slackimport.slack_add_users.unable_import", - "translation": "Nie można zaimportować użytkownika: {{.Username}}\r\n" + "translation": "Nie można zaimportować użytkownika: {{.Username}}.\r\n" }, { "id": "api.slackimport.slack_convert_channel_mentions.compile_regexp_failed.warn", @@ -1965,11 +1965,11 @@ }, { "id": "api.slackimport.slack_convert_user_mentions.compile_regexp_failed.warn", - "translation": "Slack Import: Nie można sakompilować !channel, pasującego do regular expressions dla kanału Slacka {{.ChannelName}} (id={{.ChannelID}})." + "translation": "Slack Import: Nie można skompilować @mention, pasującej do regular expressions dla kanału Slacka {{.ChannelName}} (id={{.ChannelID}})." }, { "id": "api.slackimport.slack_deactivate_bot_user.failed_to_deactivate", - "translation": "Slack Import: Unable to deactivate the user account used for the bot." + "translation": "Slack Import: Nie można zdezaktywować konta użytkownika używanego przez bota." }, { "id": "api.slackimport.slack_import.log", @@ -1993,7 +1993,7 @@ }, { "id": "api.slackimport.slack_import.open.app_error", - "translation": "Unable to open the file: {{.Filename}}.\r\n" + "translation": "Nie można otworzyć pliku: {{.Filename}}.\r\n" }, { "id": "api.slackimport.slack_import.team_fail", @@ -2001,15 +2001,15 @@ }, { "id": "api.slackimport.slack_import.zip.app_error", - "translation": "Unable to open the Slack export zip file.\r\n" + "translation": "Nie można otworzyć pliku zip z eksportem Slacka.\r\n" }, { "id": "api.slackimport.slack_parse_channels.error", - "translation": "Slack Import: Error occurred when parsing some Slack channels. Import may work anyway." + "translation": "Slack Import: Wystąpił błąd parsowania kanałów Slacka. Import może działać pomimo tego." }, { "id": "api.slackimport.slack_parse_posts.error", - "translation": "Slack Import: Error occurred when parsing some Slack posts. Import may work anyway." + "translation": "Slack Import: Wystąpił błąd parsowania postów Slacka. Import może działać pomimo tego." }, { "id": "api.slackimport.slack_sanitise_channel_properties.display_name_too_long.warn", @@ -2125,7 +2125,7 @@ }, { "id": "api.team.invite_members.invalid_email.app_error", - "translation": "The following email addresses do not belong to an accepted domain: {{.Addresses}}. Please contact your System Administrator for details." + "translation": "Następujące adresy e-mail nie należą do akceptowanej domeny: {{.Addresses}}. Skontaktuj się z administratorem systemu, by dowiedzieć się więcej." }, { "id": "api.team.invite_members.member", @@ -2141,7 +2141,7 @@ }, { "id": "api.team.invite_members.restricted_team_admin.app_error", - "translation": "Zapraszanie nowych użytkowników do zespołu ogranicza się do zespołu i administratorów systemu." + "translation": "Zapraszanie nowych użytkowników do zespołu ogranicza się do administratorów systemu i zespołu." }, { "id": "api.team.invite_members.send.error", @@ -2157,7 +2157,7 @@ }, { "id": "api.team.is_team_creation_allowed.domain.app_error", - "translation": "List musi być z określonej domeny (np. @example.com). Proszę, skontaktuj się z administratorem systemu, aby poznać szczegóły." + "translation": "E-mail musi być z określonej domeny (np. @example.com). Proszę, skontaktuj się z administratorem systemu, aby poznać szczegóły." }, { "id": "api.team.permanent_delete_team.attempting.warn", @@ -2189,7 +2189,7 @@ }, { "id": "api.templates.email_change_body.info", - "translation": "Twój adres e-mail {{.TeamDisplayName}} został zmieniony na {{.NewEmail}}.
Jeśli nie to proszę, skontaktuj się z administratorem systemu." + "translation": "Twój adres e-mail na {{.TeamDisplayName}} został zmieniony na {{.NewEmail}}.
Jeśli to nie ty dokonałeś tej zmiany, skontaktuj się z administratorem systemu." }, { "id": "api.templates.email_change_body.title", @@ -2357,15 +2357,15 @@ }, { "id": "api.templates.user_access_token_body.info", - "translation": "A personal access token was added to your account on {{ .SiteURL }}. They can be used to access {{.SiteName}} with your account.
If this change wasn't initiated by you, please contact your system administrator." + "translation": "Osobisty token dostępu został dodany do twojego konta na {{ .SiteURL }}. Można ich użyć by logować się na {{.SiteName}} przy użyciu twojego konta.
Jeżeli ta zmiana nie została dokonana przez ciebie, skontaktuj się z administratorem systemu." }, { "id": "api.templates.user_access_token_body.title", - "translation": "Personal access token added to your account" + "translation": "Osobisty token dostępu został dodany do twojego konta" }, { "id": "api.templates.user_access_token_subject", - "translation": "[{{ .SiteName }}] Personal access token added to your account" + "translation": "[{{ .SiteName }}] Osobisty token dostępu został dodany do twojego konta" }, { "id": "api.templates.username_change_body.info", @@ -2981,7 +2981,7 @@ }, { "id": "app.channel.move_channel.members_do_not_match.error", - "translation": "Cannot move a channel unless all its members are already members of the destination team." + "translation": "Nie można przenieść kanału, dopóki wszyscy jego członkowie nie są członkami zespołu docelowego." }, { "id": "app.channel.post_update_channel_purpose_message.post.error", @@ -3045,7 +3045,7 @@ }, { "id": "app.import.import_direct_post.save_preferences.error", - "translation": "Error importing direct post. Failed to save preferences." + "translation": "Wystąpił błąd podczas importowania wiadomości bezpośrednich. Nie udało się zapisać preferencji." }, { "id": "app.import.import_direct_post.user_not_found.error", @@ -3085,7 +3085,7 @@ }, { "id": "app.import.import_post.save_preferences.error", - "translation": "Error importing post. Failed to save preferences." + "translation": "Wystąpił błąd podczas importowania wiadomości. Nie udało się zapisać preferencji." }, { "id": "app.import.import_post.team_not_found.error", @@ -3097,7 +3097,7 @@ }, { "id": "app.import.import_user_channels.save_preferences.error", - "translation": "Error importing user channel memberships. Failed to save preferences." + "translation": "Wystąpił błąd podczas importowania przynależności użytkowników do kanałów. Nie udało się zapisać preferencji." }, { "id": "app.import.validate_channel_import_data.create_at_zero.error", @@ -3161,7 +3161,7 @@ }, { "id": "app.import.validate_direct_channel_import_data.unknown_favoriter.error", - "translation": "Direct channel can only be favorited by members. \"{{.Username}}\" is not a member." + "translation": "Kanał bezpośredni może być polubiony tylko przez członków. \"{{.Username}}\" nie jest członkiem." }, { "id": "app.import.validate_direct_post_import_data.channel_members_required.error", @@ -3181,7 +3181,7 @@ }, { "id": "app.import.validate_direct_post_import_data.create_at_zero.error", - "translation": "CreateAt must be greater than 0" + "translation": "CreateAt musi być większe od 0" }, { "id": "app.import.validate_direct_post_import_data.message_length.error", @@ -3193,7 +3193,7 @@ }, { "id": "app.import.validate_direct_post_import_data.unknown_flagger.error", - "translation": "Direct post can only be flagged by members of the channel it is in. \"{{.Username}}\" is not a member." + "translation": "Bezpośrednia wiadomość może być oznaczona tylko przez członków kanału, w którym się znajduje. \"{{.Username}}\" nie jest członkiem." }, { "id": "app.import.validate_direct_post_import_data.user_missing.error", @@ -3325,11 +3325,11 @@ }, { "id": "app.import.validate_user_import_data.notify_props_channel_trigger_invalid.error", - "translation": "Invalid Channel Trigger Notify Prop for user." + "translation": "Nieprawidłowy ciąg znaków powiadamiania o kanale dla użytkownika." }, { "id": "app.import.validate_user_import_data.notify_props_comment_trigger_invalid.error", - "translation": "Invalid Comment Trigger Notify Prop for user." + "translation": "Nieprawidłowy ciąg znaków powiadamiania o komentarzu dla użytkownika." }, { "id": "app.import.validate_user_import_data.notify_props_desktop_duration_invalid.error", @@ -4527,6 +4527,10 @@ "id": "model.config.is_valid.listen_address.app_error", "translation": "Nieprawidłowy adres nasłuchiwania dla ustawień usługi." }, + { + "id": "model.config.is_valid.localization.available_locales.app_error", + "translation": "Available Languages must contain Default Client Language" + }, { "id": "model.config.is_valid.login_attempts.app_error", "translation": "Nieprawidłowa maksymalna ilość prób logowania dla ustawień usługi. Musi być liczbą większą od 0." @@ -5547,6 +5551,10 @@ "id": "store.sql_command.analytics_command_count.app_error", "translation": "Nie możemy policzyć poleceń" }, + { + "id": "store.sql_command.get_by_trigger.app_error", + "translation": "Nie można pobrać polecenia" + }, { "id": "store.sql_command.save.delete.app_error", "translation": "Nie można usunąć polecenia" diff --git a/i18n/pt-BR.json b/i18n/pt-BR.json index 29b500ad8e..d4b66e90c9 100644 --- a/i18n/pt-BR.json +++ b/i18n/pt-BR.json @@ -3689,7 +3689,7 @@ }, { "id": "ent.data_retention.generic.license.error", - "translation": "License does not support Data Retention." + "translation": "Licença não suporta Retenção de Dados." }, { "id": "ent.elasticsearch.aggregator_worker.create_index_job.error", @@ -4527,6 +4527,10 @@ "id": "model.config.is_valid.listen_address.app_error", "translation": "Inválido endereço de escuta em configurações de serviço Deve ser ajustado." }, + { + "id": "model.config.is_valid.localization.available_locales.app_error", + "translation": "Idiomas Disponíveis devem conter Idioma Padrão do Cliente" + }, { "id": "model.config.is_valid.login_attempts.app_error", "translation": "Inválido máxima tentativas de login em configurações de serviço. Deve ser um número positivo." @@ -5547,6 +5551,10 @@ "id": "store.sql_command.analytics_command_count.app_error", "translation": "Não foi possível contar os comandos" }, + { + "id": "store.sql_command.get_by_trigger.app_error", + "translation": "Não foi possível obter o comando" + }, { "id": "store.sql_command.save.delete.app_error", "translation": "Não foi possível deletar o comando" diff --git a/i18n/ru.json b/i18n/ru.json index 72e8f2fa4b..8adb44b165 100644 --- a/i18n/ru.json +++ b/i18n/ru.json @@ -4527,6 +4527,10 @@ "id": "model.config.is_valid.listen_address.app_error", "translation": "Неверный адрес прослушивания в настройках службы. Должен быть задан." }, + { + "id": "model.config.is_valid.localization.available_locales.app_error", + "translation": "Available Languages must contain Default Client Language" + }, { "id": "model.config.is_valid.login_attempts.app_error", "translation": "Неверное максимальное количество попыток входа в настройках службы. Должно быть положительным числом." @@ -5547,6 +5551,10 @@ "id": "store.sql_command.analytics_command_count.app_error", "translation": "Не удалось подсчитать команды" }, + { + "id": "store.sql_command.get_by_trigger.app_error", + "translation": "Не удалось получить команду" + }, { "id": "store.sql_command.save.delete.app_error", "translation": "Безуспешная попытка удалить команду" diff --git a/i18n/tr.json b/i18n/tr.json index e332f9e43c..77a9cb6899 100644 --- a/i18n/tr.json +++ b/i18n/tr.json @@ -3689,7 +3689,7 @@ }, { "id": "ent.data_retention.generic.license.error", - "translation": "License does not support Data Retention." + "translation": "Lisans Veri Yedeklemeyi kapsamıyor." }, { "id": "ent.elasticsearch.aggregator_worker.create_index_job.error", @@ -4527,6 +4527,10 @@ "id": "model.config.is_valid.listen_address.app_error", "translation": "Dinleme adresi hizmet ayarı geçersiz. Ayarlanmalı." }, + { + "id": "model.config.is_valid.localization.available_locales.app_error", + "translation": "Varsayılan İstemci Dili kullanılabilecek diller arasında bulunmalıdır." + }, { "id": "model.config.is_valid.login_attempts.app_error", "translation": "En fazla oturum açma girişimi hizmet ayarı geçersiz. Pozitif bir sayı olmalıdır." @@ -5547,6 +5551,10 @@ "id": "store.sql_command.analytics_command_count.app_error", "translation": "Komutlar sayılamadı" }, + { + "id": "store.sql_command.get_by_trigger.app_error", + "translation": "Komut alınamadı" + }, { "id": "store.sql_command.save.delete.app_error", "translation": "Komut silinemedi" diff --git a/i18n/zh-CN.json b/i18n/zh-CN.json index 33556f6a21..820e0a1fba 100644 --- a/i18n/zh-CN.json +++ b/i18n/zh-CN.json @@ -3597,7 +3597,7 @@ }, { "id": "cli.license.critical", - "translation": "Feature requires an upgrade to Enterprise Edition and the inclusion of a license key. Please contact your System Administrator." + "translation": "功能需要升级到企业版本并拥有许可证。请联系您的系统管理员。" }, { "id": "ent.brand.save_brand_image.decode.app_error", @@ -3689,7 +3689,7 @@ }, { "id": "ent.data_retention.generic.license.error", - "translation": "License does not support Data Retention." + "translation": "许可证不支持数据保留。" }, { "id": "ent.elasticsearch.aggregator_worker.create_index_job.error", @@ -3845,11 +3845,11 @@ }, { "id": "ent.ldap.sync.index_job_failed.error", - "translation": "LDAP sync worker failed due to the sync job failing" + "translation": "LDAP 同步工作者失败因为同步任务失败" }, { "id": "ent.ldap.sync_worker.create_index_job.error", - "translation": "LDAP sync worker failed to create the sync job" + "translation": "LDAP 同步工作者创建同步任务失败" }, { "id": "ent.ldap.syncdone.info", @@ -4373,15 +4373,15 @@ }, { "id": "model.config.is_valid.data_retention.deletion_job_start_time.app_error", - "translation": "Data retention job start time must be a 24-hour time stamp in the form HH:MM." + "translation": "数据保留任务开始时间必须为 24 小时制并格式为 HH:MM。" }, { "id": "model.config.is_valid.data_retention.file_retention_days_too_low.app_error", - "translation": "File retention must be one day or longer." + "translation": "文件保留至少一天。" }, { "id": "model.config.is_valid.data_retention.message_retention_days_too_low.app_error", - "translation": "Message retention must be one day or longer." + "translation": "消息保留至少一天。" }, { "id": "model.config.is_valid.elastic_search.aggregate_posts_after_days.app_error", @@ -4527,6 +4527,10 @@ "id": "model.config.is_valid.listen_address.app_error", "translation": "无效的服务设置时监听地址,必须设置此项。" }, + { + "id": "model.config.is_valid.localization.available_locales.app_error", + "translation": "可选语言必须包含默认客户端语言" + }, { "id": "model.config.is_valid.login_attempts.app_error", "translation": "无效的最大尝试登录数服务设置。必须是正整数。" @@ -5289,15 +5293,15 @@ }, { "id": "store.sql_audit.permanent_delete_batch.app_error", - "translation": "We encountered an error permanently deleting the batch of audits" + "translation": "批量永久删除审计时遇到错误" }, { "id": "store.sql_audit.permanent_delete_by_user.app_error", - "translation": "我们删除审核时遇到了一个错误" + "translation": "我们删除审计时遇到了一个错误" }, { "id": "store.sql_audit.save.saving.app_error", - "translation": "我们保持审核时出错" + "translation": "我们保存审计时遇到错误" }, { "id": "store.sql_channel.analytics_deleted_type_count.app_error", @@ -5547,6 +5551,10 @@ "id": "store.sql_command.analytics_command_count.app_error", "translation": "我们无法计算指令数量" }, + { + "id": "store.sql_command.get_by_trigger.app_error", + "translation": "我们无法获取这个命令" + }, { "id": "store.sql_command.save.delete.app_error", "translation": "我们无法删除命令" @@ -5653,7 +5661,7 @@ }, { "id": "store.sql_file_info.permanent_delete_batch.app_error", - "translation": "We encountered an error permanently deleting the batch of file infos" + "translation": "批量永久删除文件信息时遇到错误" }, { "id": "store.sql_file_info.save.app_error", @@ -5677,11 +5685,11 @@ }, { "id": "store.sql_job.get_count_by_status_and_type.app_erro", - "translation": "We couldn't get the job count by status and type" + "translation": "我们无法以状态和类型获取任务数" }, { "id": "store.sql_job.get_newest_job_by_status_and_type.app_error", - "translation": "We couldn't get the newest job by status and type" + "translation": "我们无法以状态和类型获取最新任务" }, { "id": "store.sql_job.save.app_error", @@ -5873,11 +5881,11 @@ }, { "id": "store.sql_post.permanent_delete_batch.app_error", - "translation": "We encountered an error permanently deleting the batch of posts" + "translation": "批量永久删除消息时遇到错误" }, { "id": "store.sql_post.permanent_delete_batch.app_error", - "translation": "We encountered an error permanently deleting the batch of posts" + "translation": "批量永久删除消息时遇到错误" }, { "id": "store.sql_post.permanent_delete_by_channel.app_error", @@ -5913,7 +5921,7 @@ }, { "id": "store.sql_preference.cleanup_flags_batch.app_error", - "translation": "We encountered an error cleaning up the batch of flags" + "translation": "清理批量标记时遇到错误" }, { "id": "store.sql_preference.delete.app_error", @@ -6005,7 +6013,7 @@ }, { "id": "store.sql_reaction.permanent_delete_batch.app_error", - "translation": "We encountered an error permanently deleting the batch of reactions" + "translation": "批量永久删除反应时遇到错误" }, { "id": "store.sql_reaction.save.begin.app_error", diff --git a/i18n/zh-TW.json b/i18n/zh-TW.json index 90e244f411..012ffae2ac 100644 --- a/i18n/zh-TW.json +++ b/i18n/zh-TW.json @@ -3441,7 +3441,7 @@ }, { "id": "app.plugin.filesystem.app_error", - "translation": "Encountered filesystem error" + "translation": "遇到檔案系統錯誤" }, { "id": "app.plugin.get_plugins.app_error", @@ -3597,7 +3597,7 @@ }, { "id": "cli.license.critical", - "translation": "Feature requires an upgrade to Enterprise Edition and the inclusion of a license key. Please contact your System Administrator." + "translation": "功能需要升級至企業版並加入授權碼。請聯絡系統管理員。" }, { "id": "ent.brand.save_brand_image.decode.app_error", @@ -3689,7 +3689,7 @@ }, { "id": "ent.data_retention.generic.license.error", - "translation": "License does not support Data Retention." + "translation": "現有授權不支援資料保留。" }, { "id": "ent.elasticsearch.aggregator_worker.create_index_job.error", @@ -3729,7 +3729,7 @@ }, { "id": "ent.elasticsearch.data_retention_delete_indexes.get_indexes.error", - "translation": "建立 Elasticsearch 索引時失敗" + "translation": "取得 Elasticsearch 索引時失敗" }, { "id": "ent.elasticsearch.delete_post.error", @@ -3845,11 +3845,11 @@ }, { "id": "ent.ldap.sync.index_job_failed.error", - "translation": "LDAP sync worker failed due to the sync job failing" + "translation": "由於同步工作失敗,LDAP 同步工作失敗。" }, { "id": "ent.ldap.sync_worker.create_index_job.error", - "translation": "LDAP sync worker failed to create the sync job" + "translation": "LDAP 同步工作無法建立同步工作" }, { "id": "ent.ldap.syncdone.info", @@ -4373,15 +4373,15 @@ }, { "id": "model.config.is_valid.data_retention.deletion_job_start_time.app_error", - "translation": "Data retention job start time must be a 24-hour time stamp in the form HH:MM." + "translation": "資料保留工作起始時間必須為 HH:MM 格式的 24 小時時間戳記。" }, { "id": "model.config.is_valid.data_retention.file_retention_days_too_low.app_error", - "translation": "File retention must be one day or longer." + "translation": "檔案保留需至少一天。" }, { "id": "model.config.is_valid.data_retention.message_retention_days_too_low.app_error", - "translation": "Message retention must be one day or longer." + "translation": "訊息保留需至少一天。" }, { "id": "model.config.is_valid.elastic_search.aggregate_posts_after_days.app_error", @@ -4527,6 +4527,10 @@ "id": "model.config.is_valid.listen_address.app_error", "translation": "服務設定中的聆聽位址無效。此項目必須設定" }, + { + "id": "model.config.is_valid.localization.available_locales.app_error", + "translation": "可用的語言必須包含用戶端預設語言" + }, { "id": "model.config.is_valid.login_attempts.app_error", "translation": "服務設定中的最多登入嘗試次數無效。必須為正數." @@ -5289,7 +5293,7 @@ }, { "id": "store.sql_audit.permanent_delete_batch.app_error", - "translation": "We encountered an error permanently deleting the batch of audits" + "translation": "永久批次刪除稽核時遇到錯誤" }, { "id": "store.sql_audit.permanent_delete_by_user.app_error", @@ -5547,6 +5551,10 @@ "id": "store.sql_command.analytics_command_count.app_error", "translation": "無法計算命令數量" }, + { + "id": "store.sql_command.get_by_trigger.app_error", + "translation": "無法取得命令" + }, { "id": "store.sql_command.save.delete.app_error", "translation": "無法刪除命令" @@ -5653,7 +5661,7 @@ }, { "id": "store.sql_file_info.permanent_delete_batch.app_error", - "translation": "We encountered an error permanently deleting the batch of file infos" + "translation": "永久批次刪除檔案資訊時遇到錯誤" }, { "id": "store.sql_file_info.save.app_error", @@ -5677,11 +5685,11 @@ }, { "id": "store.sql_job.get_count_by_status_and_type.app_erro", - "translation": "We couldn't get the job count by status and type" + "translation": "無法根據狀態與類型取得工作數量" }, { "id": "store.sql_job.get_newest_job_by_status_and_type.app_error", - "translation": "We couldn't get the newest job by status and type" + "translation": "無法根據狀態與類型取得最新工作" }, { "id": "store.sql_job.save.app_error", @@ -5873,11 +5881,11 @@ }, { "id": "store.sql_post.permanent_delete_batch.app_error", - "translation": "We encountered an error permanently deleting the batch of posts" + "translation": "永久批次刪除訊息時遇到錯誤" }, { "id": "store.sql_post.permanent_delete_batch.app_error", - "translation": "We encountered an error permanently deleting the batch of posts" + "translation": "永久批次刪除訊息時遇到錯誤" }, { "id": "store.sql_post.permanent_delete_by_channel.app_error", @@ -5913,7 +5921,7 @@ }, { "id": "store.sql_preference.cleanup_flags_batch.app_error", - "translation": "We encountered an error cleaning up the batch of flags" + "translation": "永久批次清除標記時遇到錯誤" }, { "id": "store.sql_preference.delete.app_error", @@ -6005,7 +6013,7 @@ }, { "id": "store.sql_reaction.permanent_delete_batch.app_error", - "translation": "We encountered an error permanently deleting the batch of reactions" + "translation": "永久批次刪除回應時遇到錯誤" }, { "id": "store.sql_reaction.save.begin.app_error", @@ -6585,15 +6593,15 @@ }, { "id": "utils.file.list_directory.configured.app_error", - "translation": "檔案儲存位置設定不正確。請設定為 S3 或是本地儲存。" + "translation": "檔案儲存位置設定不正確。請設定為 S3 或是本地伺服器檔案儲存空間。" }, { "id": "utils.file.list_directory.local.app_error", - "translation": "從本地儲存讀取時遇到錯誤" + "translation": "從本地伺服器儲存空間表列目錄時遇到錯誤" }, { "id": "utils.file.list_directory.s3.app_error", - "translation": "從 S3 刪除目錄時遇到錯誤" + "translation": "從 S3 表列目錄時遇到錯誤" }, { "id": "utils.file.remove_directory.configured.app_error", @@ -6781,11 +6789,11 @@ }, { "id": "web.error.unsupported_browser.message", - "translation": "Your current browser is not supported. Please upgrade to one of the following browsers:" + "translation": "當前的瀏覽器不被支援。請升級至下列瀏覽器之一:" }, { "id": "web.error.unsupported_browser.title", - "translation": "Unsupported Browser" + "translation": "不支援的瀏覽器" }, { "id": "web.find_team.title", From 675f13c808f4fe0f8a39e75f27d4471eb0680cd9 Mon Sep 17 00:00:00 2001 From: Christopher Speller Date: Wed, 11 Oct 2017 09:47:59 -0700 Subject: [PATCH 5/8] Fixing LDAP and SAML settings detection (#7605) --- utils/config.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/utils/config.go b/utils/config.go index c4ffbc8e0a..2a956dd4a0 100644 --- a/utils/config.go +++ b/utils/config.go @@ -518,9 +518,9 @@ func getClientConfig(c *model.Config) map[string]string { if *License.Features.LDAP { props["EnableLdap"] = strconv.FormatBool(*c.LdapSettings.Enable) props["LdapLoginFieldName"] = *c.LdapSettings.LoginFieldName - props["NicknameAttributeSet"] = strconv.FormatBool(*c.LdapSettings.NicknameAttribute != "") - props["FirstNameAttributeSet"] = strconv.FormatBool(*c.LdapSettings.FirstNameAttribute != "") - props["LastNameAttributeSet"] = strconv.FormatBool(*c.LdapSettings.LastNameAttribute != "") + props["LdapNicknameAttributeSet"] = strconv.FormatBool(*c.LdapSettings.NicknameAttribute != "") + props["LdapFirstNameAttributeSet"] = strconv.FormatBool(*c.LdapSettings.FirstNameAttribute != "") + props["LdapLastNameAttributeSet"] = strconv.FormatBool(*c.LdapSettings.LastNameAttribute != "") } if *License.Features.MFA { @@ -535,9 +535,9 @@ func getClientConfig(c *model.Config) map[string]string { if *License.Features.SAML { props["EnableSaml"] = strconv.FormatBool(*c.SamlSettings.Enable) props["SamlLoginButtonText"] = *c.SamlSettings.LoginButtonText - props["FirstNameAttributeSet"] = strconv.FormatBool(*c.SamlSettings.FirstNameAttribute != "") - props["LastNameAttributeSet"] = strconv.FormatBool(*c.SamlSettings.LastNameAttribute != "") - props["NicknameAttributeSet"] = strconv.FormatBool(*c.SamlSettings.NicknameAttribute != "") + props["SamlFirstNameAttributeSet"] = strconv.FormatBool(*c.SamlSettings.FirstNameAttribute != "") + props["SamlLastNameAttributeSet"] = strconv.FormatBool(*c.SamlSettings.LastNameAttribute != "") + props["SamlNicknameAttributeSet"] = strconv.FormatBool(*c.SamlSettings.NicknameAttribute != "") } if *License.Features.Cluster { From aa2b82727f0f1b3edb79f6d31c04b8fd0d718455 Mon Sep 17 00:00:00 2001 From: Chris Date: Wed, 11 Oct 2017 12:16:04 -0700 Subject: [PATCH 6/8] fix race condition in tests (#7609) --- api/apitestlib.go | 16 ++++++++++++++++ api4/apitestlib.go | 16 ++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/api/apitestlib.go b/api/apitestlib.go index 3c64d24304..a38c20813a 100644 --- a/api/apitestlib.go +++ b/api/apitestlib.go @@ -4,6 +4,7 @@ package api import ( + "net" "strings" "time" @@ -86,7 +87,20 @@ func ReloadConfigForSetup() { *utils.Cfg.TeamSettings.EnableOpenServer = true } +func (me *TestHelper) waitForConnectivity() { + for i := 0; i < 1000; i++ { + _, err := net.Dial("tcp", "localhost"+*utils.Cfg.ServiceSettings.ListenAddress) + if err == nil { + return + } + time.Sleep(time.Millisecond * 20) + } + panic("unable to connect") +} + func (me *TestHelper) InitBasic() *TestHelper { + me.waitForConnectivity() + me.BasicClient = me.CreateClient() me.BasicUser = me.CreateUser(me.BasicClient) me.LoginBasic() @@ -106,6 +120,8 @@ func (me *TestHelper) InitBasic() *TestHelper { } func (me *TestHelper) InitSystemAdmin() *TestHelper { + me.waitForConnectivity() + me.SystemAdminClient = me.CreateClient() me.SystemAdminUser = me.CreateUser(me.SystemAdminClient) me.SystemAdminUser.Password = "Password1" diff --git a/api4/apitestlib.go b/api4/apitestlib.go index f3c9c16341..f50095f79b 100644 --- a/api4/apitestlib.go +++ b/api4/apitestlib.go @@ -7,6 +7,7 @@ import ( "bytes" "fmt" "io" + "net" "net/http" "os" "reflect" @@ -151,7 +152,20 @@ func (me *TestHelper) TearDown() { utils.EnableDebugLogForTest() } +func (me *TestHelper) waitForConnectivity() { + for i := 0; i < 1000; i++ { + _, err := net.Dial("tcp", "localhost"+*utils.Cfg.ServiceSettings.ListenAddress) + if err == nil { + return + } + time.Sleep(time.Millisecond * 20) + } + panic("unable to connect") +} + func (me *TestHelper) InitBasic() *TestHelper { + me.waitForConnectivity() + me.TeamAdminUser = me.CreateUser() me.LoginTeamAdmin() me.BasicTeam = me.CreateTeam() @@ -176,6 +190,8 @@ func (me *TestHelper) InitBasic() *TestHelper { } func (me *TestHelper) InitSystemAdmin() *TestHelper { + me.waitForConnectivity() + me.SystemAdminUser = me.CreateUser() me.App.UpdateUserRoles(me.SystemAdminUser.Id, model.ROLE_SYSTEM_USER.Id+" "+model.ROLE_SYSTEM_ADMIN.Id) me.LoginSystemAdmin() From 8966452d1183e94fecc373b9d08c65a0573cbbc6 Mon Sep 17 00:00:00 2001 From: Chris Date: Thu, 12 Oct 2017 15:23:33 -0700 Subject: [PATCH 7/8] workaround for go smtp bug (#7620) --- utils/mail.go | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/utils/mail.go b/utils/mail.go index 7be1303d1b..9bda4ee39a 100644 --- a/utils/mail.go +++ b/utils/mail.go @@ -7,14 +7,13 @@ import ( "crypto/tls" "mime" "net" + "net/http" "net/mail" "net/smtp" "time" "gopkg.in/gomail.v2" - "net/http" - l4g "github.com/alecthomas/log4go" "github.com/mattermost/html2text" "github.com/mattermost/mattermost-server/model" @@ -48,6 +47,20 @@ func connectToSMTPServer(config *model.Config) (net.Conn, *model.AppError) { return conn, nil } +// TODO: Remove once this bug is fixed: https://github.com/golang/go/issues/22166 +type plainAuthOverTLSConn struct { + smtp.Auth +} + +func PlainAuthOverTLSConn(identity, username, password, host string) smtp.Auth { + return &plainAuthOverTLSConn{smtp.PlainAuth(identity, username, password, host)} +} + +func (a *plainAuthOverTLSConn) Start(server *smtp.ServerInfo) (string, []byte, error) { + server.TLS = true + return a.Auth.Start(server) +} + func newSMTPClient(conn net.Conn, config *model.Config) (*smtp.Client, *model.AppError) { c, err := smtp.NewClient(conn, config.EmailSettings.SMTPServer+":"+config.EmailSettings.SMTPPort) if err != nil { @@ -73,7 +86,12 @@ func newSMTPClient(conn net.Conn, config *model.Config) (*smtp.Client, *model.Ap } if *config.EmailSettings.EnableSMTPAuth { - auth := smtp.PlainAuth("", config.EmailSettings.SMTPUsername, config.EmailSettings.SMTPPassword, config.EmailSettings.SMTPServer+":"+config.EmailSettings.SMTPPort) + var auth smtp.Auth + if _, ok := conn.(*tls.Conn); ok { + auth = PlainAuthOverTLSConn("", config.EmailSettings.SMTPUsername, config.EmailSettings.SMTPPassword, config.EmailSettings.SMTPServer+":"+config.EmailSettings.SMTPPort) + } else { + auth = smtp.PlainAuth("", config.EmailSettings.SMTPUsername, config.EmailSettings.SMTPPassword, config.EmailSettings.SMTPServer+":"+config.EmailSettings.SMTPPort) + } if err = c.Auth(auth); err != nil { return nil, model.NewAppError("SendMail", "utils.mail.new_client.auth.app_error", nil, err.Error(), http.StatusInternalServerError) From 8bf47c1211d09079fd9407555026b7b29383ac37 Mon Sep 17 00:00:00 2001 From: JoramWilander Date: Mon, 16 Oct 2017 18:10:30 -0400 Subject: [PATCH 8/8] Fix SessionIdleTimeoutInMinutes in default.json --- config/default.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/default.json b/config/default.json index f9c5647e74..fd3e81baa5 100644 --- a/config/default.json +++ b/config/default.json @@ -36,7 +36,7 @@ "SessionLengthMobileInDays": 30, "SessionLengthSSOInDays": 30, "SessionCacheInMinutes": 10, - "SessionIdleTimeout": 0, + "SessionIdleTimeoutInMinutes": 0, "WebsocketSecurePort": 443, "WebsocketPort": 80, "WebserverMode": "gzip",