diff options
69 files changed, 442 insertions, 294 deletions
@@ -275,6 +275,14 @@ gofmt: ## Runs gofmt against all packages. done @echo "gofmt success"; \ +megacheck: ## Run megacheck on codebasis + go get honnef.co/go/tools/cmd/megacheck + $(GOPATH)/bin/megacheck $(TE_PACKAGES) + +ifeq ($(BUILD_ENTERPRISE_READY),true) + $(GOPATH)/bin/megacheck $(EE_PACKAGES) || exit 1 +endif + store-mocks: ## Creates mock files. go get -u github.com/vektra/mockery/... $(GOPATH)/bin/mockery -dir store -all -output store/storetest/mocks -note 'Regenerate this file using `make store-mocks`.' diff --git a/api4/channel_test.go b/api4/channel_test.go index 8593ea831..2aec90aea 100644 --- a/api4/channel_test.go +++ b/api4/channel_test.go @@ -150,8 +150,8 @@ func TestUpdateChannel(t *testing.T) { channel := &model.Channel{DisplayName: "Test API Name", Name: GenerateTestChannelName(), Type: model.CHANNEL_OPEN, TeamId: team.Id} private := &model.Channel{DisplayName: "Test API Name", Name: GenerateTestChannelName(), Type: model.CHANNEL_PRIVATE, TeamId: team.Id} - channel, resp := Client.CreateChannel(channel) - private, resp = Client.CreateChannel(private) + channel, _ = Client.CreateChannel(channel) + private, _ = Client.CreateChannel(private) //Update a open channel channel.DisplayName = "My new display name" @@ -434,7 +434,7 @@ func TestCreateGroupChannel(t *testing.T) { t.Fatal("should be equal") } - rgc, resp = Client.CreateGroupChannel([]string{user2.Id}) + _, resp = Client.CreateGroupChannel([]string{user2.Id}) CheckBadRequestStatus(t, resp) user4 := th.CreateUser() @@ -541,12 +541,12 @@ func TestGetDeletedChannelsForTeam(t *testing.T) { Client := th.Client team := th.BasicTeam - channels, resp := Client.GetDeletedChannelsForTeam(team.Id, 0, 100, "") + _, resp := Client.GetDeletedChannelsForTeam(team.Id, 0, 100, "") CheckForbiddenStatus(t, resp) th.LoginTeamAdmin() - channels, resp = Client.GetDeletedChannelsForTeam(team.Id, 0, 100, "") + channels, resp := Client.GetDeletedChannelsForTeam(team.Id, 0, 100, "") CheckNoError(t, resp) numInitialChannelsForTeam := len(channels) @@ -860,6 +860,7 @@ func TestDeleteChannel(t *testing.T) { // successful delete of channel with multiple members publicChannel3 := th.CreatePublicChannel() + th.App.AddUserToChannel(user, publicChannel3) th.App.AddUserToChannel(user2, publicChannel3) _, resp = Client.DeleteChannel(publicChannel3.Id) CheckNoError(t, resp) @@ -901,7 +902,7 @@ func TestDeleteChannel(t *testing.T) { publicChannel5 := th.CreatePublicChannel() Client.Logout() - Client.Login(user2.Id, user2.Password) + Client.Login(user.Id, user.Password) _, resp = Client.DeleteChannel(publicChannel5.Id) CheckUnauthorizedStatus(t, resp) @@ -927,16 +928,14 @@ func TestDeleteChannel(t *testing.T) { th.AddPermissionToRole(model.PERMISSION_DELETE_PRIVATE_CHANNEL.Id, model.TEAM_USER_ROLE_ID) Client = th.Client - team = th.BasicTeam user = th.BasicUser - user2 = th.BasicUser2 // channels created by SystemAdmin publicChannel6 := th.CreateChannelWithClient(th.SystemAdminClient, model.CHANNEL_OPEN) privateChannel7 := th.CreateChannelWithClient(th.SystemAdminClient, model.CHANNEL_PRIVATE) th.App.AddUserToChannel(user, publicChannel6) th.App.AddUserToChannel(user, privateChannel7) - th.App.AddUserToChannel(user2, privateChannel7) + th.App.AddUserToChannel(user, privateChannel7) // successful delete by user _, resp = Client.DeleteChannel(publicChannel6.Id) @@ -956,7 +955,7 @@ func TestDeleteChannel(t *testing.T) { privateChannel7 = th.CreateChannelWithClient(th.SystemAdminClient, model.CHANNEL_PRIVATE) th.App.AddUserToChannel(user, publicChannel6) th.App.AddUserToChannel(user, privateChannel7) - th.App.AddUserToChannel(user2, privateChannel7) + th.App.AddUserToChannel(user, privateChannel7) // cannot delete by user _, resp = Client.DeleteChannel(publicChannel6.Id) @@ -1629,7 +1628,7 @@ func TestUpdateChannelRoles(t *testing.T) { CheckNoError(t, resp) // System Admin promotes User 1 - pass, resp = th.SystemAdminClient.UpdateChannelRoles(channel.Id, th.BasicUser.Id, CHANNEL_ADMIN) + _, resp = th.SystemAdminClient.UpdateChannelRoles(channel.Id, th.BasicUser.Id, CHANNEL_ADMIN) CheckNoError(t, resp) th.LoginBasic() diff --git a/api4/emoji_test.go b/api4/emoji_test.go index cb6398312..e3aca4497 100644 --- a/api4/emoji_test.go +++ b/api4/emoji_test.go @@ -9,6 +9,7 @@ import ( _ "image/gif" "testing" + "github.com/mattermost/mattermost-server/app" "github.com/mattermost/mattermost-server/model" "github.com/mattermost/mattermost-server/utils" @@ -105,16 +106,26 @@ func TestCreateEmoji(t *testing.T) { t.Fatal("create with wrong name") } + // try to create an emoji that's too wide + emoji = &model.Emoji{ + CreatorId: th.BasicUser.Id, + Name: model.NewId(), + } + + newEmoji, resp = Client.CreateEmoji(emoji, utils.CreateTestGif(t, 10, app.MaxEmojiOriginalWidth+1), "image.gif") + if resp.Error == nil { + t.Fatal("should fail - emoji is too wide") + } + // try to create an emoji that's too tall emoji = &model.Emoji{ CreatorId: th.BasicUser.Id, Name: model.NewId(), } - newEmoji, resp = Client.CreateEmoji(emoji, utils.CreateTestGif(t, 10, 1000), "image.gif") - CheckNoError(t, resp) - if newEmoji.Name != emoji.Name { - t.Fatal("create with wrong name") + newEmoji, resp = Client.CreateEmoji(emoji, utils.CreateTestGif(t, app.MaxEmojiOriginalHeight+1, 10), "image.gif") + if resp.Error == nil { + t.Fatal("should fail - emoji is too tall") } // try to create an emoji that's too large @@ -329,12 +340,16 @@ func TestDeleteEmoji(t *testing.T) { th.RemovePermissionFromRole(model.PERMISSION_MANAGE_EMOJIS.Id, model.SYSTEM_USER_ROLE_ID) th.AddPermissionToRole(model.PERMISSION_MANAGE_OTHERS_EMOJIS.Id, model.SYSTEM_USER_ROLE_ID) + Client.Logout() th.LoginBasic2() - ok, resp = Client.DeleteEmoji(newEmoji.Id) + + _, resp = Client.DeleteEmoji(newEmoji.Id) CheckForbiddenStatus(t, resp) + th.RemovePermissionFromRole(model.PERMISSION_MANAGE_OTHERS_EMOJIS.Id, model.SYSTEM_USER_ROLE_ID) th.AddPermissionToRole(model.PERMISSION_MANAGE_EMOJIS.Id, model.SYSTEM_USER_ROLE_ID) + Client.Logout() th.LoginBasic() @@ -349,8 +364,10 @@ func TestDeleteEmoji(t *testing.T) { Client.Logout() th.LoginBasic2() - ok, resp = Client.DeleteEmoji(newEmoji.Id) + + _, resp = Client.DeleteEmoji(newEmoji.Id) CheckForbiddenStatus(t, resp) + Client.Logout() th.LoginBasic() @@ -365,9 +382,11 @@ func TestDeleteEmoji(t *testing.T) { th.AddPermissionToRole(model.PERMISSION_MANAGE_EMOJIS.Id, model.SYSTEM_USER_ROLE_ID) th.AddPermissionToRole(model.PERMISSION_MANAGE_OTHERS_EMOJIS.Id, model.SYSTEM_USER_ROLE_ID) + Client.Logout() th.LoginBasic2() - ok, resp = Client.DeleteEmoji(newEmoji.Id) + + _, resp = Client.DeleteEmoji(newEmoji.Id) CheckNoError(t, resp) Client.Logout() @@ -401,7 +420,8 @@ func TestDeleteEmoji(t *testing.T) { Client.Logout() th.LoginBasic2() - ok, resp = Client.DeleteEmoji(newEmoji.Id) + + _, resp = Client.DeleteEmoji(newEmoji.Id) CheckNoError(t, resp) } diff --git a/api4/file_test.go b/api4/file_test.go index 9143f4839..607e54dd7 100644 --- a/api4/file_test.go +++ b/api4/file_test.go @@ -446,7 +446,7 @@ func TestGetFileLink(t *testing.T) { fileId = fileResp.FileInfos[0].Id } - link, resp := Client.GetFileLink(fileId) + _, resp := Client.GetFileLink(fileId) CheckBadRequestStatus(t, resp) // Hacky way to assign file to a post (usually would be done by CreatePost call) @@ -460,8 +460,9 @@ func TestGetFileLink(t *testing.T) { time.Sleep(2 * time.Second) th.App.UpdateConfig(func(cfg *model.Config) { cfg.FileSettings.EnablePublicLink = true }) - link, resp = Client.GetFileLink(fileId) + link, resp := Client.GetFileLink(fileId) CheckNoError(t, resp) + if link == "" { t.Fatal("should've received public link") } diff --git a/api4/post_test.go b/api4/post_test.go index c428d3ab2..8ccd88a42 100644 --- a/api4/post_test.go +++ b/api4/post_test.go @@ -65,7 +65,7 @@ func TestCreatePost(t *testing.T) { CheckBadRequestStatus(t, resp) post2 := &model.Post{ChannelId: th.BasicChannel2.Id, Message: "zz" + model.NewId() + "a", CreateAt: 123} - rpost2, resp := Client.CreatePost(post2) + rpost2, _ := Client.CreatePost(post2) if rpost2.CreateAt == post2.CreateAt { t.Fatal("create at should not match") @@ -154,7 +154,7 @@ func TestCreatePostEphemeral(t *testing.T) { CheckUnauthorizedStatus(t, resp) Client = th.Client - rpost, resp = Client.CreatePostEphemeral(ephemeralPost) + _, resp = Client.CreatePostEphemeral(ephemeralPost) CheckForbiddenStatus(t, resp) } @@ -1023,22 +1023,22 @@ func TestGetFlaggedPostsForUser(t *testing.T) { Client.Logout() - rpl, resp = Client.GetFlaggedPostsForUserInChannel(user.Id, channel1.Id, 0, 10) + _, resp = Client.GetFlaggedPostsForUserInChannel(user.Id, channel1.Id, 0, 10) CheckUnauthorizedStatus(t, resp) - rpl, resp = Client.GetFlaggedPostsForUserInTeam(user.Id, team1.Id, 0, 10) + _, resp = Client.GetFlaggedPostsForUserInTeam(user.Id, team1.Id, 0, 10) CheckUnauthorizedStatus(t, resp) - rpl, resp = Client.GetFlaggedPostsForUser(user.Id, 0, 10) + _, resp = Client.GetFlaggedPostsForUser(user.Id, 0, 10) CheckUnauthorizedStatus(t, resp) - rpl, resp = th.SystemAdminClient.GetFlaggedPostsForUserInChannel(user.Id, channel1.Id, 0, 10) + _, resp = th.SystemAdminClient.GetFlaggedPostsForUserInChannel(user.Id, channel1.Id, 0, 10) CheckNoError(t, resp) - rpl, resp = th.SystemAdminClient.GetFlaggedPostsForUserInTeam(user.Id, team1.Id, 0, 10) + _, resp = th.SystemAdminClient.GetFlaggedPostsForUserInTeam(user.Id, team1.Id, 0, 10) CheckNoError(t, resp) - rpl, resp = th.SystemAdminClient.GetFlaggedPostsForUser(user.Id, 0, 10) + _, resp = th.SystemAdminClient.GetFlaggedPostsForUser(user.Id, 0, 10) CheckNoError(t, resp) } @@ -1153,25 +1153,25 @@ func TestGetPost(t *testing.T) { Client.RemoveUserFromChannel(th.BasicChannel.Id, th.BasicUser.Id) // Channel is public, should be able to read post - post, resp = Client.GetPost(th.BasicPost.Id, "") + _, resp = Client.GetPost(th.BasicPost.Id, "") CheckNoError(t, resp) privatePost := th.CreatePostWithClient(Client, th.BasicPrivateChannel) - post, resp = Client.GetPost(privatePost.Id, "") + _, resp = Client.GetPost(privatePost.Id, "") CheckNoError(t, resp) Client.RemoveUserFromChannel(th.BasicPrivateChannel.Id, th.BasicUser.Id) // Channel is private, should not be able to read post - post, resp = Client.GetPost(privatePost.Id, "") + _, resp = Client.GetPost(privatePost.Id, "") CheckForbiddenStatus(t, resp) Client.Logout() _, resp = Client.GetPost(model.NewId(), "") CheckUnauthorizedStatus(t, resp) - post, resp = th.SystemAdminClient.GetPost(th.BasicPost.Id, "") + _, resp = th.SystemAdminClient.GetPost(th.BasicPost.Id, "") CheckNoError(t, resp) } @@ -1267,7 +1267,7 @@ func TestGetPostThread(t *testing.T) { _, resp = Client.GetPostThread(model.NewId(), "") CheckUnauthorizedStatus(t, resp) - list, resp = th.SystemAdminClient.GetPostThread(th.BasicPost.Id, "") + _, resp = th.SystemAdminClient.GetPostThread(th.BasicPost.Id, "") CheckNoError(t, resp) } @@ -1351,12 +1351,13 @@ func TestSearchPosts(t *testing.T) { t.Fatal("wrong search") } - if posts, resp = Client.SearchPosts(th.BasicTeam.Id, "*", false); len(posts.Order) != 0 { + if posts, _ = Client.SearchPosts(th.BasicTeam.Id, "*", false); len(posts.Order) != 0 { t.Fatal("searching for just * shouldn't return any results") } posts, resp = Client.SearchPosts(th.BasicTeam.Id, "post1 post2", true) CheckNoError(t, resp) + if len(posts.Order) != 2 { t.Fatal("wrong search results") } diff --git a/api4/preference_test.go b/api4/preference_test.go index 68d34784f..41681ff69 100644 --- a/api4/preference_test.go +++ b/api4/preference_test.go @@ -105,15 +105,15 @@ func TestGetPreferencesByCategory(t *testing.T) { t.Fatalf("received the wrong number of preferences %v:%v", len(prefs), 2) } - prefs, resp = Client.GetPreferencesByCategory(user1.Id, "junk") + _, resp = Client.GetPreferencesByCategory(user1.Id, "junk") CheckNotFoundStatus(t, resp) th.LoginBasic2() - prefs, resp = Client.GetPreferencesByCategory(th.BasicUser2.Id, category) + _, resp = Client.GetPreferencesByCategory(th.BasicUser2.Id, category) CheckNotFoundStatus(t, resp) - prefs, resp = Client.GetPreferencesByCategory(user1.Id, category) + _, resp = Client.GetPreferencesByCategory(user1.Id, category) CheckForbiddenStatus(t, resp) prefs, resp = Client.GetPreferencesByCategory(th.BasicUser2.Id, "junk") @@ -309,7 +309,7 @@ func TestDeletePreferences(t *testing.T) { th.LoginBasic() - prefs, resp := Client.GetPreferences(th.BasicUser.Id) + prefs, _ := Client.GetPreferences(th.BasicUser.Id) originalCount := len(prefs) // save 10 preferences @@ -328,7 +328,7 @@ func TestDeletePreferences(t *testing.T) { // delete 10 preferences th.LoginBasic2() - _, resp = Client.DeletePreferences(th.BasicUser2.Id, &preferences) + _, resp := Client.DeletePreferences(th.BasicUser2.Id, &preferences) CheckForbiddenStatus(t, resp) th.LoginBasic() @@ -339,7 +339,7 @@ func TestDeletePreferences(t *testing.T) { _, resp = Client.DeletePreferences(th.BasicUser2.Id, &preferences) CheckForbiddenStatus(t, resp) - prefs, resp = Client.GetPreferences(th.BasicUser.Id) + prefs, _ = Client.GetPreferences(th.BasicUser.Id) if len(prefs) != originalCount { t.Fatal("should've deleted preferences") } diff --git a/api4/role_test.go b/api4/role_test.go index 8149ff3c6..2a8008dc9 100644 --- a/api4/role_test.go +++ b/api4/role_test.go @@ -130,7 +130,7 @@ func TestGetRolesByNames(t *testing.T) { assert.Contains(t, received, role3) // Check a list of non-existent roles. - received, resp = th.Client.GetRolesByNames([]string{model.NewId(), model.NewId()}) + _, resp = th.Client.GetRolesByNames([]string{model.NewId(), model.NewId()}) CheckNoError(t, resp) // Empty list should error. @@ -138,11 +138,11 @@ func TestGetRolesByNames(t *testing.T) { CheckBadRequestStatus(t, resp) // Invalid role name should error. - received, resp = th.Client.GetRolesByNames([]string{model.NewId(), model.NewId(), "!!!!!!"}) + _, resp = th.Client.GetRolesByNames([]string{model.NewId(), model.NewId(), "!!!!!!"}) CheckBadRequestStatus(t, resp) // Empty/whitespace rolenames should be ignored. - received, resp = th.Client.GetRolesByNames([]string{model.NewId(), model.NewId(), "", " "}) + _, resp = th.Client.GetRolesByNames([]string{model.NewId(), model.NewId(), "", " "}) CheckNoError(t, resp) } @@ -178,16 +178,16 @@ func TestPatchRole(t *testing.T) { assert.Equal(t, received.SchemeManaged, role.SchemeManaged) // Check a no-op patch succeeds. - received, resp = th.SystemAdminClient.PatchRole(role.Id, patch) + _, resp = th.SystemAdminClient.PatchRole(role.Id, patch) CheckNoError(t, resp) - received, resp = th.SystemAdminClient.PatchRole("junk", patch) + _, resp = th.SystemAdminClient.PatchRole("junk", patch) CheckBadRequestStatus(t, resp) - received, resp = th.Client.PatchRole(model.NewId(), patch) + _, resp = th.Client.PatchRole(model.NewId(), patch) CheckNotFoundStatus(t, resp) - received, resp = th.Client.PatchRole(role.Id, patch) + _, resp = th.Client.PatchRole(role.Id, patch) CheckForbiddenStatus(t, resp) // Check a change that the license would not allow. @@ -195,7 +195,7 @@ func TestPatchRole(t *testing.T) { Permissions: &[]string{"manage_system", "manage_webhooks"}, } - received, resp = th.SystemAdminClient.PatchRole(role.Id, patch) + _, resp = th.SystemAdminClient.PatchRole(role.Id, patch) CheckNotImplementedStatus(t, resp) // Add a license. diff --git a/api4/status_test.go b/api4/status_test.go index 9b3583c1e..afff8526d 100644 --- a/api4/status_test.go +++ b/api4/status_test.go @@ -150,11 +150,11 @@ func TestUpdateUserStatus(t *testing.T) { } toUpdateUserStatus.Status = "online" - updateUserStatus, resp = Client.UpdateUserStatus(th.BasicUser2.Id, toUpdateUserStatus) + _, resp = Client.UpdateUserStatus(th.BasicUser2.Id, toUpdateUserStatus) CheckForbiddenStatus(t, resp) toUpdateUserStatus.Status = "online" - updateUserStatus, resp = th.SystemAdminClient.UpdateUserStatus(th.BasicUser2.Id, toUpdateUserStatus) + updateUserStatus, _ = th.SystemAdminClient.UpdateUserStatus(th.BasicUser2.Id, toUpdateUserStatus) if updateUserStatus.Status != "online" { t.Fatal("Should return online status") } diff --git a/api4/team_test.go b/api4/team_test.go index 468b9451d..8304c979d 100644 --- a/api4/team_test.go +++ b/api4/team_test.go @@ -858,10 +858,10 @@ func TestSearchAllTeams(t *testing.T) { Client.Logout() - rteams, resp = Client.SearchTeams(&model.TeamSearch{Term: pTeam.Name}) + _, resp = Client.SearchTeams(&model.TeamSearch{Term: pTeam.Name}) CheckUnauthorizedStatus(t, resp) - rteams, resp = Client.SearchTeams(&model.TeamSearch{Term: pTeam.DisplayName}) + _, resp = Client.SearchTeams(&model.TeamSearch{Term: pTeam.DisplayName}) CheckUnauthorizedStatus(t, resp) } @@ -1148,10 +1148,10 @@ func TestGetTeamMembers(t *testing.T) { CheckForbiddenStatus(t, resp) Client.Logout() - rmembers, resp = Client.GetTeamMembers(team.Id, 0, 1, "") + _, resp = Client.GetTeamMembers(team.Id, 0, 1, "") CheckUnauthorizedStatus(t, resp) - rmembers, resp = th.SystemAdminClient.GetTeamMembers(team.Id, 0, 100, "") + _, resp = th.SystemAdminClient.GetTeamMembers(team.Id, 0, 100, "") CheckNoError(t, resp) } @@ -1220,10 +1220,10 @@ func TestGetTeamMembersByIds(t *testing.T) { t.Fatal("1 user should be returned") } - tm1, resp = Client.GetTeamMembersByIds("junk", []string{th.BasicUser.Id}) + _, resp = Client.GetTeamMembersByIds("junk", []string{th.BasicUser.Id}) CheckBadRequestStatus(t, resp) - tm1, resp = Client.GetTeamMembersByIds(model.NewId(), []string{th.BasicUser.Id}) + _, resp = Client.GetTeamMembersByIds(model.NewId(), []string{th.BasicUser.Id}) CheckForbiddenStatus(t, resp) Client.Logout() @@ -1244,7 +1244,7 @@ func TestAddTeamMember(t *testing.T) { // Regular user can't add a member to a team they don't belong to. th.LoginBasic2() - tm, resp := Client.AddTeamMember(team.Id, otherUser.Id) + _, resp := Client.AddTeamMember(team.Id, otherUser.Id) CheckForbiddenStatus(t, resp) if resp.Error == nil { t.Fatalf("Error is nil") @@ -1253,7 +1253,7 @@ func TestAddTeamMember(t *testing.T) { // Regular user can add a member to a team they belong to. th.LoginBasic() - tm, resp = Client.AddTeamMember(team.Id, otherUser.Id) + tm, resp := Client.AddTeamMember(team.Id, otherUser.Id) CheckNoError(t, resp) CheckCreatedStatus(t, resp) @@ -1370,7 +1370,7 @@ func TestAddTeamMember(t *testing.T) { token.CreateAt = model.GetMillis() - 1000*60*60*50 <-th.App.Srv.Store.Token().Save(token) - tm, resp = Client.AddTeamMemberFromInvite(token.Token, "") + _, resp = Client.AddTeamMemberFromInvite(token.Token, "") CheckBadRequestStatus(t, resp) th.App.DeleteToken(token) @@ -1382,7 +1382,7 @@ func TestAddTeamMember(t *testing.T) { ) <-th.App.Srv.Store.Token().Save(token) - tm, resp = Client.AddTeamMemberFromInvite(token.Token, "") + _, resp = Client.AddTeamMemberFromInvite(token.Token, "") CheckNotFoundStatus(t, resp) th.App.DeleteToken(token) @@ -1428,13 +1428,13 @@ func TestAddTeamMembers(t *testing.T) { // Regular user can't add a member to a team they don't belong to. th.LoginBasic2() - tm, resp := Client.AddTeamMembers(team.Id, userList) + _, resp := Client.AddTeamMembers(team.Id, userList) CheckForbiddenStatus(t, resp) Client.Logout() // Regular user can add a member to a team they belong to. th.LoginBasic() - tm, resp = Client.AddTeamMembers(team.Id, userList) + tm, resp := Client.AddTeamMembers(team.Id, userList) CheckNoError(t, resp) CheckCreatedStatus(t, resp) @@ -2018,7 +2018,7 @@ func TestGetTeamInviteInfo(t *testing.T) { team, resp = th.SystemAdminClient.UpdateTeam(team) CheckNoError(t, resp) - team, resp = Client.GetTeamInviteInfo(team.InviteId) + _, resp = Client.GetTeamInviteInfo(team.InviteId) CheckNoError(t, resp) _, resp = Client.GetTeamInviteInfo("junk") diff --git a/api4/user_test.go b/api4/user_test.go index 6cd64b7cf..e624d747d 100644 --- a/api4/user_test.go +++ b/api4/user_test.go @@ -406,7 +406,7 @@ func TestGetUser(t *testing.T) { CheckUnauthorizedStatus(t, resp) // System admins should ignore privacy settings - ruser, resp = th.SystemAdminClient.GetUser(user.Id, resp.Etag) + ruser, _ = th.SystemAdminClient.GetUser(user.Id, resp.Etag) if ruser.Email == "" { t.Fatal("email should not be blank") } @@ -474,7 +474,7 @@ func TestGetUserByUsername(t *testing.T) { CheckUnauthorizedStatus(t, resp) // System admins should ignore privacy settings - ruser, resp = th.SystemAdminClient.GetUserByUsername(user.Username, resp.Etag) + ruser, _ = th.SystemAdminClient.GetUserByUsername(user.Username, resp.Etag) if ruser.Email == "" { t.Fatal("email should not be blank") } @@ -539,7 +539,7 @@ func TestGetUserByEmail(t *testing.T) { CheckUnauthorizedStatus(t, resp) // System admins should ignore privacy settings - ruser, resp = th.SystemAdminClient.GetUserByEmail(user.Email, resp.Etag) + ruser, _ = th.SystemAdminClient.GetUserByEmail(user.Email, resp.Etag) if ruser.Email == "" { t.Fatal("email should not be blank") } @@ -2208,14 +2208,14 @@ func TestVerifyUserEmail(t *testing.T) { user := model.User{Email: th.GenerateTestEmail(), Nickname: "Darth Vader", Password: "hello1", Username: GenerateTestUsername(), Roles: model.SYSTEM_ADMIN_ROLE_ID + " " + model.SYSTEM_USER_ROLE_ID} - ruser, resp := Client.CreateUser(&user) + ruser, _ := Client.CreateUser(&user) token, err := th.App.CreateVerifyEmailToken(ruser.Id) if err != nil { t.Fatal("Unable to create email verify token") } - _, resp = Client.VerifyUserEmail(token.Token) + _, resp := Client.VerifyUserEmail(token.Token) CheckNoError(t, resp) _, resp = Client.VerifyUserEmail(GenerateTestId()) @@ -2329,7 +2329,7 @@ func TestCBALogin(t *testing.T) { } Client.HttpHeader["X-SSL-Client-Cert-Subject-DN"] = "C=US, ST=Maryland, L=Pasadena, O=Brent Baccala, OU=FreeSoft, CN=www.freesoft.org/emailAddress=" + th.BasicUser.Email - user, resp = Client.Login(th.BasicUser.Email, "") + user, _ = Client.Login(th.BasicUser.Email, "") if !(user != nil && user.Email == th.BasicUser.Email) { t.Fatal("Should have been able to login") } @@ -2340,13 +2340,13 @@ func TestCBALogin(t *testing.T) { }) Client.HttpHeader["X-SSL-Client-Cert-Subject-DN"] = "C=US, ST=Maryland, L=Pasadena, O=Brent Baccala, OU=FreeSoft, CN=www.freesoft.org/emailAddress=" + th.BasicUser.Email - user, resp = Client.Login(th.BasicUser.Email, "") + user, _ = Client.Login(th.BasicUser.Email, "") if resp.Error.StatusCode != 400 && user == nil { t.Fatal("Should have failed because password is required") } Client.HttpHeader["X-SSL-Client-Cert-Subject-DN"] = "C=US, ST=Maryland, L=Pasadena, O=Brent Baccala, OU=FreeSoft, CN=www.freesoft.org/emailAddress=" + th.BasicUser.Email - user, resp = Client.Login(th.BasicUser.Email, th.BasicUser.Password) + user, _ = Client.Login(th.BasicUser.Email, th.BasicUser.Password) if !(user != nil && user.Email == th.BasicUser.Email) { t.Fatal("Should have been able to login") } @@ -2597,7 +2597,7 @@ func TestGetUserAccessToken(t *testing.T) { _, resp = AdminClient.GetUserAccessToken(token.Id) CheckNoError(t, resp) - token, resp = Client.CreateUserAccessToken(th.BasicUser.Id, testDescription) + _, resp = Client.CreateUserAccessToken(th.BasicUser.Id, testDescription) CheckNoError(t, resp) rtokens, resp := Client.GetUserAccessTokensForUser(th.BasicUser.Id, 0, 100) diff --git a/api4/webhook_test.go b/api4/webhook_test.go index 764f25709..78598f9dc 100644 --- a/api4/webhook_test.go +++ b/api4/webhook_test.go @@ -365,7 +365,7 @@ func TestGetOutgoingWebhooks(t *testing.T) { t.Fatal("missing hook") } - hooks, resp = th.SystemAdminClient.GetOutgoingWebhooksForChannel(model.NewId(), 0, 1000, "") + _, resp = th.SystemAdminClient.GetOutgoingWebhooksForChannel(model.NewId(), 0, 1000, "") CheckForbiddenStatus(t, resp) _, resp = Client.GetOutgoingWebhooks(0, 1000, "") diff --git a/app/app.go b/app/app.go index b704bb449..c3fcc7aec 100644 --- a/app/app.go +++ b/app/app.go @@ -7,12 +7,10 @@ import ( "crypto/ecdsa" "fmt" "html/template" - "net" "net/http" "path" "reflect" "strconv" - "strings" "sync" "sync/atomic" @@ -100,6 +98,8 @@ type App struct { diagnosticId string phase2PermissionsMigrationComplete bool + + HTTPService HTTPService } var appCount = 0 @@ -125,6 +125,9 @@ func New(options ...Option) (outApp *App, outErr error) { clientConfig: make(map[string]string), licenseListeners: map[string]func(){}, } + + app.HTTPService = MakeHTTPService(app) + defer func() { if outErr != nil { app.Shutdown() @@ -285,6 +288,8 @@ func (a *App) Shutdown() { mlog.Info("Server stopped") a.DisableConfigWatch() + + a.HTTPService.Close() } var accountMigrationInterface func(*App) einterfaces.AccountMigrationInterface @@ -505,43 +510,6 @@ func (a *App) HTMLTemplates() *template.Template { return nil } -func (a *App) HTTPClient(trustURLs bool) *http.Client { - insecure := a.Config().ServiceSettings.EnableInsecureOutgoingConnections != nil && *a.Config().ServiceSettings.EnableInsecureOutgoingConnections - - if trustURLs { - return utils.NewHTTPClient(insecure, nil, nil) - } - - allowHost := func(host string) bool { - if a.Config().ServiceSettings.AllowedUntrustedInternalConnections == nil { - return false - } - for _, allowed := range strings.Fields(*a.Config().ServiceSettings.AllowedUntrustedInternalConnections) { - if host == allowed { - return true - } - } - return false - } - - allowIP := func(ip net.IP) bool { - if !utils.IsReservedIP(ip) { - return true - } - if a.Config().ServiceSettings.AllowedUntrustedInternalConnections == nil { - return false - } - for _, allowed := range strings.Fields(*a.Config().ServiceSettings.AllowedUntrustedInternalConnections) { - if _, ipRange, err := net.ParseCIDR(allowed); err == nil && ipRange.Contains(ip) { - return true - } - } - return false - } - - return utils.NewHTTPClient(insecure, allowHost, allowIP) -} - func (a *App) Handle404(w http.ResponseWriter, r *http.Request) { err := model.NewAppError("Handle404", "api.context.404.app_error", nil, "", http.StatusNotFound) @@ -642,7 +610,6 @@ func (a *App) DoEmojisPermissionsMigration() { mlog.Critical(err.Error()) return } - break case model.RESTRICT_EMOJI_CREATION_ADMIN: role, err = a.GetRoleByName(model.TEAM_ADMIN_ROLE_ID) if err != nil { @@ -650,10 +617,8 @@ func (a *App) DoEmojisPermissionsMigration() { mlog.Critical(err.Error()) return } - break case model.RESTRICT_EMOJI_CREATION_SYSTEM_ADMIN: role = nil - break default: mlog.Critical("Failed to migrate emojis creation permissions from mattermost config.") mlog.Critical("Invalid restrict emoji creation setting") @@ -703,13 +668,13 @@ func (a *App) StartElasticsearch() { }) a.AddConfigListener(func(oldConfig *model.Config, newConfig *model.Config) { - if *oldConfig.ElasticsearchSettings.EnableIndexing == false && *newConfig.ElasticsearchSettings.EnableIndexing == true { + if !*oldConfig.ElasticsearchSettings.EnableIndexing && *newConfig.ElasticsearchSettings.EnableIndexing { a.Go(func() { if err := a.Elasticsearch.Start(); err != nil { mlog.Error(err.Error()) } }) - } else if *oldConfig.ElasticsearchSettings.EnableIndexing == true && *newConfig.ElasticsearchSettings.EnableIndexing == false { + } else if *oldConfig.ElasticsearchSettings.EnableIndexing && !*newConfig.ElasticsearchSettings.EnableIndexing { a.Go(func() { if err := a.Elasticsearch.Stop(); err != nil { mlog.Error(err.Error()) @@ -717,7 +682,7 @@ func (a *App) StartElasticsearch() { }) } else if *oldConfig.ElasticsearchSettings.Password != *newConfig.ElasticsearchSettings.Password || *oldConfig.ElasticsearchSettings.Username != *newConfig.ElasticsearchSettings.Username || *oldConfig.ElasticsearchSettings.ConnectionUrl != *newConfig.ElasticsearchSettings.ConnectionUrl || *oldConfig.ElasticsearchSettings.Sniff != *newConfig.ElasticsearchSettings.Sniff { a.Go(func() { - if *oldConfig.ElasticsearchSettings.EnableIndexing == true { + if *oldConfig.ElasticsearchSettings.EnableIndexing { if err := a.Elasticsearch.Stop(); err != nil { mlog.Error(err.Error()) } diff --git a/app/apptestlib.go b/app/apptestlib.go index 48783f49c..c0d2cfaa2 100644 --- a/app/apptestlib.go +++ b/app/apptestlib.go @@ -6,6 +6,8 @@ package app import ( "io" "io/ioutil" + "net/http" + "net/http/httptest" "os" "path/filepath" "time" @@ -33,6 +35,8 @@ type TestHelper struct { tempConfigPath string tempWorkspace string + + MockedHTTPService *MockedHTTPService } type persistentTestStore struct { @@ -163,6 +167,13 @@ func (me *TestHelper) InitSystemAdmin() *TestHelper { return me } +func (me *TestHelper) MockHTTPService(handler http.Handler) *TestHelper { + me.MockedHTTPService = MakeMockedHTTPService(handler) + me.App.HTTPService = me.MockedHTTPService + + return me +} + func (me *TestHelper) MakeEmail() string { return "success_" + model.NewId() + "@simulator.amazonses.com" } @@ -503,3 +514,22 @@ func (me *FakeClusterInterface) sendClearRoleCacheMessage() { Event: model.CLUSTER_EVENT_INVALIDATE_CACHE_FOR_ROLES, }) } + +type MockedHTTPService struct { + Server *httptest.Server +} + +func MakeMockedHTTPService(handler http.Handler) *MockedHTTPService { + return &MockedHTTPService{ + Server: httptest.NewServer(handler), + } +} + +func (h *MockedHTTPService) MakeClient(trustURLs bool) *http.Client { + return h.Server.Client() +} + +func (h *MockedHTTPService) Close() { + h.Server.CloseClientConnections() + h.Server.Close() +} diff --git a/app/auto_responder_test.go b/app/auto_responder_test.go index f78bbc669..4afa03348 100644 --- a/app/auto_responder_test.go +++ b/app/auto_responder_test.go @@ -94,7 +94,7 @@ func TestSendAutoResponseSuccess(t *testing.T) { userUpdated1, err := th.App.PatchUser(user.Id, patch, true) require.Nil(t, err) - firstPost, err := th.App.CreatePost(&model.Post{ + firstPost, _ := th.App.CreatePost(&model.Post{ ChannelId: th.BasicChannel.Id, Message: "zz" + model.NewId() + "a", UserId: th.BasicUser.Id}, @@ -134,7 +134,7 @@ func TestSendAutoResponseFailure(t *testing.T) { userUpdated1, err := th.App.PatchUser(user.Id, patch, true) require.Nil(t, err) - firstPost, err := th.App.CreatePost(&model.Post{ + firstPost, _ := th.App.CreatePost(&model.Post{ ChannelId: th.BasicChannel.Id, Message: "zz" + model.NewId() + "a", UserId: th.BasicUser.Id}, diff --git a/app/brand.go b/app/brand.go index 4814264dd..f01393125 100644 --- a/app/brand.go +++ b/app/brand.go @@ -27,10 +27,10 @@ func (a *App) SaveBrandImage(imageData *multipart.FileHeader) *model.AppError { } file, err := imageData.Open() - defer file.Close() if err != nil { return model.NewAppError("SaveBrandImage", "brand.save_brand_image.open.app_error", nil, err.Error(), http.StatusBadRequest) } + defer file.Close() // Decode image config first to check dimensions before loading the whole thing into memory later on config, _, err := image.DecodeConfig(file) diff --git a/app/channel.go b/app/channel.go index 535eff724..0ac2894fb 100644 --- a/app/channel.go +++ b/app/channel.go @@ -52,7 +52,7 @@ func (a *App) JoinDefaultChannels(teamId string, user *model.User, shouldBeAdmin } else { seenChannels := map[string]bool{} for _, channelName := range a.Config().TeamSettings.ExperimentalDefaultChannels { - if seenChannels[channelName] != true { + if !seenChannels[channelName] { defaultChannelList = append(defaultChannelList, channelName) seenChannels[channelName] = true } @@ -1398,7 +1398,7 @@ func (a *App) removeUserFromChannel(userIdToRemove string, removerUserId string, var actorUser *model.User if removerUserId != "" { - actorUser, err = a.GetUser(removerUserId) + actorUser, _ = a.GetUser(removerUserId) } a.Go(func() { diff --git a/app/command.go b/app/command.go index 92c35865a..124668f6b 100644 --- a/app/command.go +++ b/app/command.go @@ -244,7 +244,7 @@ func (a *App) ExecuteCommand(args *model.CommandArgs) (*model.CommandResponse, * req.Header.Set("Content-Type", "application/x-www-form-urlencoded") } - if resp, err := a.HTTPClient(false).Do(req); err != nil { + if resp, err := a.HTTPService.MakeClient(false).Do(req); err != nil { return nil, model.NewAppError("command", "api.command.execute_command.failed.app_error", map[string]interface{}{"Trigger": trigger}, err.Error(), http.StatusInternalServerError) } else { if resp.StatusCode == http.StatusOK { diff --git a/app/config_test.go b/app/config_test.go index eb3fa8a53..abaf00167 100644 --- a/app/config_test.go +++ b/app/config_test.go @@ -122,12 +122,10 @@ func TestEnsureInstallationDate(t *testing.T) { sqlStore := th.App.Srv.Store.User().(*sqlstore.SqlUserStore) sqlStore.GetMaster().Exec("DELETE FROM Users") - var users []*model.User for _, createAt := range tc.UsersCreationDates { user := th.CreateUser() user.CreateAt = createAt sqlStore.GetMaster().Exec("UPDATE Users SET CreateAt = :CreateAt WHERE Id = :UserId", map[string]interface{}{"CreateAt": createAt, "UserId": user.Id}) - users = append(users, user) } if tc.PrevInstallationDate == nil { diff --git a/app/diagnostics_test.go b/app/diagnostics_test.go index 1dfcbecd1..8d4e57107 100644 --- a/app/diagnostics_test.go +++ b/app/diagnostics_test.go @@ -103,19 +103,13 @@ func TestDiagnostics(t *testing.T) { info := "" // Collect the info sent. + Loop: for { - done := false select { case result := <-data: info += result case <-time.After(time.Second * 1): - // Done recieving - done = true - break - } - - if done { - break + break Loop } } diff --git a/app/emoji.go b/app/emoji.go index b07331e65..864dc31bf 100644 --- a/app/emoji.go +++ b/app/emoji.go @@ -23,9 +23,11 @@ import ( ) const ( - MaxEmojiFileSize = 1 << 20 // 1 MB - MaxEmojiWidth = 128 - MaxEmojiHeight = 128 + MaxEmojiFileSize = 1 << 20 // 1 MB + MaxEmojiWidth = 128 + MaxEmojiHeight = 128 + MaxEmojiOriginalWidth = 1028 + MaxEmojiOriginalHeight = 1028 ) func (a *App) CreateEmoji(sessionUserId string, emoji *model.Emoji, multiPartImageData *multipart.Form) (*model.Emoji, *model.AppError) { @@ -85,6 +87,11 @@ func (a *App) UploadEmojiImage(id string, imageData *multipart.FileHeader) *mode // make sure the file is an image and is within the required dimensions if config, _, err := image.DecodeConfig(bytes.NewReader(buf.Bytes())); err != nil { return model.NewAppError("uploadEmojiImage", "api.emoji.upload.image.app_error", nil, "", http.StatusBadRequest) + } else if config.Width > MaxEmojiOriginalWidth || config.Height > MaxEmojiOriginalHeight { + return model.NewAppError("uploadEmojiImage", "api.emoji.upload.large_image.too_large.app_error", map[string]interface{}{ + "MaxWidth": MaxEmojiOriginalWidth, + "MaxHeight": MaxEmojiOriginalHeight, + }, "", http.StatusBadRequest) } else if config.Width > MaxEmojiWidth || config.Height > MaxEmojiHeight { data := buf.Bytes() newbuf := bytes.NewBuffer(nil) diff --git a/app/file.go b/app/file.go index d2a145c81..278990b49 100644 --- a/app/file.go +++ b/app/file.go @@ -613,19 +613,18 @@ func (a *App) GetFileInfo(fileId string) (*model.FileInfo, *model.AppError) { } func (a *App) CopyFileInfos(userId string, fileIds []string) ([]string, *model.AppError) { - newFileIds := []string{} + var newFileIds []string now := model.GetMillis() for _, fileId := range fileIds { - fileInfo := &model.FileInfo{} + result := <-a.Srv.Store.FileInfo().Get(fileId) - if result := <-a.Srv.Store.FileInfo().Get(fileId); result.Err != nil { + if result.Err != nil { return nil, result.Err - } else { - fileInfo = result.Data.(*model.FileInfo) } + fileInfo := result.Data.(*model.FileInfo) fileInfo.Id = model.NewId() fileInfo.CreatorId = userId fileInfo.CreateAt = now diff --git a/app/http_service.go b/app/http_service.go new file mode 100644 index 000000000..71e72ab2f --- /dev/null +++ b/app/http_service.go @@ -0,0 +1,67 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See License.txt for license information. + +package app + +import ( + "net" + "net/http" + "strings" + + "github.com/mattermost/mattermost-server/utils" +) + +// Wraps the functionality for creating a new http.Client to encapsulate that and allow it to be mocked when testing +type HTTPService interface { + MakeClient(trustURLs bool) *http.Client + Close() +} + +type HTTPServiceImpl struct { + app *App +} + +func MakeHTTPService(app *App) HTTPService { + return &HTTPServiceImpl{app} +} + +func (h *HTTPServiceImpl) MakeClient(trustURLs bool) *http.Client { + insecure := h.app.Config().ServiceSettings.EnableInsecureOutgoingConnections != nil && *h.app.Config().ServiceSettings.EnableInsecureOutgoingConnections + + if trustURLs { + return utils.NewHTTPClient(insecure, nil, nil) + } + + allowHost := func(host string) bool { + if h.app.Config().ServiceSettings.AllowedUntrustedInternalConnections == nil { + return false + } + for _, allowed := range strings.Fields(*h.app.Config().ServiceSettings.AllowedUntrustedInternalConnections) { + if host == allowed { + return true + } + } + return false + } + + allowIP := func(ip net.IP) bool { + if !utils.IsReservedIP(ip) { + return true + } + if h.app.Config().ServiceSettings.AllowedUntrustedInternalConnections == nil { + return false + } + for _, allowed := range strings.Fields(*h.app.Config().ServiceSettings.AllowedUntrustedInternalConnections) { + if _, ipRange, err := net.ParseCIDR(allowed); err == nil && ipRange.Contains(ip) { + return true + } + } + return false + } + + return utils.NewHTTPClient(insecure, allowHost, allowIP) +} + +func (h *HTTPServiceImpl) Close() { + // Does nothing, but allows this to be overridden when mocking the service +} diff --git a/app/http_service_test.go b/app/http_service_test.go new file mode 100644 index 000000000..396a991b1 --- /dev/null +++ b/app/http_service_test.go @@ -0,0 +1,65 @@ +package app + +import ( + "io/ioutil" + "net/http" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestMockHTTPService(t *testing.T) { + getCalled := false + putCalled := false + + handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.URL.Path == "/get" && r.Method == http.MethodGet { + getCalled = true + + w.WriteHeader(http.StatusOK) + w.Write([]byte("OK")) + } else if r.URL.Path == "/put" && r.Method == http.MethodPut { + putCalled = true + + w.WriteHeader(http.StatusCreated) + w.Write([]byte("CREATED")) + } else { + w.WriteHeader(http.StatusNotFound) + } + }) + + th := Setup().MockHTTPService(handler) + defer th.TearDown() + + url := th.MockedHTTPService.Server.URL + + t.Run("GET", func(t *testing.T) { + client := th.App.HTTPService.MakeClient(false) + + resp, err := client.Get(url + "/get") + defer consumeAndClose(resp) + + bodyContents, _ := ioutil.ReadAll(resp.Body) + + require.Nil(t, err) + assert.Equal(t, http.StatusOK, resp.StatusCode) + assert.Equal(t, "OK", string(bodyContents)) + assert.True(t, getCalled) + }) + + t.Run("PUT", func(t *testing.T) { + client := th.App.HTTPService.MakeClient(false) + + request, _ := http.NewRequest(http.MethodPut, url+"/put", nil) + resp, err := client.Do(request) + defer consumeAndClose(resp) + + bodyContents, _ := ioutil.ReadAll(resp.Body) + + require.Nil(t, err) + assert.Equal(t, http.StatusCreated, resp.StatusCode) + assert.Equal(t, "CREATED", string(bodyContents)) + assert.True(t, putCalled) + }) +} diff --git a/app/import_functions.go b/app/import_functions.go index 1490dc6fa..dce84feb5 100644 --- a/app/import_functions.go +++ b/app/import_functions.go @@ -123,9 +123,9 @@ func (a *App) ImportRole(data *RoleImportData, dryRun bool, isSchemeRole bool) * } if len(role.Id) == 0 { - role, err = a.CreateRole(role) + _, err = a.CreateRole(role) } else { - role, err = a.UpdateRole(role) + _, err = a.UpdateRole(role) } return err diff --git a/app/notification_email.go b/app/notification_email.go index cccd02eba..f5b55f9a8 100644 --- a/app/notification_email.go +++ b/app/notification_email.go @@ -306,7 +306,7 @@ func getFormattedPostTime(user *model.User, post *model.Post, useMilitaryTime bo Year: fmt.Sprintf("%d", localTime.Year()), Month: translateFunc(localTime.Month().String()), Day: fmt.Sprintf("%d", localTime.Day()), - Hour: fmt.Sprintf("%s", hour), + Hour: hour, Minute: fmt.Sprintf("%02d"+period, localTime.Minute()), TimeZone: zone, } diff --git a/app/notification_push.go b/app/notification_push.go index 12d9f5258..517988a97 100644 --- a/app/notification_push.go +++ b/app/notification_push.go @@ -184,7 +184,7 @@ func (a *App) sendToPushProxy(msg model.PushNotification, session *model.Session request, _ := http.NewRequest("POST", strings.TrimRight(*a.Config().EmailSettings.PushNotificationServer, "/")+model.API_URL_SUFFIX_V1+"/send_push", strings.NewReader(msg.ToJson())) - if resp, err := a.HTTPClient(true).Do(request); err != nil { + if resp, err := a.HTTPService.MakeClient(true).Do(request); err != nil { mlog.Error(fmt.Sprintf("Device push reported as error for UserId=%v SessionId=%v message=%v", session.UserId, session.Id, err.Error()), mlog.String("user_id", session.UserId)) } else { pushResponse := model.PushResponseFromJson(resp.Body) diff --git a/app/oauth.go b/app/oauth.go index a0123c0e9..645d502f5 100644 --- a/app/oauth.go +++ b/app/oauth.go @@ -761,7 +761,7 @@ func (a *App) AuthorizeOAuthUser(w http.ResponseWriter, r *http.Request, service var ar *model.AccessResponse var bodyBytes []byte - if resp, err := a.HTTPClient(true).Do(req); err != nil { + if resp, err := a.HTTPService.MakeClient(true).Do(req); err != nil { return nil, "", stateProps, model.NewAppError("AuthorizeOAuthUser", "api.user.authorize_oauth_user.token_failed.app_error", nil, err.Error(), http.StatusInternalServerError) } else { bodyBytes, _ = ioutil.ReadAll(resp.Body) @@ -791,7 +791,7 @@ func (a *App) AuthorizeOAuthUser(w http.ResponseWriter, r *http.Request, service req.Header.Set("Accept", "application/json") req.Header.Set("Authorization", "Bearer "+ar.AccessToken) - if resp, err := a.HTTPClient(true).Do(req); err != nil { + if resp, err := a.HTTPService.MakeClient(true).Do(req); err != nil { return nil, "", stateProps, model.NewAppError("AuthorizeOAuthUser", "api.user.authorize_oauth_user.service.app_error", map[string]interface{}{"Service": service}, err.Error(), http.StatusInternalServerError) } else { bodyBytes, _ = ioutil.ReadAll(resp.Body) diff --git a/app/permissions.go b/app/permissions.go index 8b4df7c56..ca5c8a165 100644 --- a/app/permissions.go +++ b/app/permissions.go @@ -138,11 +138,7 @@ func (a *App) ExportPermissions(w io.Writer) error { schemeExport = append(schemeExport, []byte("\n")...) _, err = w.Write(schemeExport) - if err != nil { - return err - } - - return nil + return err } func (a *App) ImportPermissions(jsonl io.Reader) error { diff --git a/app/plugin_hooks_test.go b/app/plugin_hooks_test.go index f098374ad..0eabbddbc 100644 --- a/app/plugin_hooks_test.go +++ b/app/plugin_hooks_test.go @@ -89,7 +89,7 @@ func TestHookMessageWillBePosted(t *testing.T) { Message: "message_", CreateAt: model.GetMillis() - 10000, } - post, err := th.App.CreatePost(post, th.BasicChannel, false) + _, err := th.App.CreatePost(post, th.BasicChannel, false) if assert.NotNil(t, err) { assert.Equal(t, "Post rejected by plugin. rejected", err.Message) } @@ -129,7 +129,7 @@ func TestHookMessageWillBePosted(t *testing.T) { Message: "message_", CreateAt: model.GetMillis() - 10000, } - post, err := th.App.CreatePost(post, th.BasicChannel, false) + _, err := th.App.CreatePost(post, th.BasicChannel, false) if assert.NotNil(t, err) { assert.Equal(t, "Post rejected by plugin. rejected", err.Message) } @@ -327,7 +327,7 @@ func TestHookMessageHasBeenPosted(t *testing.T) { Message: "message", CreateAt: model.GetMillis() - 10000, } - post, err := th.App.CreatePost(post, th.BasicChannel, false) + _, err := th.App.CreatePost(post, th.BasicChannel, false) if err != nil { t.Fatal(err) } @@ -424,7 +424,7 @@ func TestHookMessageHasBeenUpdated(t *testing.T) { } assert.Equal(t, "message_", post.Message) post.Message = post.Message + "edited" - post, err = th.App.UpdatePost(post, true) + _, err = th.App.UpdatePost(post, true) if err != nil { t.Fatal(err) } @@ -785,7 +785,7 @@ func TestUserHasLoggedIn(t *testing.T) { time.Sleep(2 * time.Second) - user, err = th.App.GetUser(th.BasicUser.Id) + user, _ = th.App.GetUser(th.BasicUser.Id) if user.FirstName != "plugin-callback-success" { t.Errorf("Expected firstname overwrite, got default") diff --git a/app/post.go b/app/post.go index 8cfc6d659..114029f44 100644 --- a/app/post.go +++ b/app/post.go @@ -779,7 +779,7 @@ func (a *App) GetFileInfosForPost(postId string, readFromMaster bool) ([]*model. func (a *App) GetOpenGraphMetadata(requestURL string) *opengraph.OpenGraph { og := opengraph.NewOpenGraph() - res, err := a.HTTPClient(false).Get(requestURL) + res, err := a.HTTPService.MakeClient(false).Get(requestURL) if err != nil { mlog.Error(fmt.Sprintf("GetOpenGraphMetadata request failed for url=%v with err=%v", requestURL, err.Error())) return og @@ -892,9 +892,9 @@ func (a *App) DoPostAction(postId, actionId, userId, selectedOption string) *mod siteURL, _ := url.Parse(*a.Config().ServiceSettings.SiteURL) subpath, _ := utils.GetSubpathFromConfig(a.Config()) if (url.Hostname() == "localhost" || url.Hostname() == "127.0.0.1" || url.Hostname() == siteURL.Hostname()) && strings.HasPrefix(url.Path, path.Join(subpath, "plugins")) { - httpClient = a.HTTPClient(true) + httpClient = a.HTTPService.MakeClient(true) } else { - httpClient = a.HTTPClient(false) + httpClient = a.HTTPService.MakeClient(false) } resp, err := httpClient.Do(req) diff --git a/app/session_test.go b/app/session_test.go index bf8198a4e..8349a4cec 100644 --- a/app/session_test.go +++ b/app/session_test.go @@ -54,8 +54,6 @@ func TestGetSessionIdleTimeoutInMinutes(t *testing.T) { require.Nil(t, err) assert.Equal(t, rsession.Id, session.Id) - rsession, err = th.App.GetSession(session.Token) - // Test regular session, should timeout time := session.LastActivityAt - (1000 * 60 * 6) <-th.App.Srv.Store.Session().UpdateLastActivityAt(session.Id, time) diff --git a/app/team.go b/app/team.go index dd372a99a..e7b25dddf 100644 --- a/app/team.go +++ b/app/team.go @@ -468,7 +468,7 @@ func (a *App) JoinUserToTeam(team *model.Team, user *model.User, userRequestorId if a.PluginsReady() { var actor *model.User if userRequestorId != "" { - actor, err = a.GetUser(userRequestorId) + actor, _ = a.GetUser(userRequestorId) } a.Go(func() { @@ -798,7 +798,7 @@ func (a *App) LeaveTeam(team *model.Team, user *model.User, requestorId string) if a.PluginsReady() { var actor *model.User if requestorId != "" { - actor, err = a.GetUser(requestorId) + actor, _ = a.GetUser(requestorId) } a.Go(func() { diff --git a/app/user.go b/app/user.go index fa4f36ff1..c8df2ca26 100644 --- a/app/user.go +++ b/app/user.go @@ -1176,11 +1176,7 @@ func (a *App) SendPasswordReset(email string, siteURL string) (bool, *model.AppE return false, err } - if _, err := a.SendPasswordResetEmail(user.Email, token, user.Locale, siteURL); err != nil { - return false, model.NewAppError("SendPasswordReset", "api.user.send_password_reset.send.app_error", nil, "err="+err.Message, http.StatusInternalServerError) - } - - return true, nil + return a.SendPasswordResetEmail(user.Email, token, user.Locale, siteURL) } func (a *App) CreatePasswordRecoveryToken(userId string) (*model.Token, *model.AppError) { diff --git a/app/webhook.go b/app/webhook.go index e801b0467..f0264c0c6 100644 --- a/app/webhook.go +++ b/app/webhook.go @@ -107,7 +107,7 @@ func (a *App) TriggerWebhook(payload *model.OutgoingWebhookPayload, hook *model. req, _ := http.NewRequest("POST", url, body) req.Header.Set("Content-Type", contentType) req.Header.Set("Accept", "application/json") - if resp, err := a.HTTPClient(false).Do(req); err != nil { + if resp, err := a.HTTPService.MakeClient(false).Do(req); err != nil { mlog.Error(fmt.Sprintf("Event POST failed, err=%s", err.Error())) } else { defer consumeAndClose(resp) diff --git a/app/webrtc.go b/app/webrtc.go index b10450cab..08601a98c 100644 --- a/app/webrtc.go +++ b/app/webrtc.go @@ -59,7 +59,7 @@ func (a *App) GetWebrtcToken(sessionId string) (string, *model.AppError) { rq, _ := http.NewRequest("POST", *a.Config().WebrtcSettings.GatewayAdminUrl, strings.NewReader(model.MapToJson(data))) rq.Header.Set("Content-Type", "application/json") - if rp, err := a.HTTPClient(true).Do(rq); err != nil { + if rp, err := a.HTTPService.MakeClient(true).Do(rq); err != nil { return "", model.NewAppError("WebRTC.Token", "model.client.connecting.app_error", nil, err.Error(), http.StatusInternalServerError) } else if rp.StatusCode >= 300 { defer consumeAndClose(rp) @@ -93,5 +93,5 @@ func (a *App) RevokeWebrtcToken(sessionId string) { rq.Header.Set("Content-Type", "application/json") // we do not care about the response - a.HTTPClient(true).Do(rq) + a.HTTPService.MakeClient(true).Do(rq) } diff --git a/cmd/mattermost/commands/channel.go b/cmd/mattermost/commands/channel.go index c57a0702d..270ed6586 100644 --- a/cmd/mattermost/commands/channel.go +++ b/cmd/mattermost/commands/channel.go @@ -35,11 +35,12 @@ var ChannelRenameCmd = &cobra.Command{ } var RemoveChannelUsersCmd = &cobra.Command{ - Use: "remove [channel] [users]", - Short: "Remove users from channel", - Long: "Remove some users from channel", - Example: " channel remove myteam:mychannel user@example.com username", - RunE: removeChannelUsersCmdF, + Use: "remove [channel] [users]", + Short: "Remove users from channel", + Long: "Remove some users from channel", + Example: ` channel remove myteam:mychannel user@example.com username + channel remove myteam:mychannel --all-users`, + RunE: removeChannelUsersCmdF, } var AddChannelUsersCmd = &cobra.Command{ @@ -125,6 +126,8 @@ func init() { ChannelRenameCmd.Flags().String("display_name", "", "Channel Display Name") + RemoveChannelUsersCmd.Flags().Bool("all-users", false, "Remove all users from the indicated channel.") + ChannelCmd.AddCommand( ChannelCreateCmd, RemoveChannelUsersCmd, @@ -198,8 +201,14 @@ func removeChannelUsersCmdF(command *cobra.Command, args []string) error { } defer a.Shutdown() - if len(args) < 2 { - return errors.New("Not enough arguments.") + allUsers, _ := command.Flags().GetBool("all-users") + + if allUsers && len(args) != 1 { + return errors.New("individual users must not be specified in conjunction with the --all-users flag") + } + + if !allUsers && len(args) < 2 { + return errors.New("you must specify some users to remove from the channel, or use the --all-users flag to remove them all") } channel := getChannelFromChannelArg(a, args[0]) @@ -207,9 +216,13 @@ func removeChannelUsersCmdF(command *cobra.Command, args []string) error { return errors.New("Unable to find channel '" + args[0] + "'") } - users := getUsersFromUserArgs(a, args[1:]) - for i, user := range users { - removeUserFromChannel(a, channel, user, args[i+1]) + if allUsers { + removeAllUsersFromChannel(a, channel) + } else { + users := getUsersFromUserArgs(a, args[1:]) + for i, user := range users { + removeUserFromChannel(a, channel, user, args[i+1]) + } } return nil @@ -225,6 +238,12 @@ func removeUserFromChannel(a *app.App, channel *model.Channel, user *model.User, } } +func removeAllUsersFromChannel(a *app.App, channel *model.Channel) { + if result := <-a.Srv.Store.Channel().PermanentDeleteMembersByChannel(channel.Id); result.Err != nil { + CommandPrintErrorln("Unable to remove all users from " + channel.Name + ". Error: " + result.Err.Error()) + } +} + func addChannelUsersCmdF(command *cobra.Command, args []string) error { a, err := InitDBCommandContextCobra(command) if err != nil { diff --git a/cmd/mattermost/commands/permissions.go b/cmd/mattermost/commands/permissions.go index 9d9962ce5..01d933a98 100644 --- a/cmd/mattermost/commands/permissions.go +++ b/cmd/mattermost/commands/permissions.go @@ -124,9 +124,5 @@ func importPermissionsCmdF(command *cobra.Command, args []string) error { } defer file.Close() - if err := a.ImportPermissions(file); err != nil { - return err - } - - return nil + return a.ImportPermissions(file) } diff --git a/cmd/mattermost/commands/permissions_test.go b/cmd/mattermost/commands/permissions_test.go index eeaa17109..54ccbddb8 100644 --- a/cmd/mattermost/commands/permissions_test.go +++ b/cmd/mattermost/commands/permissions_test.go @@ -30,7 +30,7 @@ func permissionsLicenseRequiredTest(t *testing.T, subcommand string) { t.Fail() } args := []string{"-test.run", "ExecCommand", "--", "--disableconfigwatch", "permissions", subcommand} - output, err := exec.Command(path, args...).CombinedOutput() + output, _ := exec.Command(path, args...).CombinedOutput() actual := string(output) expected := utils.T("cli.license.critical") diff --git a/i18n/en.json b/i18n/en.json index 5345fa0cf..0ad1722fc 100644 --- a/i18n/en.json +++ b/i18n/en.json @@ -1009,6 +1009,10 @@ "translation": "Unable to create emoji. File must be a PNG, JPEG, or GIF." }, { + "id": "api.emoji.upload.large_image.too_large.app_error", + "translation": "Unable to create emoji. Image must be smaller than {{.MaxWidth}} by {{.MaxHeight}}." + }, + { "id": "api.emoji.upload.large_image.decode_error", "translation": "Unable to create emoji. An error occurred when trying to decode the image." }, diff --git a/model/config.go b/model/config.go index c0f443b72..5cc1a4edc 100644 --- a/model/config.go +++ b/model/config.go @@ -2370,7 +2370,7 @@ func (ss *ServiceSettings) isValid() *AppError { } } - host, port, err := net.SplitHostPort(*ss.ListenAddress) + host, port, _ := net.SplitHostPort(*ss.ListenAddress) var isValidHost bool if host == "" { isValidHost = true diff --git a/model/incoming_webhook.go b/model/incoming_webhook.go index 1d6d7b4f0..3856d22ff 100644 --- a/model/incoming_webhook.go +++ b/model/incoming_webhook.go @@ -93,7 +93,7 @@ func (o *IncomingWebhook) IsValid() *AppError { return NewAppError("IncomingWebhook.IsValid", "model.incoming_hook.display_name.app_error", nil, "", http.StatusBadRequest) } - if len(o.Description) > 128 { + if len(o.Description) > 500 { return NewAppError("IncomingWebhook.IsValid", "model.incoming_hook.description.app_error", nil, "", http.StatusBadRequest) } diff --git a/model/incoming_webhook_test.go b/model/incoming_webhook_test.go index 5498a6a0c..3f7d13695 100644 --- a/model/incoming_webhook_test.go +++ b/model/incoming_webhook_test.go @@ -80,12 +80,12 @@ func TestIncomingWebhookIsValid(t *testing.T) { t.Fatal(err) } - o.Description = strings.Repeat("1", 129) + o.Description = strings.Repeat("1", 501) if err := o.IsValid(); err == nil { t.Fatal("should be invalid") } - o.Description = strings.Repeat("1", 128) + o.Description = strings.Repeat("1", 500) if err := o.IsValid(); err != nil { t.Fatal(err) } diff --git a/model/outgoing_webhook.go b/model/outgoing_webhook.go index 698a226e3..5f7a67d04 100644 --- a/model/outgoing_webhook.go +++ b/model/outgoing_webhook.go @@ -171,7 +171,7 @@ func (o *OutgoingWebhook) IsValid() *AppError { return NewAppError("OutgoingWebhook.IsValid", "model.outgoing_hook.is_valid.display_name.app_error", nil, "", http.StatusBadRequest) } - if len(o.Description) > 128 { + if len(o.Description) > 500 { return NewAppError("OutgoingWebhook.IsValid", "model.outgoing_hook.is_valid.description.app_error", nil, "", http.StatusBadRequest) } diff --git a/model/outgoing_webhook_test.go b/model/outgoing_webhook_test.go index 3241e649f..5403fca6f 100644 --- a/model/outgoing_webhook_test.go +++ b/model/outgoing_webhook_test.go @@ -102,14 +102,14 @@ func TestOutgoingWebhookIsValid(t *testing.T) { t.Fatal(err) } - o.Description = strings.Repeat("1", 129) + o.Description = strings.Repeat("1", 501) if err := o.IsValid(); err == nil { t.Fatal("should be invalid") } - o.Description = strings.Repeat("1", 128) + o.Description = strings.Repeat("1", 500) if err := o.IsValid(); err != nil { - t.Fatal("should be invalid") + t.Fatal(err) } o.ContentType = strings.Repeat("1", 129) diff --git a/model/session_test.go b/model/session_test.go index bf32d2f09..88e0bdd43 100644 --- a/model/session_test.go +++ b/model/session_test.go @@ -31,7 +31,7 @@ func TestSessionDeepCopy(t *testing.T) { session = &Session{Id: sessionId} copySession = session.DeepCopy() - assert.Equal(t, sessionId, session.Id) + assert.Equal(t, sessionId, copySession.Id) session = &Session{TeamMembers: []*TeamMember{}} copySession = session.DeepCopy() diff --git a/model/user_test.go b/model/user_test.go index f86b52919..d7f7b6711 100644 --- a/model/user_test.go +++ b/model/user_test.go @@ -52,7 +52,7 @@ func TestUserDeepCopy(t *testing.T) { user = &User{Id: id} copyUser = user.DeepCopy() - assert.Equal(t, id, user.Id) + assert.Equal(t, id, copyUser.Id) } func TestUserJson(t *testing.T) { diff --git a/plugin/client_rpc.go b/plugin/client_rpc.go index dde4c5f2e..d8547f352 100644 --- a/plugin/client_rpc.go +++ b/plugin/client_rpc.go @@ -265,7 +265,7 @@ func (g *hooksRPCClient) ServeHTTP(c *Context, w http.ResponseWriter, r *http.Re go func() { bodyConnection, err := g.muxBroker.Accept(requestBodyStreamId) if err != nil { - g.log.Error("Plugin failed to ServeHTTP, muxBroker couldn't Accept request body connecion", mlog.Err(err)) + g.log.Error("Plugin failed to ServeHTTP, muxBroker couldn't Accept request body connection", mlog.Err(err)) http.Error(w, "500 internal server error", http.StatusInternalServerError) return } @@ -295,7 +295,6 @@ func (g *hooksRPCClient) ServeHTTP(c *Context, w http.ResponseWriter, r *http.Re g.log.Error("Plugin failed to ServeHTTP, RPC call failed", mlog.Err(err)) http.Error(w, "500 internal server error", http.StatusInternalServerError) } - return } func (s *hooksRPCServer) ServeHTTP(args *Z_ServeHTTPArgs, returns *struct{}) error { diff --git a/plugin/client_rpc_generated.go b/plugin/client_rpc_generated.go index d0d576f8d..9cebda716 100644 --- a/plugin/client_rpc_generated.go +++ b/plugin/client_rpc_generated.go @@ -209,7 +209,7 @@ func (g *hooksRPCClient) MessageHasBeenPosted(c *Context, post *model.Post) { g.log.Error("RPC call MessageHasBeenPosted to plugin failed.", mlog.Err(err)) } } - return + } func (s *hooksRPCServer) MessageHasBeenPosted(args *Z_MessageHasBeenPostedArgs, returns *Z_MessageHasBeenPostedReturns) error { @@ -244,7 +244,7 @@ func (g *hooksRPCClient) MessageHasBeenUpdated(c *Context, newPost, oldPost *mod g.log.Error("RPC call MessageHasBeenUpdated to plugin failed.", mlog.Err(err)) } } - return + } func (s *hooksRPCServer) MessageHasBeenUpdated(args *Z_MessageHasBeenUpdatedArgs, returns *Z_MessageHasBeenUpdatedReturns) error { @@ -278,7 +278,7 @@ func (g *hooksRPCClient) ChannelHasBeenCreated(c *Context, channel *model.Channe g.log.Error("RPC call ChannelHasBeenCreated to plugin failed.", mlog.Err(err)) } } - return + } func (s *hooksRPCServer) ChannelHasBeenCreated(args *Z_ChannelHasBeenCreatedArgs, returns *Z_ChannelHasBeenCreatedReturns) error { @@ -313,7 +313,7 @@ func (g *hooksRPCClient) UserHasJoinedChannel(c *Context, channelMember *model.C g.log.Error("RPC call UserHasJoinedChannel to plugin failed.", mlog.Err(err)) } } - return + } func (s *hooksRPCServer) UserHasJoinedChannel(args *Z_UserHasJoinedChannelArgs, returns *Z_UserHasJoinedChannelReturns) error { @@ -348,7 +348,7 @@ func (g *hooksRPCClient) UserHasLeftChannel(c *Context, channelMember *model.Cha g.log.Error("RPC call UserHasLeftChannel to plugin failed.", mlog.Err(err)) } } - return + } func (s *hooksRPCServer) UserHasLeftChannel(args *Z_UserHasLeftChannelArgs, returns *Z_UserHasLeftChannelReturns) error { @@ -383,7 +383,7 @@ func (g *hooksRPCClient) UserHasJoinedTeam(c *Context, teamMember *model.TeamMem g.log.Error("RPC call UserHasJoinedTeam to plugin failed.", mlog.Err(err)) } } - return + } func (s *hooksRPCServer) UserHasJoinedTeam(args *Z_UserHasJoinedTeamArgs, returns *Z_UserHasJoinedTeamReturns) error { @@ -418,7 +418,7 @@ func (g *hooksRPCClient) UserHasLeftTeam(c *Context, teamMember *model.TeamMembe g.log.Error("RPC call UserHasLeftTeam to plugin failed.", mlog.Err(err)) } } - return + } func (s *hooksRPCServer) UserHasLeftTeam(args *Z_UserHasLeftTeamArgs, returns *Z_UserHasLeftTeamReturns) error { @@ -487,7 +487,7 @@ func (g *hooksRPCClient) UserHasLoggedIn(c *Context, user *model.User) { g.log.Error("RPC call UserHasLoggedIn to plugin failed.", mlog.Err(err)) } } - return + } func (s *hooksRPCServer) UserHasLoggedIn(args *Z_UserHasLoggedInArgs, returns *Z_UserHasLoggedInReturns) error { @@ -2125,7 +2125,7 @@ func (g *apiRPCClient) PublishWebSocketEvent(event string, payload map[string]in if err := g.client.Call("Plugin.PublishWebSocketEvent", _args, _returns); err != nil { log.Printf("RPC call to PublishWebSocketEvent API failed: %s", err.Error()) } - return + } func (s *apiRPCServer) PublishWebSocketEvent(args *Z_PublishWebSocketEventArgs, returns *Z_PublishWebSocketEventReturns) error { @@ -2242,7 +2242,7 @@ func (g *apiRPCClient) LogDebug(msg string, keyValuePairs ...interface{}) { if err := g.client.Call("Plugin.LogDebug", _args, _returns); err != nil { log.Printf("RPC call to LogDebug API failed: %s", err.Error()) } - return + } func (s *apiRPCServer) LogDebug(args *Z_LogDebugArgs, returns *Z_LogDebugReturns) error { @@ -2270,7 +2270,7 @@ func (g *apiRPCClient) LogInfo(msg string, keyValuePairs ...interface{}) { if err := g.client.Call("Plugin.LogInfo", _args, _returns); err != nil { log.Printf("RPC call to LogInfo API failed: %s", err.Error()) } - return + } func (s *apiRPCServer) LogInfo(args *Z_LogInfoArgs, returns *Z_LogInfoReturns) error { @@ -2298,7 +2298,7 @@ func (g *apiRPCClient) LogError(msg string, keyValuePairs ...interface{}) { if err := g.client.Call("Plugin.LogError", _args, _returns); err != nil { log.Printf("RPC call to LogError API failed: %s", err.Error()) } - return + } func (s *apiRPCServer) LogError(args *Z_LogErrorArgs, returns *Z_LogErrorReturns) error { @@ -2326,7 +2326,7 @@ func (g *apiRPCClient) LogWarn(msg string, keyValuePairs ...interface{}) { if err := g.client.Call("Plugin.LogWarn", _args, _returns); err != nil { log.Printf("RPC call to LogWarn API failed: %s", err.Error()) } - return + } func (s *apiRPCServer) LogWarn(args *Z_LogWarnArgs, returns *Z_LogWarnReturns) error { diff --git a/plugin/environment.go b/plugin/environment.go index 5c3a98349..55543e239 100644 --- a/plugin/environment.go +++ b/plugin/environment.go @@ -18,7 +18,6 @@ import ( ) type apiImplCreatorFunc func(*model.Manifest) API -type supervisorCreatorFunc func(*model.BundleInfo, *mlog.Logger, API) (*supervisor, error) // multiPluginHookRunnerFunc is a callback function to invoke as part of RunMultiPluginHook. // diff --git a/plugin/interface_generator/main.go b/plugin/interface_generator/main.go index b321c344a..6aa8bdfb1 100644 --- a/plugin/interface_generator/main.go +++ b/plugin/interface_generator/main.go @@ -229,7 +229,7 @@ func (g *hooksRPCClient) {{.Name}}{{funcStyle .Params}} {{funcStyle .Return}} { g.log.Error("RPC call {{.Name}} to plugin failed.", mlog.Err(err)) } } - return {{destruct "_returns." .Return}} + {{ if .Return }} return {{destruct "_returns." .Return}} {{ end }} } func (s *hooksRPCServer) {{.Name}}(args *{{.Name | obscure}}Args, returns *{{.Name | obscure}}Returns) error { @@ -260,7 +260,7 @@ func (g *apiRPCClient) {{.Name}}{{funcStyle .Params}} {{funcStyle .Return}} { if err := g.client.Call("Plugin.{{.Name}}", _args, _returns); err != nil { log.Printf("RPC call to {{.Name}} API failed: %s", err.Error()) } - return {{destruct "_returns." .Return}} + {{ if .Return }} return {{destruct "_returns." .Return}} {{ end }} } func (s *apiRPCServer) {{.Name}}(args *{{.Name | obscure}}Args, returns *{{.Name | obscure}}Returns) error { diff --git a/plugin/io_rpc.go b/plugin/io_rpc.go index 18a1eb525..fad7373a1 100644 --- a/plugin/io_rpc.go +++ b/plugin/io_rpc.go @@ -9,19 +9,6 @@ import ( "io" ) -type rwc struct { - io.ReadCloser - io.WriteCloser -} - -func (rwc *rwc) Close() (err error) { - err = rwc.WriteCloser.Close() - if rerr := rwc.ReadCloser.Close(); err == nil { - err = rerr - } - return -} - type remoteIOReader struct { conn io.ReadWriteCloser } diff --git a/plugin/supervisor.go b/plugin/supervisor.go index 33243e9cf..1165f5fb3 100644 --- a/plugin/supervisor.go +++ b/plugin/supervisor.go @@ -17,7 +17,6 @@ import ( ) type supervisor struct { - pluginId string client *plugin.Client hooks Hooks implemented [TotalHooksId]bool diff --git a/store/sqlstore/channel_store.go b/store/sqlstore/channel_store.go index fba37d7cb..1b5ae7ff7 100644 --- a/store/sqlstore/channel_store.go +++ b/store/sqlstore/channel_store.go @@ -1864,7 +1864,7 @@ func (s SqlChannelStore) ClearAllCustomRoleAssignments() store.StoreChannel { lastUserId := strings.Repeat("0", 26) lastChannelId := strings.Repeat("0", 26) - for true { + for { var transaction *gorp.Transaction var err error diff --git a/store/sqlstore/team_store.go b/store/sqlstore/team_store.go index d9e33df76..3ea6feced 100644 --- a/store/sqlstore/team_store.go +++ b/store/sqlstore/team_store.go @@ -851,7 +851,7 @@ func (s SqlTeamStore) ClearAllCustomRoleAssignments() store.StoreChannel { lastUserId := strings.Repeat("0", 26) lastTeamId := strings.Repeat("0", 26) - for true { + for { var transaction *gorp.Transaction var err error diff --git a/store/sqlstore/upgrade.go b/store/sqlstore/upgrade.go index cd45dfcb3..5f74dbfb1 100644 --- a/store/sqlstore/upgrade.go +++ b/store/sqlstore/upgrade.go @@ -15,6 +15,7 @@ import ( ) const ( + VERSION_5_4_0 = "5.4.0" VERSION_5_3_0 = "5.3.0" VERSION_5_2_0 = "5.2.0" VERSION_5_1_0 = "5.1.0" @@ -84,6 +85,7 @@ func UpgradeDatabase(sqlStore SqlStore) { UpgradeDatabaseToVersion51(sqlStore) UpgradeDatabaseToVersion52(sqlStore) UpgradeDatabaseToVersion53(sqlStore) + UpgradeDatabaseToVersion54(sqlStore) // If the SchemaVersion is empty this this is the first time it has ran // so lets set it to the current version. @@ -487,4 +489,14 @@ func UpgradeDatabaseToVersion53(sqlStore SqlStore) { if shouldPerformUpgrade(sqlStore, VERSION_5_2_0, VERSION_5_3_0) { saveSchemaVersion(sqlStore, VERSION_5_3_0) } + +} + +func UpgradeDatabaseToVersion54(sqlStore SqlStore) { + // TODO: Uncomment following condition when version 5.4.0 is released + // if shouldPerformUpgrade(sqlStore, VERSION_5_3_0, VERSION_5_4_0) { + sqlStore.AlterColumnTypeIfExists("OutgoingWebhooks", "Description", "varchar(500)", "varchar(500)") + sqlStore.AlterColumnTypeIfExists("IncomingWebhooks", "Description", "varchar(500)", "varchar(500)") + // saveSchemaVersion(sqlStore, VERSION_5_4_0) + // } } diff --git a/store/sqlstore/user_store.go b/store/sqlstore/user_store.go index d8a77cd9d..c89c445ad 100644 --- a/store/sqlstore/user_store.go +++ b/store/sqlstore/user_store.go @@ -1255,7 +1255,7 @@ func (us SqlUserStore) ClearAllCustomRoleAssignments() store.StoreChannel { builtInRoles := model.MakeDefaultRoles() lastUserId := strings.Repeat("0", 26) - for true { + for { var transaction *gorp.Transaction var err error diff --git a/store/sqlstore/webhook_store.go b/store/sqlstore/webhook_store.go index f3c572aaf..94eadf836 100644 --- a/store/sqlstore/webhook_store.go +++ b/store/sqlstore/webhook_store.go @@ -47,7 +47,7 @@ func NewSqlWebhookStore(sqlStore SqlStore, metrics einterfaces.MetricsInterface) table.ColMap("ChannelId").SetMaxSize(26) table.ColMap("TeamId").SetMaxSize(26) table.ColMap("DisplayName").SetMaxSize(64) - table.ColMap("Description").SetMaxSize(128) + table.ColMap("Description").SetMaxSize(500) tableo := db.AddTableWithName(model.OutgoingWebhook{}, "OutgoingWebhooks").SetKeys(false, "Id") tableo.ColMap("Id").SetMaxSize(26) @@ -58,7 +58,7 @@ func NewSqlWebhookStore(sqlStore SqlStore, metrics einterfaces.MetricsInterface) tableo.ColMap("TriggerWords").SetMaxSize(1024) tableo.ColMap("CallbackURLs").SetMaxSize(1024) tableo.ColMap("DisplayName").SetMaxSize(64) - tableo.ColMap("Description").SetMaxSize(128) + tableo.ColMap("Description").SetMaxSize(500) tableo.ColMap("ContentType").SetMaxSize(128) tableo.ColMap("TriggerWhen").SetMaxSize(1) tableo.ColMap("Username").SetMaxSize(64) diff --git a/store/storetest/channel_store.go b/store/storetest/channel_store.go index c827a4226..776434b6e 100644 --- a/store/storetest/channel_store.go +++ b/store/storetest/channel_store.go @@ -2287,9 +2287,9 @@ func testChannelStoreGetChannelsByScheme(t *testing.T, ss store.Store) { Type: model.CHANNEL_OPEN, } - c1 = (<-ss.Channel().Save(c1, 100)).Data.(*model.Channel) - c2 = (<-ss.Channel().Save(c2, 100)).Data.(*model.Channel) - c3 = (<-ss.Channel().Save(c3, 100)).Data.(*model.Channel) + _ = (<-ss.Channel().Save(c1, 100)).Data.(*model.Channel) + _ = (<-ss.Channel().Save(c2, 100)).Data.(*model.Channel) + _ = (<-ss.Channel().Save(c3, 100)).Data.(*model.Channel) // Get the channels by a valid Scheme ID. res1 := <-ss.Channel().GetChannelsByScheme(s1.Id, 0, 100) diff --git a/store/storetest/command_store.go b/store/storetest/command_store.go index ffc575563..ba6c26482 100644 --- a/store/storetest/command_store.go +++ b/store/storetest/command_store.go @@ -105,7 +105,7 @@ func testCommandStoreGetByTrigger(t *testing.T, ss store.Store) { o2.Trigger = "trigger1" o1 = (<-ss.Command().Save(o1)).Data.(*model.Command) - o2 = (<-ss.Command().Save(o2)).Data.(*model.Command) + _ = (<-ss.Command().Save(o2)).Data.(*model.Command) if r1 := <-ss.Command().GetByTrigger(o1.TeamId, o1.Trigger); r1.Err != nil { t.Fatal(r1.Err) diff --git a/store/storetest/compliance_store.go b/store/storetest/compliance_store.go index f7f095a00..14ed29865 100644 --- a/store/storetest/compliance_store.go +++ b/store/storetest/compliance_store.go @@ -108,14 +108,14 @@ func testComplianceExport(t *testing.T, ss store.Store) { o1a.UserId = u1.Id o1a.CreateAt = o1.CreateAt + 10 o1a.Message = "zz" + model.NewId() + "b" - o1a = store.Must(ss.Post().Save(o1a)).(*model.Post) + _ = store.Must(ss.Post().Save(o1a)).(*model.Post) o2 := &model.Post{} o2.ChannelId = c1.Id o2.UserId = u1.Id o2.CreateAt = o1.CreateAt + 20 o2.Message = "zz" + model.NewId() + "b" - o2 = store.Must(ss.Post().Save(o2)).(*model.Post) + _ = store.Must(ss.Post().Save(o2)).(*model.Post) o2a := &model.Post{} o2a.ChannelId = c1.Id @@ -272,21 +272,21 @@ func testComplianceExportDirectMessages(t *testing.T, ss store.Store) { o1a.UserId = u1.Id o1a.CreateAt = o1.CreateAt + 10 o1a.Message = "zz" + model.NewId() + "b" - o1a = store.Must(ss.Post().Save(o1a)).(*model.Post) + _ = store.Must(ss.Post().Save(o1a)).(*model.Post) o2 := &model.Post{} o2.ChannelId = c1.Id o2.UserId = u1.Id o2.CreateAt = o1.CreateAt + 20 o2.Message = "zz" + model.NewId() + "b" - o2 = store.Must(ss.Post().Save(o2)).(*model.Post) + _ = store.Must(ss.Post().Save(o2)).(*model.Post) o2a := &model.Post{} o2a.ChannelId = c1.Id o2a.UserId = u2.Id o2a.CreateAt = o1.CreateAt + 30 o2a.Message = "zz" + model.NewId() + "b" - o2a = store.Must(ss.Post().Save(o2a)).(*model.Post) + _ = store.Must(ss.Post().Save(o2a)).(*model.Post) o3 := &model.Post{} o3.ChannelId = cDM.Id diff --git a/store/storetest/job_store.go b/store/storetest/job_store.go index 631df08fd..936999f52 100644 --- a/store/storetest/job_store.go +++ b/store/storetest/job_store.go @@ -492,7 +492,6 @@ func testJobUpdateStatusUpdateStatusOptimistically(t *testing.T, ss store.Store) if received.LastActivityAt <= lastUpdateAt { t.Fatal("lastActivityAt wasn't updated") } - lastUpdateAt = received.LastActivityAt } } diff --git a/store/storetest/post_store.go b/store/storetest/post_store.go index 235d6f9b7..72819f49e 100644 --- a/store/storetest/post_store.go +++ b/store/storetest/post_store.go @@ -514,7 +514,7 @@ func testPostStoreGetPostsWithDetails(t *testing.T, ss store.Store) { o2.Message = "zz" + model.NewId() + "b" o2.ParentId = o1.Id o2.RootId = o1.Id - o2 = (<-ss.Post().Save(o2)).Data.(*model.Post) + _ = (<-ss.Post().Save(o2)).Data.(*model.Post) time.Sleep(2 * time.Millisecond) o2a := &model.Post{} @@ -609,7 +609,7 @@ func testPostStoreGetPostsWithDetails(t *testing.T, ss store.Store) { o6.ChannelId = o1.ChannelId o6.UserId = model.NewId() o6.Message = "zz" + model.NewId() + "b" - o6 = (<-ss.Post().Save(o6)).Data.(*model.Post) + _ = (<-ss.Post().Save(o6)).Data.(*model.Post) // Should only be 6 since we hit the cache r3 := (<-ss.Post().GetPosts(o1.ChannelId, 0, 30, true)).Data.(*model.PostList) @@ -627,7 +627,7 @@ func testPostStoreGetPostsBeforeAfter(t *testing.T, ss store.Store) { o0.ChannelId = model.NewId() o0.UserId = model.NewId() o0.Message = "zz" + model.NewId() + "b" - o0 = (<-ss.Post().Save(o0)).Data.(*model.Post) + _ = (<-ss.Post().Save(o0)).Data.(*model.Post) time.Sleep(2 * time.Millisecond) o1 := &model.Post{} @@ -677,7 +677,7 @@ func testPostStoreGetPostsBeforeAfter(t *testing.T, ss store.Store) { o5.Message = "zz" + model.NewId() + "b" o5.ParentId = o4.Id o5.RootId = o4.Id - o5 = (<-ss.Post().Save(o5)).Data.(*model.Post) + _ = (<-ss.Post().Save(o5)).Data.(*model.Post) r1 := (<-ss.Post().GetPostsBefore(o1.ChannelId, o1.Id, 4, 0)).Data.(*model.PostList) @@ -731,7 +731,7 @@ func testPostStoreGetPostsSince(t *testing.T, ss store.Store) { o0.ChannelId = model.NewId() o0.UserId = model.NewId() o0.Message = "zz" + model.NewId() + "b" - o0 = (<-ss.Post().Save(o0)).Data.(*model.Post) + _ = (<-ss.Post().Save(o0)).Data.(*model.Post) time.Sleep(2 * time.Millisecond) o1 := &model.Post{} @@ -747,7 +747,7 @@ func testPostStoreGetPostsSince(t *testing.T, ss store.Store) { o2.Message = "zz" + model.NewId() + "b" o2.ParentId = o1.Id o2.RootId = o1.Id - o2 = (<-ss.Post().Save(o2)).Data.(*model.Post) + _ = (<-ss.Post().Save(o2)).Data.(*model.Post) time.Sleep(2 * time.Millisecond) o2a := &model.Post{} @@ -865,7 +865,7 @@ func testPostStoreSearch(t *testing.T, ss store.Store) { o1a.UserId = model.NewId() o1a.Message = "corey mattermost new york" o1a.Type = model.POST_JOIN_CHANNEL - o1a = (<-ss.Post().Save(o1a)).Data.(*model.Post) + _ = (<-ss.Post().Save(o1a)).Data.(*model.Post) o2 := &model.Post{} o2.ChannelId = c1.Id @@ -877,7 +877,7 @@ func testPostStoreSearch(t *testing.T, ss store.Store) { o3.ChannelId = c2.Id o3.UserId = model.NewId() o3.Message = "New Jersey is where John is from corey new york" - o3 = (<-ss.Post().Save(o3)).Data.(*model.Post) + _ = (<-ss.Post().Save(o3)).Data.(*model.Post) o4 := &model.Post{} o4.ChannelId = c1.Id @@ -1045,7 +1045,7 @@ func testUserCountsWithPostsByDay(t *testing.T, ss store.Store) { o1a.UserId = model.NewId() o1a.CreateAt = o1.CreateAt o1a.Message = "zz" + model.NewId() + "b" - o1a = store.Must(ss.Post().Save(o1a)).(*model.Post) + _ = store.Must(ss.Post().Save(o1a)).(*model.Post) o2 := &model.Post{} o2.ChannelId = c1.Id @@ -1059,7 +1059,7 @@ func testUserCountsWithPostsByDay(t *testing.T, ss store.Store) { o2a.UserId = o2.UserId o2a.CreateAt = o1.CreateAt - (1000 * 60 * 60 * 24) o2a.Message = "zz" + model.NewId() + "b" - o2a = store.Must(ss.Post().Save(o2a)).(*model.Post) + _ = store.Must(ss.Post().Save(o2a)).(*model.Post) if r1 := <-ss.Post().AnalyticsUserCountsWithPostsByDay(t1.Id); r1.Err != nil { t.Fatal(r1.Err) @@ -1103,7 +1103,7 @@ func testPostCountsByDay(t *testing.T, ss store.Store) { o1a.UserId = model.NewId() o1a.CreateAt = o1.CreateAt o1a.Message = "zz" + model.NewId() + "b" - o1a = store.Must(ss.Post().Save(o1a)).(*model.Post) + _ = store.Must(ss.Post().Save(o1a)).(*model.Post) o2 := &model.Post{} o2.ChannelId = c1.Id @@ -1117,7 +1117,7 @@ func testPostCountsByDay(t *testing.T, ss store.Store) { o2a.UserId = o2.UserId o2a.CreateAt = o1.CreateAt - (1000 * 60 * 60 * 24 * 2) o2a.Message = "zz" + model.NewId() + "b" - o2a = store.Must(ss.Post().Save(o2a)).(*model.Post) + _ = store.Must(ss.Post().Save(o2a)).(*model.Post) time.Sleep(1 * time.Second) @@ -1534,14 +1534,14 @@ func testPostStoreGetPostsCreatedAt(t *testing.T, ss store.Store) { o2.ParentId = o1.Id o2.RootId = o1.Id o2.CreateAt = createTime + 1 - o2 = (<-ss.Post().Save(o2)).Data.(*model.Post) + _ = (<-ss.Post().Save(o2)).Data.(*model.Post) o3 := &model.Post{} o3.ChannelId = model.NewId() o3.UserId = model.NewId() o3.Message = "zz" + model.NewId() + "b" o3.CreateAt = createTime - o3 = (<-ss.Post().Save(o3)).Data.(*model.Post) + _ = (<-ss.Post().Save(o3)).Data.(*model.Post) r1 := (<-ss.Post().GetPostsCreatedAt(o1.ChannelId, createTime)).Data.([]*model.Post) assert.Equal(t, 2, len(r1)) diff --git a/store/storetest/scheme_store.go b/store/storetest/scheme_store.go index f855ae5d4..a9204fbe2 100644 --- a/store/storetest/scheme_store.go +++ b/store/storetest/scheme_store.go @@ -20,6 +20,7 @@ func TestSchemeStore(t *testing.T, ss store.Store) { t.Run("GetAllPage", func(t *testing.T) { testSchemeStoreGetAllPage(t, ss) }) t.Run("Delete", func(t *testing.T) { testSchemeStoreDelete(t, ss) }) t.Run("PermanentDeleteAll", func(t *testing.T) { testSchemeStorePermanentDeleteAll(t, ss) }) + t.Run("GetByName", func(t *testing.T) { testSchemeStoreGetByName(t, ss) }) } func createDefaultRoles(t *testing.T, ss store.Store) { diff --git a/store/storetest/team_store.go b/store/storetest/team_store.go index ede1a91d3..1369dc69b 100644 --- a/store/storetest/team_store.go +++ b/store/storetest/team_store.go @@ -1088,9 +1088,9 @@ func testGetTeamsByScheme(t *testing.T, ss store.Store) { Type: model.TEAM_OPEN, } - t1 = (<-ss.Team().Save(t1)).Data.(*model.Team) - t2 = (<-ss.Team().Save(t2)).Data.(*model.Team) - t3 = (<-ss.Team().Save(t3)).Data.(*model.Team) + _ = (<-ss.Team().Save(t1)).Data.(*model.Team) + _ = (<-ss.Team().Save(t2)).Data.(*model.Team) + _ = (<-ss.Team().Save(t3)).Data.(*model.Team) // Get the teams by a valid Scheme ID. res1 := <-ss.Team().GetTeamsByScheme(s1.Id, 0, 100) @@ -1286,7 +1286,7 @@ func testTeamStoreAnalyticsGetTeamCountForScheme(t *testing.T, ss store.Store) { Type: model.TEAM_OPEN, SchemeId: &s1.Id, } - t1 = (<-ss.Team().Save(t1)).Data.(*model.Team) + _ = (<-ss.Team().Save(t1)).Data.(*model.Team) count2 := (<-ss.Team().AnalyticsGetTeamCountForScheme(s1.Id)).Data.(int64) assert.Equal(t, int64(1), count2) @@ -1298,7 +1298,7 @@ func testTeamStoreAnalyticsGetTeamCountForScheme(t *testing.T, ss store.Store) { Type: model.TEAM_OPEN, SchemeId: &s1.Id, } - t2 = (<-ss.Team().Save(t2)).Data.(*model.Team) + _ = (<-ss.Team().Save(t2)).Data.(*model.Team) count3 := (<-ss.Team().AnalyticsGetTeamCountForScheme(s1.Id)).Data.(int64) assert.Equal(t, int64(2), count3) @@ -1309,7 +1309,7 @@ func testTeamStoreAnalyticsGetTeamCountForScheme(t *testing.T, ss store.Store) { Email: MakeEmail(), Type: model.TEAM_OPEN, } - t3 = (<-ss.Team().Save(t3)).Data.(*model.Team) + _ = (<-ss.Team().Save(t3)).Data.(*model.Team) count4 := (<-ss.Team().AnalyticsGetTeamCountForScheme(s1.Id)).Data.(int64) assert.Equal(t, int64(2), count4) @@ -1322,7 +1322,7 @@ func testTeamStoreAnalyticsGetTeamCountForScheme(t *testing.T, ss store.Store) { SchemeId: &s1.Id, DeleteAt: model.GetMillis(), } - t4 = (<-ss.Team().Save(t4)).Data.(*model.Team) + _ = (<-ss.Team().Save(t4)).Data.(*model.Team) count5 := (<-ss.Team().AnalyticsGetTeamCountForScheme(s1.Id)).Data.(int64) assert.Equal(t, int64(2), count5) diff --git a/store/storetest/webhook_store.go b/store/storetest/webhook_store.go index 2dfa2ae53..2b30f2d33 100644 --- a/store/storetest/webhook_store.go +++ b/store/storetest/webhook_store.go @@ -484,7 +484,7 @@ func testWebhookStoreCountIncoming(t *testing.T, ss store.Store) { o1.UserId = model.NewId() o1.TeamId = model.NewId() - o1 = (<-ss.Webhook().SaveIncoming(o1)).Data.(*model.IncomingWebhook) + _ = (<-ss.Webhook().SaveIncoming(o1)).Data.(*model.IncomingWebhook) if r := <-ss.Webhook().AnalyticsIncomingCount(""); r.Err != nil { t.Fatal(r.Err) @@ -502,7 +502,7 @@ func testWebhookStoreCountOutgoing(t *testing.T, ss store.Store) { o1.TeamId = model.NewId() o1.CallbackURLs = []string{"http://nowhere.com/"} - o1 = (<-ss.Webhook().SaveOutgoing(o1)).Data.(*model.OutgoingWebhook) + _ = (<-ss.Webhook().SaveOutgoing(o1)).Data.(*model.OutgoingWebhook) if r := <-ss.Webhook().AnalyticsOutgoingCount(""); r.Err != nil { t.Fatal(r.Err) diff --git a/utils/config.go b/utils/config.go index 7e5a42faa..786e248ca 100644 --- a/utils/config.go +++ b/utils/config.go @@ -51,9 +51,7 @@ func FindPath(path string, baseSearchPaths []string, filter func(os.FileInfo) bo } searchPaths := []string{} - for _, baseSearchPath := range baseSearchPaths { - searchPaths = append(searchPaths, baseSearchPath) - } + searchPaths = append(searchPaths, baseSearchPaths...) // Additionally attempt to search relative to the location of the running binary. var binaryDir string diff --git a/utils/i18n.go b/utils/i18n.go index d7c55e4e6..4fcd7669d 100644 --- a/utils/i18n.go +++ b/utils/i18n.go @@ -27,12 +27,7 @@ func TranslationsPreInit() error { // segfault trying to handle the error, and the untranslated IDs are strictly better. T = TfuncWithFallback("en") TDefault = TfuncWithFallback("en") - - if err := InitTranslationsWithDir("i18n"); err != nil { - return err - } - - return nil + return InitTranslationsWithDir("i18n") } func InitTranslations(localizationSettings model.LocalizationSettings) error { diff --git a/utils/jsonutils/json_test.go b/utils/jsonutils/json_test.go index b3986e87b..85cb66d60 100644 --- a/utils/jsonutils/json_test.go +++ b/utils/jsonutils/json_test.go @@ -76,8 +76,6 @@ func TestHumanizeJsonError(t *testing.T) { func TestNewHumanizedJsonError(t *testing.T) { t.Parallel() - type testType struct{} - testCases := []struct { Description string Data []byte diff --git a/utils/mail.go b/utils/mail.go index 7b0cb3588..750cb64fe 100644 --- a/utils/mail.go +++ b/utils/mail.go @@ -257,20 +257,18 @@ func SendMail(c *smtp.Client, mimeTo, smtpTo string, from mail.Address, subject, m.SetBody("text/plain", txtBody) m.AddAlternative("text/html", htmlMessage) - if attachments != nil { - for _, fileInfo := range attachments { - bytes, err := fileBackend.ReadFile(fileInfo.Path) - if err != nil { - return err - } - - m.Attach(fileInfo.Name, gomail.SetCopyFunc(func(writer io.Writer) error { - if _, err := writer.Write(bytes); err != nil { - return model.NewAppError("SendMail", "utils.mail.sendMail.attachments.write_error", nil, err.Error(), http.StatusInternalServerError) - } - return nil - })) + for _, fileInfo := range attachments { + bytes, err := fileBackend.ReadFile(fileInfo.Path) + if err != nil { + return err } + + m.Attach(fileInfo.Name, gomail.SetCopyFunc(func(writer io.Writer) error { + if _, err := writer.Write(bytes); err != nil { + return model.NewAppError("SendMail", "utils.mail.sendMail.attachments.write_error", nil, err.Error(), http.StatusInternalServerError) + } + return nil + })) } if err := c.Mail(from.Address); err != nil { |