github.com/mattermosttest/mattermost-server/v5@v5.0.0-20200917143240-9dfa12e121f9/app/post_test.go (about)

     1  // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
     2  // See LICENSE.txt for license information.
     3  
     4  package app
     5  
     6  import (
     7  	"fmt"
     8  	"net/http"
     9  	"sync"
    10  	"testing"
    11  	"time"
    12  
    13  	"github.com/stretchr/testify/assert"
    14  	"github.com/stretchr/testify/require"
    15  
    16  	"github.com/mattermost/mattermost-server/v5/mlog"
    17  	"github.com/mattermost/mattermost-server/v5/model"
    18  	"github.com/mattermost/mattermost-server/v5/plugin/plugintest/mock"
    19  	"github.com/mattermost/mattermost-server/v5/services/searchengine/mocks"
    20  	"github.com/mattermost/mattermost-server/v5/store/storetest"
    21  	storemocks "github.com/mattermost/mattermost-server/v5/store/storetest/mocks"
    22  	"github.com/mattermost/mattermost-server/v5/testlib"
    23  )
    24  
    25  func TestCreatePostDeduplicate(t *testing.T) {
    26  	th := Setup(t).InitBasic()
    27  	defer th.TearDown()
    28  
    29  	t.Run("duplicate create post is idempotent", func(t *testing.T) {
    30  		pendingPostId := model.NewId()
    31  		post, err := th.App.CreatePostAsUser(&model.Post{
    32  			UserId:        th.BasicUser.Id,
    33  			ChannelId:     th.BasicChannel.Id,
    34  			Message:       "message",
    35  			PendingPostId: pendingPostId,
    36  		}, "", true)
    37  		require.Nil(t, err)
    38  		require.Equal(t, "message", post.Message)
    39  
    40  		duplicatePost, err := th.App.CreatePostAsUser(&model.Post{
    41  			UserId:        th.BasicUser.Id,
    42  			ChannelId:     th.BasicChannel.Id,
    43  			Message:       "message",
    44  			PendingPostId: pendingPostId,
    45  		}, "", true)
    46  		require.Nil(t, err)
    47  		require.Equal(t, post.Id, duplicatePost.Id, "should have returned previously created post id")
    48  		require.Equal(t, "message", duplicatePost.Message)
    49  	})
    50  
    51  	t.Run("post rejected by plugin leaves cache ready for non-deduplicated try", func(t *testing.T) {
    52  		setupPluginApiTest(t, `
    53  			package main
    54  
    55  			import (
    56  				"github.com/mattermost/mattermost-server/v5/plugin"
    57  				"github.com/mattermost/mattermost-server/v5/model"
    58  			)
    59  
    60  			type MyPlugin struct {
    61  				plugin.MattermostPlugin
    62  				allow bool
    63  			}
    64  
    65  			func (p *MyPlugin) MessageWillBePosted(c *plugin.Context, post *model.Post) (*model.Post, string) {
    66  				if !p.allow {
    67  					p.allow = true
    68  					return nil, "rejected"
    69  				}
    70  
    71  				return nil, ""
    72  			}
    73  
    74  			func main() {
    75  				plugin.ClientMain(&MyPlugin{})
    76  			}
    77  		`, `{"id": "testrejectfirstpost", "backend": {"executable": "backend.exe"}}`, "testrejectfirstpost", th.App)
    78  
    79  		pendingPostId := model.NewId()
    80  		post, err := th.App.CreatePostAsUser(&model.Post{
    81  			UserId:        th.BasicUser.Id,
    82  			ChannelId:     th.BasicChannel.Id,
    83  			Message:       "message",
    84  			PendingPostId: pendingPostId,
    85  		}, "", true)
    86  		require.NotNil(t, err)
    87  		require.Equal(t, "Post rejected by plugin. rejected", err.Id)
    88  		require.Nil(t, post)
    89  
    90  		duplicatePost, err := th.App.CreatePostAsUser(&model.Post{
    91  			UserId:        th.BasicUser.Id,
    92  			ChannelId:     th.BasicChannel.Id,
    93  			Message:       "message",
    94  			PendingPostId: pendingPostId,
    95  		}, "", true)
    96  		require.Nil(t, err)
    97  		require.Equal(t, "message", duplicatePost.Message)
    98  	})
    99  
   100  	t.Run("slow posting after cache entry blocks duplicate request", func(t *testing.T) {
   101  		setupPluginApiTest(t, `
   102  			package main
   103  
   104  			import (
   105  				"github.com/mattermost/mattermost-server/v5/plugin"
   106  				"github.com/mattermost/mattermost-server/v5/model"
   107  				"time"
   108  			)
   109  
   110  			type MyPlugin struct {
   111  				plugin.MattermostPlugin
   112  				instant bool
   113  			}
   114  
   115  			func (p *MyPlugin) MessageWillBePosted(c *plugin.Context, post *model.Post) (*model.Post, string) {
   116  				if !p.instant {
   117  					p.instant = true
   118  					time.Sleep(3 * time.Second)
   119  				}
   120  
   121  				return nil, ""
   122  			}
   123  
   124  			func main() {
   125  				plugin.ClientMain(&MyPlugin{})
   126  			}
   127  		`, `{"id": "testdelayfirstpost", "backend": {"executable": "backend.exe"}}`, "testdelayfirstpost", th.App)
   128  
   129  		var post *model.Post
   130  		pendingPostId := model.NewId()
   131  
   132  		wg := sync.WaitGroup{}
   133  
   134  		// Launch a goroutine to make the first CreatePost call that will get delayed
   135  		// by the plugin above.
   136  		wg.Add(1)
   137  		go func() {
   138  			defer wg.Done()
   139  			var err error
   140  			post, err = th.App.CreatePostAsUser(&model.Post{
   141  				UserId:        th.BasicUser.Id,
   142  				ChannelId:     th.BasicChannel.Id,
   143  				Message:       "plugin delayed",
   144  				PendingPostId: pendingPostId,
   145  			}, "", true)
   146  			require.Nil(t, err)
   147  			require.Equal(t, post.Message, "plugin delayed")
   148  		}()
   149  
   150  		// Give the goroutine above a chance to start and get delayed by the plugin.
   151  		time.Sleep(2 * time.Second)
   152  
   153  		// Try creating a duplicate post
   154  		duplicatePost, err := th.App.CreatePostAsUser(&model.Post{
   155  			UserId:        th.BasicUser.Id,
   156  			ChannelId:     th.BasicChannel.Id,
   157  			Message:       "plugin delayed",
   158  			PendingPostId: pendingPostId,
   159  		}, "", true)
   160  		require.NotNil(t, err)
   161  		require.Equal(t, "api.post.deduplicate_create_post.pending", err.Id)
   162  		require.Nil(t, duplicatePost)
   163  
   164  		// Wait for the first CreatePost to finish to ensure assertions are made.
   165  		wg.Wait()
   166  	})
   167  
   168  	t.Run("duplicate create post after cache expires is not idempotent", func(t *testing.T) {
   169  		pendingPostId := model.NewId()
   170  		post, err := th.App.CreatePostAsUser(&model.Post{
   171  			UserId:        th.BasicUser.Id,
   172  			ChannelId:     th.BasicChannel.Id,
   173  			Message:       "message",
   174  			PendingPostId: pendingPostId,
   175  		}, "", true)
   176  		require.Nil(t, err)
   177  		require.Equal(t, "message", post.Message)
   178  
   179  		time.Sleep(PENDING_POST_IDS_CACHE_TTL)
   180  
   181  		duplicatePost, err := th.App.CreatePostAsUser(&model.Post{
   182  			UserId:        th.BasicUser.Id,
   183  			ChannelId:     th.BasicChannel.Id,
   184  			Message:       "message",
   185  			PendingPostId: pendingPostId,
   186  		}, "", true)
   187  		require.Nil(t, err)
   188  		require.NotEqual(t, post.Id, duplicatePost.Id, "should have created new post id")
   189  		require.Equal(t, "message", duplicatePost.Message)
   190  	})
   191  }
   192  
   193  func TestAttachFilesToPost(t *testing.T) {
   194  	t.Run("should attach files", func(t *testing.T) {
   195  		th := Setup(t).InitBasic()
   196  		defer th.TearDown()
   197  
   198  		info1, err := th.App.Srv().Store.FileInfo().Save(&model.FileInfo{
   199  			CreatorId: th.BasicUser.Id,
   200  			Path:      "path.txt",
   201  		})
   202  		require.Nil(t, err)
   203  
   204  		info2, err := th.App.Srv().Store.FileInfo().Save(&model.FileInfo{
   205  			CreatorId: th.BasicUser.Id,
   206  			Path:      "path.txt",
   207  		})
   208  		require.Nil(t, err)
   209  
   210  		post := th.BasicPost
   211  		post.FileIds = []string{info1.Id, info2.Id}
   212  
   213  		err = th.App.attachFilesToPost(post)
   214  		assert.Nil(t, err)
   215  
   216  		infos, err := th.App.GetFileInfosForPost(post.Id, false)
   217  		assert.Nil(t, err)
   218  		assert.Len(t, infos, 2)
   219  	})
   220  
   221  	t.Run("should update File.PostIds after failing to add files", func(t *testing.T) {
   222  		th := Setup(t).InitBasic()
   223  		defer th.TearDown()
   224  
   225  		info1, err := th.App.Srv().Store.FileInfo().Save(&model.FileInfo{
   226  			CreatorId: th.BasicUser.Id,
   227  			Path:      "path.txt",
   228  			PostId:    model.NewId(),
   229  		})
   230  		require.Nil(t, err)
   231  
   232  		info2, err := th.App.Srv().Store.FileInfo().Save(&model.FileInfo{
   233  			CreatorId: th.BasicUser.Id,
   234  			Path:      "path.txt",
   235  		})
   236  		require.Nil(t, err)
   237  
   238  		post := th.BasicPost
   239  		post.FileIds = []string{info1.Id, info2.Id}
   240  
   241  		err = th.App.attachFilesToPost(post)
   242  		assert.Nil(t, err)
   243  
   244  		infos, err := th.App.GetFileInfosForPost(post.Id, false)
   245  		assert.Nil(t, err)
   246  		assert.Len(t, infos, 1)
   247  		assert.Equal(t, info2.Id, infos[0].Id)
   248  
   249  		updated, err := th.App.GetSinglePost(post.Id)
   250  		require.Nil(t, err)
   251  		assert.Len(t, updated.FileIds, 1)
   252  		assert.Contains(t, updated.FileIds, info2.Id)
   253  	})
   254  }
   255  
   256  func TestUpdatePostEditAt(t *testing.T) {
   257  	th := Setup(t).InitBasic()
   258  	defer th.TearDown()
   259  
   260  	post := &model.Post{}
   261  	post = th.BasicPost.Clone()
   262  
   263  	post.IsPinned = true
   264  	saved, err := th.App.UpdatePost(post, true)
   265  	require.Nil(t, err)
   266  	assert.Equal(t, saved.EditAt, post.EditAt, "shouldn't have updated post.EditAt when pinning post")
   267  	post = saved.Clone()
   268  
   269  	time.Sleep(time.Millisecond * 100)
   270  
   271  	post.Message = model.NewId()
   272  	saved, err = th.App.UpdatePost(post, true)
   273  	require.Nil(t, err)
   274  	assert.NotEqual(t, saved.EditAt, post.EditAt, "should have updated post.EditAt when updating post message")
   275  
   276  	time.Sleep(time.Millisecond * 200)
   277  }
   278  
   279  func TestUpdatePostTimeLimit(t *testing.T) {
   280  	th := Setup(t).InitBasic()
   281  	defer th.TearDown()
   282  
   283  	post := &model.Post{}
   284  	post = th.BasicPost.Clone()
   285  
   286  	th.App.Srv().SetLicense(model.NewTestLicense())
   287  
   288  	th.App.UpdateConfig(func(cfg *model.Config) {
   289  		*cfg.ServiceSettings.PostEditTimeLimit = -1
   290  	})
   291  	_, err := th.App.UpdatePost(post, true)
   292  	require.Nil(t, err)
   293  
   294  	th.App.UpdateConfig(func(cfg *model.Config) {
   295  		*cfg.ServiceSettings.PostEditTimeLimit = 1000000000
   296  	})
   297  	post.Message = model.NewId()
   298  
   299  	_, err = th.App.UpdatePost(post, true)
   300  	require.Nil(t, err, "should allow you to edit the post")
   301  
   302  	th.App.UpdateConfig(func(cfg *model.Config) {
   303  		*cfg.ServiceSettings.PostEditTimeLimit = 1
   304  	})
   305  	post.Message = model.NewId()
   306  	_, err = th.App.UpdatePost(post, true)
   307  	require.NotNil(t, err, "should fail on update old post")
   308  
   309  	th.App.UpdateConfig(func(cfg *model.Config) {
   310  		*cfg.ServiceSettings.PostEditTimeLimit = -1
   311  	})
   312  }
   313  
   314  func TestUpdatePostInArchivedChannel(t *testing.T) {
   315  	th := Setup(t).InitBasic()
   316  	defer th.TearDown()
   317  
   318  	archivedChannel := th.CreateChannel(th.BasicTeam)
   319  	post := th.CreatePost(archivedChannel)
   320  	th.App.DeleteChannel(archivedChannel, "")
   321  
   322  	_, err := th.App.UpdatePost(post, true)
   323  	require.NotNil(t, err)
   324  	require.Equal(t, "api.post.update_post.can_not_update_post_in_deleted.error", err.Id)
   325  }
   326  
   327  func TestPostReplyToPostWhereRootPosterLeftChannel(t *testing.T) {
   328  	// This test ensures that when replying to a root post made by a user who has since left the channel, the reply
   329  	// post completes successfully. This is a regression test for PLT-6523.
   330  	th := Setup(t).InitBasic()
   331  	defer th.TearDown()
   332  
   333  	channel := th.BasicChannel
   334  	userInChannel := th.BasicUser2
   335  	userNotInChannel := th.BasicUser
   336  	rootPost := th.BasicPost
   337  
   338  	_, err := th.App.AddUserToChannel(userInChannel, channel)
   339  	require.Nil(t, err)
   340  
   341  	err = th.App.RemoveUserFromChannel(userNotInChannel.Id, "", channel)
   342  	require.Nil(t, err)
   343  	replyPost := model.Post{
   344  		Message:       "asd",
   345  		ChannelId:     channel.Id,
   346  		RootId:        rootPost.Id,
   347  		ParentId:      rootPost.Id,
   348  		PendingPostId: model.NewId() + ":" + fmt.Sprint(model.GetMillis()),
   349  		UserId:        userInChannel.Id,
   350  		CreateAt:      0,
   351  	}
   352  
   353  	_, err = th.App.CreatePostAsUser(&replyPost, "", true)
   354  	require.Nil(t, err)
   355  }
   356  
   357  func TestPostAttachPostToChildPost(t *testing.T) {
   358  	th := Setup(t).InitBasic()
   359  	defer th.TearDown()
   360  
   361  	channel := th.BasicChannel
   362  	user := th.BasicUser
   363  	rootPost := th.BasicPost
   364  
   365  	replyPost1 := model.Post{
   366  		Message:       "reply one",
   367  		ChannelId:     channel.Id,
   368  		RootId:        rootPost.Id,
   369  		ParentId:      rootPost.Id,
   370  		PendingPostId: model.NewId() + ":" + fmt.Sprint(model.GetMillis()),
   371  		UserId:        user.Id,
   372  		CreateAt:      0,
   373  	}
   374  
   375  	res1, err := th.App.CreatePostAsUser(&replyPost1, "", true)
   376  	require.Nil(t, err)
   377  
   378  	replyPost2 := model.Post{
   379  		Message:       "reply two",
   380  		ChannelId:     channel.Id,
   381  		RootId:        res1.Id,
   382  		ParentId:      res1.Id,
   383  		PendingPostId: model.NewId() + ":" + fmt.Sprint(model.GetMillis()),
   384  		UserId:        user.Id,
   385  		CreateAt:      0,
   386  	}
   387  
   388  	_, err = th.App.CreatePostAsUser(&replyPost2, "", true)
   389  	assert.Equalf(t, err.StatusCode, http.StatusBadRequest, "Expected BadRequest error, got %v", err)
   390  
   391  	replyPost3 := model.Post{
   392  		Message:       "reply three",
   393  		ChannelId:     channel.Id,
   394  		RootId:        rootPost.Id,
   395  		ParentId:      rootPost.Id,
   396  		PendingPostId: model.NewId() + ":" + fmt.Sprint(model.GetMillis()),
   397  		UserId:        user.Id,
   398  		CreateAt:      0,
   399  	}
   400  
   401  	_, err = th.App.CreatePostAsUser(&replyPost3, "", true)
   402  	assert.Nil(t, err)
   403  }
   404  
   405  func TestPostChannelMentions(t *testing.T) {
   406  	th := Setup(t).InitBasic()
   407  	defer th.TearDown()
   408  
   409  	channel := th.BasicChannel
   410  	user := th.BasicUser
   411  
   412  	channelToMention, err := th.App.CreateChannel(&model.Channel{
   413  		DisplayName: "Mention Test",
   414  		Name:        "mention-test",
   415  		Type:        model.CHANNEL_OPEN,
   416  		TeamId:      th.BasicTeam.Id,
   417  	}, false)
   418  	require.Nil(t, err)
   419  	defer th.App.PermanentDeleteChannel(channelToMention)
   420  
   421  	_, err = th.App.AddUserToChannel(user, channel)
   422  	require.Nil(t, err)
   423  
   424  	post := &model.Post{
   425  		Message:       fmt.Sprintf("hello, ~%v!", channelToMention.Name),
   426  		ChannelId:     channel.Id,
   427  		PendingPostId: model.NewId() + ":" + fmt.Sprint(model.GetMillis()),
   428  		UserId:        user.Id,
   429  		CreateAt:      0,
   430  	}
   431  
   432  	result, err := th.App.CreatePostAsUser(post, "", true)
   433  	require.Nil(t, err)
   434  	assert.Equal(t, map[string]interface{}{
   435  		"mention-test": map[string]interface{}{
   436  			"display_name": "Mention Test",
   437  			"team_name":    th.BasicTeam.Name,
   438  		},
   439  	}, result.GetProp("channel_mentions"))
   440  
   441  	post.Message = fmt.Sprintf("goodbye, ~%v!", channelToMention.Name)
   442  	result, err = th.App.UpdatePost(post, false)
   443  	require.Nil(t, err)
   444  	assert.Equal(t, map[string]interface{}{
   445  		"mention-test": map[string]interface{}{
   446  			"display_name": "Mention Test",
   447  			"team_name":    th.BasicTeam.Name,
   448  		},
   449  	}, result.GetProp("channel_mentions"))
   450  }
   451  
   452  func TestImageProxy(t *testing.T) {
   453  	th := SetupWithStoreMock(t)
   454  	defer th.TearDown()
   455  
   456  	mockStore := th.App.Srv().Store.(*storemocks.Store)
   457  	mockUserStore := storemocks.UserStore{}
   458  	mockUserStore.On("Count", mock.Anything).Return(int64(10), nil)
   459  	mockPostStore := storemocks.PostStore{}
   460  	mockPostStore.On("GetMaxPostSize").Return(65535, nil)
   461  	mockSystemStore := storemocks.SystemStore{}
   462  	mockSystemStore.On("GetByName", "InstallationDate").Return(&model.System{Name: "InstallationDate", Value: "10"}, nil)
   463  	mockSystemStore.On("GetByName", "FirstServerRunTimestamp").Return(&model.System{Name: "FirstServerRunTimestamp", Value: "10"}, nil)
   464  
   465  	mockStore.On("User").Return(&mockUserStore)
   466  	mockStore.On("Post").Return(&mockPostStore)
   467  	mockStore.On("System").Return(&mockSystemStore)
   468  
   469  	th.App.UpdateConfig(func(cfg *model.Config) {
   470  		*cfg.ServiceSettings.SiteURL = "http://mymattermost.com"
   471  	})
   472  
   473  	for name, tc := range map[string]struct {
   474  		ProxyType       string
   475  		ProxyURL        string
   476  		ProxyOptions    string
   477  		ImageURL        string
   478  		ProxiedImageURL string
   479  	}{
   480  		"atmos/camo": {
   481  			ProxyType:       model.IMAGE_PROXY_TYPE_ATMOS_CAMO,
   482  			ProxyURL:        "https://127.0.0.1",
   483  			ProxyOptions:    "foo",
   484  			ImageURL:        "http://mydomain.com/myimage",
   485  			ProxiedImageURL: "http://mymattermost.com/api/v4/image?url=http%3A%2F%2Fmydomain.com%2Fmyimage",
   486  		},
   487  		"atmos/camo_SameSite": {
   488  			ProxyType:       model.IMAGE_PROXY_TYPE_ATMOS_CAMO,
   489  			ProxyURL:        "https://127.0.0.1",
   490  			ProxyOptions:    "foo",
   491  			ImageURL:        "http://mymattermost.com/myimage",
   492  			ProxiedImageURL: "http://mymattermost.com/myimage",
   493  		},
   494  		"atmos/camo_PathOnly": {
   495  			ProxyType:       model.IMAGE_PROXY_TYPE_ATMOS_CAMO,
   496  			ProxyURL:        "https://127.0.0.1",
   497  			ProxyOptions:    "foo",
   498  			ImageURL:        "/myimage",
   499  			ProxiedImageURL: "/myimage",
   500  		},
   501  		"atmos/camo_EmptyImageURL": {
   502  			ProxyType:       model.IMAGE_PROXY_TYPE_ATMOS_CAMO,
   503  			ProxyURL:        "https://127.0.0.1",
   504  			ProxyOptions:    "foo",
   505  			ImageURL:        "",
   506  			ProxiedImageURL: "",
   507  		},
   508  		"local": {
   509  			ProxyType:       model.IMAGE_PROXY_TYPE_LOCAL,
   510  			ImageURL:        "http://mydomain.com/myimage",
   511  			ProxiedImageURL: "http://mymattermost.com/api/v4/image?url=http%3A%2F%2Fmydomain.com%2Fmyimage",
   512  		},
   513  		"local_SameSite": {
   514  			ProxyType:       model.IMAGE_PROXY_TYPE_LOCAL,
   515  			ImageURL:        "http://mymattermost.com/myimage",
   516  			ProxiedImageURL: "http://mymattermost.com/myimage",
   517  		},
   518  		"local_PathOnly": {
   519  			ProxyType:       model.IMAGE_PROXY_TYPE_LOCAL,
   520  			ImageURL:        "/myimage",
   521  			ProxiedImageURL: "/myimage",
   522  		},
   523  		"local_EmptyImageURL": {
   524  			ProxyType:       model.IMAGE_PROXY_TYPE_LOCAL,
   525  			ImageURL:        "",
   526  			ProxiedImageURL: "",
   527  		},
   528  	} {
   529  		t.Run(name, func(t *testing.T) {
   530  			th.App.UpdateConfig(func(cfg *model.Config) {
   531  				cfg.ImageProxySettings.Enable = model.NewBool(true)
   532  				cfg.ImageProxySettings.ImageProxyType = model.NewString(tc.ProxyType)
   533  				cfg.ImageProxySettings.RemoteImageProxyOptions = model.NewString(tc.ProxyOptions)
   534  				cfg.ImageProxySettings.RemoteImageProxyURL = model.NewString(tc.ProxyURL)
   535  			})
   536  
   537  			post := &model.Post{
   538  				Id:      model.NewId(),
   539  				Message: "![foo](" + tc.ImageURL + ")",
   540  			}
   541  
   542  			list := model.NewPostList()
   543  			list.Posts[post.Id] = post
   544  
   545  			assert.Equal(t, "![foo]("+tc.ProxiedImageURL+")", th.App.PostWithProxyAddedToImageURLs(post).Message)
   546  
   547  			assert.Equal(t, "![foo]("+tc.ImageURL+")", th.App.PostWithProxyRemovedFromImageURLs(post).Message)
   548  			post.Message = "![foo](" + tc.ProxiedImageURL + ")"
   549  			assert.Equal(t, "![foo]("+tc.ImageURL+")", th.App.PostWithProxyRemovedFromImageURLs(post).Message)
   550  
   551  			if tc.ImageURL != "" {
   552  				post.Message = "![foo](" + tc.ImageURL + " =500x200)"
   553  				assert.Equal(t, "![foo]("+tc.ProxiedImageURL+" =500x200)", th.App.PostWithProxyAddedToImageURLs(post).Message)
   554  				assert.Equal(t, "![foo]("+tc.ImageURL+" =500x200)", th.App.PostWithProxyRemovedFromImageURLs(post).Message)
   555  				post.Message = "![foo](" + tc.ProxiedImageURL + " =500x200)"
   556  				assert.Equal(t, "![foo]("+tc.ImageURL+" =500x200)", th.App.PostWithProxyRemovedFromImageURLs(post).Message)
   557  			}
   558  		})
   559  	}
   560  }
   561  
   562  func TestMaxPostSize(t *testing.T) {
   563  	t.Skip("TODO: fix flaky test")
   564  	t.Parallel()
   565  
   566  	testCases := []struct {
   567  		Description         string
   568  		StoreMaxPostSize    int
   569  		ExpectedMaxPostSize int
   570  	}{
   571  		{
   572  			"Max post size less than model.model.POST_MESSAGE_MAX_RUNES_V1 ",
   573  			0,
   574  			model.POST_MESSAGE_MAX_RUNES_V1,
   575  		},
   576  		{
   577  			"4000 rune limit",
   578  			4000,
   579  			4000,
   580  		},
   581  		{
   582  			"16383 rune limit",
   583  			16383,
   584  			16383,
   585  		},
   586  	}
   587  
   588  	for _, testCase := range testCases {
   589  		testCase := testCase
   590  		t.Run(testCase.Description, func(t *testing.T) {
   591  			t.Parallel()
   592  
   593  			mockStore := &storetest.Store{}
   594  			defer mockStore.AssertExpectations(t)
   595  
   596  			mockStore.PostStore.On("GetMaxPostSize").Return(testCase.StoreMaxPostSize)
   597  
   598  			app := App{
   599  				srv: &Server{
   600  					Store: mockStore,
   601  				},
   602  			}
   603  
   604  			assert.Equal(t, testCase.ExpectedMaxPostSize, app.MaxPostSize())
   605  		})
   606  	}
   607  }
   608  
   609  func TestDeletePostWithFileAttachments(t *testing.T) {
   610  	th := Setup(t).InitBasic()
   611  	defer th.TearDown()
   612  
   613  	// Create a post with a file attachment.
   614  	teamId := th.BasicTeam.Id
   615  	channelId := th.BasicChannel.Id
   616  	userId := th.BasicUser.Id
   617  	filename := "test"
   618  	data := []byte("abcd")
   619  
   620  	info1, err := th.App.DoUploadFile(time.Date(2007, 2, 4, 1, 2, 3, 4, time.Local), teamId, channelId, userId, filename, data)
   621  	require.Nil(t, err)
   622  	defer func() {
   623  		th.App.Srv().Store.FileInfo().PermanentDelete(info1.Id)
   624  		th.App.RemoveFile(info1.Path)
   625  	}()
   626  
   627  	post := &model.Post{
   628  		Message:       "asd",
   629  		ChannelId:     channelId,
   630  		PendingPostId: model.NewId() + ":" + fmt.Sprint(model.GetMillis()),
   631  		UserId:        userId,
   632  		CreateAt:      0,
   633  		FileIds:       []string{info1.Id},
   634  	}
   635  
   636  	post, err = th.App.CreatePost(post, th.BasicChannel, false, true)
   637  	assert.Nil(t, err)
   638  
   639  	// Delete the post.
   640  	post, err = th.App.DeletePost(post.Id, userId)
   641  	assert.Nil(t, err)
   642  
   643  	// Wait for the cleanup routine to finish.
   644  	time.Sleep(time.Millisecond * 100)
   645  
   646  	// Check that the file can no longer be reached.
   647  	_, err = th.App.GetFileInfo(info1.Id)
   648  	assert.NotNil(t, err)
   649  }
   650  
   651  func TestDeletePostInArchivedChannel(t *testing.T) {
   652  	th := Setup(t).InitBasic()
   653  	defer th.TearDown()
   654  
   655  	archivedChannel := th.CreateChannel(th.BasicTeam)
   656  	post := th.CreatePost(archivedChannel)
   657  	th.App.DeleteChannel(archivedChannel, "")
   658  
   659  	_, err := th.App.DeletePost(post.Id, "")
   660  	require.NotNil(t, err)
   661  	require.Equal(t, "api.post.delete_post.can_not_delete_post_in_deleted.error", err.Id)
   662  }
   663  
   664  func TestCreatePost(t *testing.T) {
   665  	t.Run("call PreparePostForClient before returning", func(t *testing.T) {
   666  		th := Setup(t).InitBasic()
   667  		defer th.TearDown()
   668  
   669  		th.App.UpdateConfig(func(cfg *model.Config) {
   670  			*cfg.ServiceSettings.SiteURL = "http://mymattermost.com"
   671  			*cfg.ImageProxySettings.Enable = true
   672  			*cfg.ImageProxySettings.ImageProxyType = "atmos/camo"
   673  			*cfg.ImageProxySettings.RemoteImageProxyURL = "https://127.0.0.1"
   674  			*cfg.ImageProxySettings.RemoteImageProxyOptions = "foo"
   675  		})
   676  
   677  		imageURL := "http://mydomain.com/myimage"
   678  		proxiedImageURL := "http://mymattermost.com/api/v4/image?url=http%3A%2F%2Fmydomain.com%2Fmyimage"
   679  
   680  		post := &model.Post{
   681  			ChannelId: th.BasicChannel.Id,
   682  			Message:   "![image](" + imageURL + ")",
   683  			UserId:    th.BasicUser.Id,
   684  		}
   685  
   686  		rpost, err := th.App.CreatePost(post, th.BasicChannel, false, true)
   687  		require.Nil(t, err)
   688  		assert.Equal(t, "![image]("+proxiedImageURL+")", rpost.Message)
   689  	})
   690  
   691  	t.Run("Sets prop MENTION_HIGHLIGHT_DISABLED when it should", func(t *testing.T) {
   692  		th := Setup(t).InitBasic()
   693  		defer th.TearDown()
   694  		th.AddUserToChannel(th.BasicUser, th.BasicChannel)
   695  
   696  		t.Run("Does not set prop when user has USE_CHANNEL_MENTIONS", func(t *testing.T) {
   697  			postWithNoMention := &model.Post{
   698  				ChannelId: th.BasicChannel.Id,
   699  				Message:   "This post does not have mentions",
   700  				UserId:    th.BasicUser.Id,
   701  			}
   702  			rpost, err := th.App.CreatePost(postWithNoMention, th.BasicChannel, false, true)
   703  			require.Nil(t, err)
   704  			assert.Equal(t, rpost.GetProps(), model.StringInterface{})
   705  
   706  			postWithMention := &model.Post{
   707  				ChannelId: th.BasicChannel.Id,
   708  				Message:   "This post has @here mention @all",
   709  				UserId:    th.BasicUser.Id,
   710  			}
   711  			rpost, err = th.App.CreatePost(postWithMention, th.BasicChannel, false, true)
   712  			require.Nil(t, err)
   713  			assert.Equal(t, rpost.GetProps(), model.StringInterface{})
   714  		})
   715  
   716  		t.Run("Sets prop when post has mentions and user does not have USE_CHANNEL_MENTIONS", func(t *testing.T) {
   717  			th.RemovePermissionFromRole(model.PERMISSION_USE_CHANNEL_MENTIONS.Id, model.CHANNEL_USER_ROLE_ID)
   718  			th.RemovePermissionFromRole(model.PERMISSION_USE_CHANNEL_MENTIONS.Id, model.CHANNEL_ADMIN_ROLE_ID)
   719  
   720  			postWithNoMention := &model.Post{
   721  				ChannelId: th.BasicChannel.Id,
   722  				Message:   "This post does not have mentions",
   723  				UserId:    th.BasicUser.Id,
   724  			}
   725  			rpost, err := th.App.CreatePost(postWithNoMention, th.BasicChannel, false, true)
   726  			require.Nil(t, err)
   727  			assert.Equal(t, rpost.GetProps(), model.StringInterface{})
   728  
   729  			postWithMention := &model.Post{
   730  				ChannelId: th.BasicChannel.Id,
   731  				Message:   "This post has @here mention @all",
   732  				UserId:    th.BasicUser.Id,
   733  			}
   734  			rpost, err = th.App.CreatePost(postWithMention, th.BasicChannel, false, true)
   735  			require.Nil(t, err)
   736  			assert.Equal(t, rpost.GetProp(model.POST_PROPS_MENTION_HIGHLIGHT_DISABLED), true)
   737  
   738  			th.AddPermissionToRole(model.PERMISSION_USE_CHANNEL_MENTIONS.Id, model.CHANNEL_USER_ROLE_ID)
   739  			th.AddPermissionToRole(model.PERMISSION_USE_CHANNEL_MENTIONS.Id, model.CHANNEL_ADMIN_ROLE_ID)
   740  		})
   741  	})
   742  }
   743  
   744  func TestPatchPost(t *testing.T) {
   745  	t.Run("call PreparePostForClient before returning", func(t *testing.T) {
   746  		th := Setup(t).InitBasic()
   747  		defer th.TearDown()
   748  
   749  		th.App.UpdateConfig(func(cfg *model.Config) {
   750  			*cfg.ServiceSettings.SiteURL = "http://mymattermost.com"
   751  			*cfg.ImageProxySettings.Enable = true
   752  			*cfg.ImageProxySettings.ImageProxyType = "atmos/camo"
   753  			*cfg.ImageProxySettings.RemoteImageProxyURL = "https://127.0.0.1"
   754  			*cfg.ImageProxySettings.RemoteImageProxyOptions = "foo"
   755  		})
   756  
   757  		imageURL := "http://mydomain.com/myimage"
   758  		proxiedImageURL := "http://mymattermost.com/api/v4/image?url=http%3A%2F%2Fmydomain.com%2Fmyimage"
   759  
   760  		post := &model.Post{
   761  			ChannelId: th.BasicChannel.Id,
   762  			Message:   "![image](http://mydomain/anotherimage)",
   763  			UserId:    th.BasicUser.Id,
   764  		}
   765  
   766  		rpost, err := th.App.CreatePost(post, th.BasicChannel, false, true)
   767  		require.Nil(t, err)
   768  		assert.NotEqual(t, "![image]("+proxiedImageURL+")", rpost.Message)
   769  
   770  		patch := &model.PostPatch{
   771  			Message: model.NewString("![image](" + imageURL + ")"),
   772  		}
   773  
   774  		rpost, err = th.App.PatchPost(rpost.Id, patch)
   775  		require.Nil(t, err)
   776  		assert.Equal(t, "![image]("+proxiedImageURL+")", rpost.Message)
   777  	})
   778  
   779  	t.Run("Sets Prop MENTION_HIGHLIGHT_DISABLED when it should", func(t *testing.T) {
   780  		th := Setup(t).InitBasic()
   781  		defer th.TearDown()
   782  
   783  		th.AddUserToChannel(th.BasicUser, th.BasicChannel)
   784  
   785  		post := &model.Post{
   786  			ChannelId: th.BasicChannel.Id,
   787  			Message:   "This post does not have mentions",
   788  			UserId:    th.BasicUser.Id,
   789  		}
   790  
   791  		rpost, err := th.App.CreatePost(post, th.BasicChannel, false, true)
   792  		require.Nil(t, err)
   793  
   794  		t.Run("Does not set prop when user has USE_CHANNEL_MENTIONS", func(t *testing.T) {
   795  			patchWithNoMention := &model.PostPatch{Message: model.NewString("This patch has no channel mention")}
   796  
   797  			rpost, err = th.App.PatchPost(rpost.Id, patchWithNoMention)
   798  			require.Nil(t, err)
   799  			assert.Equal(t, rpost.GetProps(), model.StringInterface{})
   800  
   801  			patchWithMention := &model.PostPatch{Message: model.NewString("This patch has a mention now @here")}
   802  
   803  			rpost, err = th.App.PatchPost(rpost.Id, patchWithMention)
   804  			require.Nil(t, err)
   805  			assert.Equal(t, rpost.GetProps(), model.StringInterface{})
   806  		})
   807  
   808  		t.Run("Sets prop when user does not have USE_CHANNEL_MENTIONS", func(t *testing.T) {
   809  			th.RemovePermissionFromRole(model.PERMISSION_USE_CHANNEL_MENTIONS.Id, model.CHANNEL_USER_ROLE_ID)
   810  			th.RemovePermissionFromRole(model.PERMISSION_USE_CHANNEL_MENTIONS.Id, model.CHANNEL_ADMIN_ROLE_ID)
   811  
   812  			patchWithNoMention := &model.PostPatch{Message: model.NewString("This patch still does not have a mention")}
   813  			rpost, err = th.App.PatchPost(rpost.Id, patchWithNoMention)
   814  			require.Nil(t, err)
   815  			assert.Equal(t, rpost.GetProps(), model.StringInterface{})
   816  
   817  			patchWithMention := &model.PostPatch{Message: model.NewString("This patch has a mention now @here")}
   818  
   819  			rpost, err = th.App.PatchPost(rpost.Id, patchWithMention)
   820  			require.Nil(t, err)
   821  			assert.Equal(t, rpost.GetProp(model.POST_PROPS_MENTION_HIGHLIGHT_DISABLED), true)
   822  
   823  			th.AddPermissionToRole(model.PERMISSION_USE_CHANNEL_MENTIONS.Id, model.CHANNEL_USER_ROLE_ID)
   824  			th.AddPermissionToRole(model.PERMISSION_USE_CHANNEL_MENTIONS.Id, model.CHANNEL_ADMIN_ROLE_ID)
   825  		})
   826  	})
   827  }
   828  
   829  func TestCreatePostAsUser(t *testing.T) {
   830  	t.Run("marks channel as viewed for regular user", func(t *testing.T) {
   831  		th := Setup(t).InitBasic()
   832  		defer th.TearDown()
   833  
   834  		post := &model.Post{
   835  			ChannelId: th.BasicChannel.Id,
   836  			Message:   "test",
   837  			UserId:    th.BasicUser.Id,
   838  		}
   839  
   840  		channelMemberBefore, appErr := th.App.Srv().Store.Channel().GetMember(th.BasicChannel.Id, th.BasicUser.Id)
   841  		require.Nil(t, appErr)
   842  
   843  		time.Sleep(1 * time.Millisecond)
   844  		_, appErr = th.App.CreatePostAsUser(post, "", true)
   845  		require.Nil(t, appErr)
   846  
   847  		channelMemberAfter, appErr := th.App.Srv().Store.Channel().GetMember(th.BasicChannel.Id, th.BasicUser.Id)
   848  		require.Nil(t, appErr)
   849  
   850  		require.Greater(t, channelMemberAfter.LastViewedAt, channelMemberBefore.LastViewedAt)
   851  	})
   852  
   853  	t.Run("does not mark channel as viewed for webhook from user", func(t *testing.T) {
   854  		th := Setup(t).InitBasic()
   855  		defer th.TearDown()
   856  
   857  		post := &model.Post{
   858  			ChannelId: th.BasicChannel.Id,
   859  			Message:   "test",
   860  			UserId:    th.BasicUser.Id,
   861  		}
   862  		post.AddProp("from_webhook", "true")
   863  
   864  		channelMemberBefore, appErr := th.App.Srv().Store.Channel().GetMember(th.BasicChannel.Id, th.BasicUser.Id)
   865  		require.Nil(t, appErr)
   866  
   867  		time.Sleep(1 * time.Millisecond)
   868  		_, appErr = th.App.CreatePostAsUser(post, "", true)
   869  		require.Nil(t, appErr)
   870  
   871  		channelMemberAfter, appErr := th.App.Srv().Store.Channel().GetMember(th.BasicChannel.Id, th.BasicUser.Id)
   872  		require.Nil(t, appErr)
   873  
   874  		require.Equal(t, channelMemberAfter.LastViewedAt, channelMemberBefore.LastViewedAt)
   875  	})
   876  
   877  	t.Run("does not mark channel as viewed for bot user in channel", func(t *testing.T) {
   878  		th := Setup(t).InitBasic()
   879  		defer th.TearDown()
   880  
   881  		bot := th.CreateBot()
   882  
   883  		botUser, appErr := th.App.GetUser(bot.UserId)
   884  		require.Nil(t, appErr)
   885  
   886  		th.LinkUserToTeam(botUser, th.BasicTeam)
   887  		th.AddUserToChannel(botUser, th.BasicChannel)
   888  
   889  		post := &model.Post{
   890  			ChannelId: th.BasicChannel.Id,
   891  			Message:   "test",
   892  			UserId:    bot.UserId,
   893  		}
   894  
   895  		channelMemberBefore, appErr := th.App.Srv().Store.Channel().GetMember(th.BasicChannel.Id, th.BasicUser.Id)
   896  		require.Nil(t, appErr)
   897  
   898  		time.Sleep(1 * time.Millisecond)
   899  		_, appErr = th.App.CreatePostAsUser(post, "", true)
   900  		require.Nil(t, appErr)
   901  
   902  		channelMemberAfter, appErr := th.App.Srv().Store.Channel().GetMember(th.BasicChannel.Id, th.BasicUser.Id)
   903  		require.Nil(t, appErr)
   904  
   905  		require.Equal(t, channelMemberAfter.LastViewedAt, channelMemberBefore.LastViewedAt)
   906  	})
   907  
   908  	t.Run("logs warning for user not in channel", func(t *testing.T) {
   909  		th := Setup(t).InitBasic()
   910  		defer th.TearDown()
   911  
   912  		user := th.CreateUser()
   913  		th.LinkUserToTeam(user, th.BasicTeam)
   914  
   915  		post := &model.Post{
   916  			ChannelId: th.BasicChannel.Id,
   917  			Message:   "test",
   918  			UserId:    user.Id,
   919  		}
   920  
   921  		_, appErr := th.App.CreatePostAsUser(post, "", true)
   922  		require.Nil(t, appErr)
   923  
   924  		testlib.AssertLog(t, th.LogBuffer, mlog.LevelWarn, "Failed to get membership")
   925  	})
   926  
   927  	t.Run("does not log warning for bot user not in channel", func(t *testing.T) {
   928  		th := Setup(t).InitBasic()
   929  		defer th.TearDown()
   930  
   931  		bot := th.CreateBot()
   932  
   933  		botUser, appErr := th.App.GetUser(bot.UserId)
   934  		require.Nil(t, appErr)
   935  
   936  		th.LinkUserToTeam(botUser, th.BasicTeam)
   937  
   938  		post := &model.Post{
   939  			ChannelId: th.BasicChannel.Id,
   940  			Message:   "test",
   941  			UserId:    bot.UserId,
   942  		}
   943  
   944  		_, appErr = th.App.CreatePostAsUser(post, "", true)
   945  		require.Nil(t, appErr)
   946  
   947  		testlib.AssertNoLog(t, th.LogBuffer, mlog.LevelWarn, "Failed to get membership")
   948  	})
   949  }
   950  
   951  func TestPatchPostInArchivedChannel(t *testing.T) {
   952  	th := Setup(t).InitBasic()
   953  	defer th.TearDown()
   954  
   955  	archivedChannel := th.CreateChannel(th.BasicTeam)
   956  	post := th.CreatePost(archivedChannel)
   957  	th.App.DeleteChannel(archivedChannel, "")
   958  
   959  	_, err := th.App.PatchPost(post.Id, &model.PostPatch{IsPinned: model.NewBool(true)})
   960  	require.NotNil(t, err)
   961  	require.Equal(t, "api.post.patch_post.can_not_update_post_in_deleted.error", err.Id)
   962  }
   963  
   964  func TestUpdatePost(t *testing.T) {
   965  	t.Run("call PreparePostForClient before returning", func(t *testing.T) {
   966  		th := Setup(t).InitBasic()
   967  		defer th.TearDown()
   968  
   969  		th.App.UpdateConfig(func(cfg *model.Config) {
   970  			*cfg.ServiceSettings.SiteURL = "http://mymattermost.com"
   971  			*cfg.ImageProxySettings.Enable = true
   972  			*cfg.ImageProxySettings.ImageProxyType = "atmos/camo"
   973  			*cfg.ImageProxySettings.RemoteImageProxyURL = "https://127.0.0.1"
   974  			*cfg.ImageProxySettings.RemoteImageProxyOptions = "foo"
   975  		})
   976  
   977  		imageURL := "http://mydomain.com/myimage"
   978  		proxiedImageURL := "http://mymattermost.com/api/v4/image?url=http%3A%2F%2Fmydomain.com%2Fmyimage"
   979  
   980  		post := &model.Post{
   981  			ChannelId: th.BasicChannel.Id,
   982  			Message:   "![image](http://mydomain/anotherimage)",
   983  			UserId:    th.BasicUser.Id,
   984  		}
   985  
   986  		rpost, err := th.App.CreatePost(post, th.BasicChannel, false, true)
   987  		require.Nil(t, err)
   988  		assert.NotEqual(t, "![image]("+proxiedImageURL+")", rpost.Message)
   989  
   990  		post.Id = rpost.Id
   991  		post.Message = "![image](" + imageURL + ")"
   992  
   993  		rpost, err = th.App.UpdatePost(post, false)
   994  		require.Nil(t, err)
   995  		assert.Equal(t, "![image]("+proxiedImageURL+")", rpost.Message)
   996  	})
   997  }
   998  
   999  func TestSearchPostsInTeamForUser(t *testing.T) {
  1000  	perPage := 5
  1001  	searchTerm := "searchTerm"
  1002  
  1003  	setup := func(t *testing.T, enableElasticsearch bool) (*TestHelper, []*model.Post) {
  1004  		th := Setup(t).InitBasic()
  1005  
  1006  		posts := make([]*model.Post, 7)
  1007  		for i := 0; i < cap(posts); i++ {
  1008  			post, err := th.App.CreatePost(&model.Post{
  1009  				UserId:    th.BasicUser.Id,
  1010  				ChannelId: th.BasicChannel.Id,
  1011  				Message:   searchTerm,
  1012  			}, th.BasicChannel, false, true)
  1013  
  1014  			require.Nil(t, err)
  1015  
  1016  			posts[i] = post
  1017  		}
  1018  
  1019  		if enableElasticsearch {
  1020  			th.App.Srv().SetLicense(model.NewTestLicense("elastic_search"))
  1021  
  1022  			th.App.UpdateConfig(func(cfg *model.Config) {
  1023  				*cfg.ElasticsearchSettings.EnableIndexing = true
  1024  				*cfg.ElasticsearchSettings.EnableSearching = true
  1025  			})
  1026  		} else {
  1027  			th.App.UpdateConfig(func(cfg *model.Config) {
  1028  				*cfg.ElasticsearchSettings.EnableSearching = false
  1029  			})
  1030  		}
  1031  
  1032  		return th, posts
  1033  	}
  1034  
  1035  	t.Run("should return everything as first page of posts from database", func(t *testing.T) {
  1036  		th, posts := setup(t, false)
  1037  		defer th.TearDown()
  1038  
  1039  		page := 0
  1040  
  1041  		results, err := th.App.SearchPostsInTeamForUser(searchTerm, th.BasicUser.Id, th.BasicTeam.Id, false, false, 0, page, perPage)
  1042  
  1043  		assert.Nil(t, err)
  1044  		assert.Equal(t, []string{
  1045  			posts[6].Id,
  1046  			posts[5].Id,
  1047  			posts[4].Id,
  1048  			posts[3].Id,
  1049  			posts[2].Id,
  1050  			posts[1].Id,
  1051  			posts[0].Id,
  1052  		}, results.Order)
  1053  	})
  1054  
  1055  	t.Run("should not return later pages of posts from database", func(t *testing.T) {
  1056  		th, _ := setup(t, false)
  1057  		defer th.TearDown()
  1058  
  1059  		page := 1
  1060  
  1061  		results, err := th.App.SearchPostsInTeamForUser(searchTerm, th.BasicUser.Id, th.BasicTeam.Id, false, false, 0, page, perPage)
  1062  
  1063  		assert.Nil(t, err)
  1064  		assert.Equal(t, []string{}, results.Order)
  1065  	})
  1066  
  1067  	t.Run("should return first page of posts from ElasticSearch", func(t *testing.T) {
  1068  		th, posts := setup(t, true)
  1069  		defer th.TearDown()
  1070  
  1071  		page := 0
  1072  		resultsPage := []string{
  1073  			posts[6].Id,
  1074  			posts[5].Id,
  1075  			posts[4].Id,
  1076  			posts[3].Id,
  1077  			posts[2].Id,
  1078  		}
  1079  
  1080  		es := &mocks.SearchEngineInterface{}
  1081  		es.On("SearchPosts", mock.Anything, mock.Anything, page, perPage).Return(resultsPage, nil, nil)
  1082  		es.On("GetName").Return("mock")
  1083  		es.On("Start").Return(nil).Maybe()
  1084  		es.On("IsActive").Return(true)
  1085  		es.On("IsSearchEnabled").Return(true)
  1086  		th.App.Srv().SearchEngine.ElasticsearchEngine = es
  1087  		defer func() {
  1088  			th.App.Srv().SearchEngine.ElasticsearchEngine = nil
  1089  		}()
  1090  
  1091  		results, err := th.App.SearchPostsInTeamForUser(searchTerm, th.BasicUser.Id, th.BasicTeam.Id, false, false, 0, page, perPage)
  1092  
  1093  		assert.Nil(t, err)
  1094  		assert.Equal(t, resultsPage, results.Order)
  1095  		es.AssertExpectations(t)
  1096  	})
  1097  
  1098  	t.Run("should return later pages of posts from ElasticSearch", func(t *testing.T) {
  1099  		th, posts := setup(t, true)
  1100  		defer th.TearDown()
  1101  
  1102  		page := 1
  1103  		resultsPage := []string{
  1104  			posts[1].Id,
  1105  			posts[0].Id,
  1106  		}
  1107  
  1108  		es := &mocks.SearchEngineInterface{}
  1109  		es.On("SearchPosts", mock.Anything, mock.Anything, page, perPage).Return(resultsPage, nil, nil)
  1110  		es.On("GetName").Return("mock")
  1111  		es.On("Start").Return(nil).Maybe()
  1112  		es.On("IsActive").Return(true)
  1113  		es.On("IsSearchEnabled").Return(true)
  1114  		th.App.Srv().SearchEngine.ElasticsearchEngine = es
  1115  		defer func() {
  1116  			th.App.Srv().SearchEngine.ElasticsearchEngine = nil
  1117  		}()
  1118  
  1119  		results, err := th.App.SearchPostsInTeamForUser(searchTerm, th.BasicUser.Id, th.BasicTeam.Id, false, false, 0, page, perPage)
  1120  
  1121  		assert.Nil(t, err)
  1122  		assert.Equal(t, resultsPage, results.Order)
  1123  		es.AssertExpectations(t)
  1124  	})
  1125  
  1126  	t.Run("should fall back to database if ElasticSearch fails on first page", func(t *testing.T) {
  1127  		th, posts := setup(t, true)
  1128  		defer th.TearDown()
  1129  
  1130  		page := 0
  1131  
  1132  		es := &mocks.SearchEngineInterface{}
  1133  		es.On("SearchPosts", mock.Anything, mock.Anything, page, perPage).Return(nil, nil, &model.AppError{})
  1134  		es.On("GetName").Return("mock")
  1135  		es.On("Start").Return(nil).Maybe()
  1136  		es.On("IsActive").Return(true)
  1137  		es.On("IsSearchEnabled").Return(true)
  1138  		th.App.Srv().SearchEngine.ElasticsearchEngine = es
  1139  		defer func() {
  1140  			th.App.Srv().SearchEngine.ElasticsearchEngine = nil
  1141  		}()
  1142  
  1143  		results, err := th.App.SearchPostsInTeamForUser(searchTerm, th.BasicUser.Id, th.BasicTeam.Id, false, false, 0, page, perPage)
  1144  
  1145  		assert.Nil(t, err)
  1146  		assert.Equal(t, []string{
  1147  			posts[6].Id,
  1148  			posts[5].Id,
  1149  			posts[4].Id,
  1150  			posts[3].Id,
  1151  			posts[2].Id,
  1152  			posts[1].Id,
  1153  			posts[0].Id,
  1154  		}, results.Order)
  1155  		es.AssertExpectations(t)
  1156  	})
  1157  
  1158  	t.Run("should return nothing if ElasticSearch fails on later pages", func(t *testing.T) {
  1159  		th, _ := setup(t, true)
  1160  		defer th.TearDown()
  1161  
  1162  		page := 1
  1163  
  1164  		es := &mocks.SearchEngineInterface{}
  1165  		es.On("SearchPosts", mock.Anything, mock.Anything, page, perPage).Return(nil, nil, &model.AppError{})
  1166  		es.On("GetName").Return("mock")
  1167  		es.On("Start").Return(nil).Maybe()
  1168  		es.On("IsActive").Return(true)
  1169  		es.On("IsSearchEnabled").Return(true)
  1170  		th.App.Srv().SearchEngine.ElasticsearchEngine = es
  1171  		defer func() {
  1172  			th.App.Srv().SearchEngine.ElasticsearchEngine = nil
  1173  		}()
  1174  
  1175  		results, err := th.App.SearchPostsInTeamForUser(searchTerm, th.BasicUser.Id, th.BasicTeam.Id, false, false, 0, page, perPage)
  1176  
  1177  		assert.Nil(t, err)
  1178  		assert.Equal(t, []string{}, results.Order)
  1179  		es.AssertExpectations(t)
  1180  	})
  1181  }
  1182  
  1183  func TestCountMentionsFromPost(t *testing.T) {
  1184  	t.Run("should not count posts without mentions", func(t *testing.T) {
  1185  		th := Setup(t).InitBasic()
  1186  		defer th.TearDown()
  1187  
  1188  		user1 := th.BasicUser
  1189  		user2 := th.BasicUser2
  1190  
  1191  		channel := th.CreateChannel(th.BasicTeam)
  1192  		th.AddUserToChannel(user2, channel)
  1193  
  1194  		post1, err := th.App.CreatePost(&model.Post{
  1195  			UserId:    user1.Id,
  1196  			ChannelId: channel.Id,
  1197  			Message:   "test",
  1198  		}, channel, false, true)
  1199  		require.Nil(t, err)
  1200  		_, err = th.App.CreatePost(&model.Post{
  1201  			UserId:    user1.Id,
  1202  			ChannelId: channel.Id,
  1203  			Message:   "test2",
  1204  		}, channel, false, true)
  1205  		require.Nil(t, err)
  1206  		_, err = th.App.CreatePost(&model.Post{
  1207  			UserId:    user1.Id,
  1208  			ChannelId: channel.Id,
  1209  			Message:   "test3",
  1210  		}, channel, false, true)
  1211  		require.Nil(t, err)
  1212  
  1213  		count, err := th.App.countMentionsFromPost(user2, post1)
  1214  
  1215  		assert.Nil(t, err)
  1216  		assert.Equal(t, 0, count)
  1217  	})
  1218  
  1219  	t.Run("should count keyword mentions", func(t *testing.T) {
  1220  		th := Setup(t).InitBasic()
  1221  		defer th.TearDown()
  1222  
  1223  		user1 := th.BasicUser
  1224  		user2 := th.BasicUser2
  1225  
  1226  		channel := th.CreateChannel(th.BasicTeam)
  1227  		th.AddUserToChannel(user2, channel)
  1228  
  1229  		user2.NotifyProps[model.MENTION_KEYS_NOTIFY_PROP] = "apple"
  1230  
  1231  		post1, err := th.App.CreatePost(&model.Post{
  1232  			UserId:    user1.Id,
  1233  			ChannelId: channel.Id,
  1234  			Message:   fmt.Sprintf("@%s", user2.Username),
  1235  		}, channel, false, true)
  1236  		require.Nil(t, err)
  1237  		_, err = th.App.CreatePost(&model.Post{
  1238  			UserId:    user1.Id,
  1239  			ChannelId: channel.Id,
  1240  			Message:   "test2",
  1241  		}, channel, false, true)
  1242  		require.Nil(t, err)
  1243  		_, err = th.App.CreatePost(&model.Post{
  1244  			UserId:    user1.Id,
  1245  			ChannelId: channel.Id,
  1246  			Message:   "apple",
  1247  		}, channel, false, true)
  1248  		require.Nil(t, err)
  1249  
  1250  		// post1 and post3 should mention the user
  1251  
  1252  		count, err := th.App.countMentionsFromPost(user2, post1)
  1253  
  1254  		assert.Nil(t, err)
  1255  		assert.Equal(t, 2, count)
  1256  	})
  1257  
  1258  	t.Run("should count channel-wide mentions when enabled", func(t *testing.T) {
  1259  		th := Setup(t).InitBasic()
  1260  		defer th.TearDown()
  1261  
  1262  		user1 := th.BasicUser
  1263  		user2 := th.BasicUser2
  1264  
  1265  		channel := th.CreateChannel(th.BasicTeam)
  1266  		th.AddUserToChannel(user2, channel)
  1267  
  1268  		user2.NotifyProps[model.CHANNEL_MENTIONS_NOTIFY_PROP] = "true"
  1269  
  1270  		post1, err := th.App.CreatePost(&model.Post{
  1271  			UserId:    user1.Id,
  1272  			ChannelId: channel.Id,
  1273  			Message:   "test",
  1274  		}, channel, false, true)
  1275  		require.Nil(t, err)
  1276  		_, err = th.App.CreatePost(&model.Post{
  1277  			UserId:    user1.Id,
  1278  			ChannelId: channel.Id,
  1279  			Message:   "@channel",
  1280  		}, channel, false, true)
  1281  		require.Nil(t, err)
  1282  		_, err = th.App.CreatePost(&model.Post{
  1283  			UserId:    user1.Id,
  1284  			ChannelId: channel.Id,
  1285  			Message:   "@all",
  1286  		}, channel, false, true)
  1287  		require.Nil(t, err)
  1288  
  1289  		// post2 and post3 should mention the user
  1290  
  1291  		count, err := th.App.countMentionsFromPost(user2, post1)
  1292  
  1293  		assert.Nil(t, err)
  1294  		assert.Equal(t, 2, count)
  1295  	})
  1296  
  1297  	t.Run("should not count channel-wide mentions when disabled for user", func(t *testing.T) {
  1298  		th := Setup(t).InitBasic()
  1299  		defer th.TearDown()
  1300  
  1301  		user1 := th.BasicUser
  1302  		user2 := th.BasicUser2
  1303  
  1304  		channel := th.CreateChannel(th.BasicTeam)
  1305  		th.AddUserToChannel(user2, channel)
  1306  
  1307  		user2.NotifyProps[model.CHANNEL_MENTIONS_NOTIFY_PROP] = "false"
  1308  
  1309  		post1, err := th.App.CreatePost(&model.Post{
  1310  			UserId:    user1.Id,
  1311  			ChannelId: channel.Id,
  1312  			Message:   "test",
  1313  		}, channel, false, true)
  1314  		require.Nil(t, err)
  1315  		_, err = th.App.CreatePost(&model.Post{
  1316  			UserId:    user1.Id,
  1317  			ChannelId: channel.Id,
  1318  			Message:   "@channel",
  1319  		}, channel, false, true)
  1320  		require.Nil(t, err)
  1321  		_, err = th.App.CreatePost(&model.Post{
  1322  			UserId:    user1.Id,
  1323  			ChannelId: channel.Id,
  1324  			Message:   "@all",
  1325  		}, channel, false, true)
  1326  		require.Nil(t, err)
  1327  
  1328  		count, err := th.App.countMentionsFromPost(user2, post1)
  1329  
  1330  		assert.Nil(t, err)
  1331  		assert.Equal(t, 0, count)
  1332  	})
  1333  
  1334  	t.Run("should not count channel-wide mentions when disabled for channel", func(t *testing.T) {
  1335  		th := Setup(t).InitBasic()
  1336  		defer th.TearDown()
  1337  
  1338  		user1 := th.BasicUser
  1339  		user2 := th.BasicUser2
  1340  
  1341  		channel := th.CreateChannel(th.BasicTeam)
  1342  		th.AddUserToChannel(user2, channel)
  1343  
  1344  		user2.NotifyProps[model.CHANNEL_MENTIONS_NOTIFY_PROP] = "true"
  1345  
  1346  		_, err := th.App.UpdateChannelMemberNotifyProps(map[string]string{
  1347  			model.IGNORE_CHANNEL_MENTIONS_NOTIFY_PROP: model.IGNORE_CHANNEL_MENTIONS_ON,
  1348  		}, channel.Id, user2.Id)
  1349  		require.Nil(t, err)
  1350  
  1351  		post1, err := th.App.CreatePost(&model.Post{
  1352  			UserId:    user1.Id,
  1353  			ChannelId: channel.Id,
  1354  			Message:   "test",
  1355  		}, channel, false, true)
  1356  		require.Nil(t, err)
  1357  		_, err = th.App.CreatePost(&model.Post{
  1358  			UserId:    user1.Id,
  1359  			ChannelId: channel.Id,
  1360  			Message:   "@channel",
  1361  		}, channel, false, true)
  1362  		require.Nil(t, err)
  1363  		_, err = th.App.CreatePost(&model.Post{
  1364  			UserId:    user1.Id,
  1365  			ChannelId: channel.Id,
  1366  			Message:   "@all",
  1367  		}, channel, false, true)
  1368  		require.Nil(t, err)
  1369  
  1370  		count, err := th.App.countMentionsFromPost(user2, post1)
  1371  
  1372  		assert.Nil(t, err)
  1373  		assert.Equal(t, 0, count)
  1374  	})
  1375  
  1376  	t.Run("should count comment mentions when using COMMENTS_NOTIFY_ROOT", func(t *testing.T) {
  1377  		th := Setup(t).InitBasic()
  1378  		defer th.TearDown()
  1379  
  1380  		user1 := th.BasicUser
  1381  		user2 := th.BasicUser2
  1382  
  1383  		channel := th.CreateChannel(th.BasicTeam)
  1384  		th.AddUserToChannel(user2, channel)
  1385  
  1386  		user2.NotifyProps[model.COMMENTS_NOTIFY_PROP] = model.COMMENTS_NOTIFY_ROOT
  1387  
  1388  		post1, err := th.App.CreatePost(&model.Post{
  1389  			UserId:    user2.Id,
  1390  			ChannelId: channel.Id,
  1391  			Message:   "test",
  1392  		}, channel, false, true)
  1393  		require.Nil(t, err)
  1394  		_, err = th.App.CreatePost(&model.Post{
  1395  			UserId:    user1.Id,
  1396  			ChannelId: channel.Id,
  1397  			RootId:    post1.Id,
  1398  			Message:   "test2",
  1399  		}, channel, false, true)
  1400  		require.Nil(t, err)
  1401  		post3, err := th.App.CreatePost(&model.Post{
  1402  			UserId:    user1.Id,
  1403  			ChannelId: channel.Id,
  1404  			Message:   "test3",
  1405  		}, channel, false, true)
  1406  		require.Nil(t, err)
  1407  		_, err = th.App.CreatePost(&model.Post{
  1408  			UserId:    user2.Id,
  1409  			ChannelId: channel.Id,
  1410  			RootId:    post3.Id,
  1411  			Message:   "test4",
  1412  		}, channel, false, true)
  1413  		require.Nil(t, err)
  1414  		_, err = th.App.CreatePost(&model.Post{
  1415  			UserId:    user1.Id,
  1416  			ChannelId: channel.Id,
  1417  			RootId:    post3.Id,
  1418  			Message:   "test5",
  1419  		}, channel, false, true)
  1420  		require.Nil(t, err)
  1421  
  1422  		// post2 should mention the user
  1423  
  1424  		count, err := th.App.countMentionsFromPost(user2, post1)
  1425  
  1426  		assert.Nil(t, err)
  1427  		assert.Equal(t, 1, count)
  1428  	})
  1429  
  1430  	t.Run("should count comment mentions when using COMMENTS_NOTIFY_ANY", func(t *testing.T) {
  1431  		th := Setup(t).InitBasic()
  1432  		defer th.TearDown()
  1433  
  1434  		user1 := th.BasicUser
  1435  		user2 := th.BasicUser2
  1436  
  1437  		channel := th.CreateChannel(th.BasicTeam)
  1438  		th.AddUserToChannel(user2, channel)
  1439  
  1440  		user2.NotifyProps[model.COMMENTS_NOTIFY_PROP] = model.COMMENTS_NOTIFY_ANY
  1441  
  1442  		post1, err := th.App.CreatePost(&model.Post{
  1443  			UserId:    user2.Id,
  1444  			ChannelId: channel.Id,
  1445  			Message:   "test",
  1446  		}, channel, false, true)
  1447  		require.Nil(t, err)
  1448  		_, err = th.App.CreatePost(&model.Post{
  1449  			UserId:    user1.Id,
  1450  			ChannelId: channel.Id,
  1451  			RootId:    post1.Id,
  1452  			Message:   "test2",
  1453  		}, channel, false, true)
  1454  		require.Nil(t, err)
  1455  		post3, err := th.App.CreatePost(&model.Post{
  1456  			UserId:    user1.Id,
  1457  			ChannelId: channel.Id,
  1458  			Message:   "test3",
  1459  		}, channel, false, true)
  1460  		require.Nil(t, err)
  1461  		_, err = th.App.CreatePost(&model.Post{
  1462  			UserId:    user2.Id,
  1463  			ChannelId: channel.Id,
  1464  			RootId:    post3.Id,
  1465  			Message:   "test4",
  1466  		}, channel, false, true)
  1467  		require.Nil(t, err)
  1468  		_, err = th.App.CreatePost(&model.Post{
  1469  			UserId:    user1.Id,
  1470  			ChannelId: channel.Id,
  1471  			RootId:    post3.Id,
  1472  			Message:   "test5",
  1473  		}, channel, false, true)
  1474  		require.Nil(t, err)
  1475  
  1476  		// post2 and post5 should mention the user
  1477  
  1478  		count, err := th.App.countMentionsFromPost(user2, post1)
  1479  
  1480  		assert.Nil(t, err)
  1481  		assert.Equal(t, 2, count)
  1482  	})
  1483  
  1484  	t.Run("should count mentions caused by being added to the channel", func(t *testing.T) {
  1485  		th := Setup(t).InitBasic()
  1486  		defer th.TearDown()
  1487  
  1488  		user1 := th.BasicUser
  1489  		user2 := th.BasicUser2
  1490  
  1491  		channel := th.CreateChannel(th.BasicTeam)
  1492  		th.AddUserToChannel(user2, channel)
  1493  
  1494  		post1, err := th.App.CreatePost(&model.Post{
  1495  			UserId:    user1.Id,
  1496  			ChannelId: channel.Id,
  1497  			Message:   "test",
  1498  			Type:      model.POST_ADD_TO_CHANNEL,
  1499  			Props: map[string]interface{}{
  1500  				model.POST_PROPS_ADDED_USER_ID: model.NewId(),
  1501  			},
  1502  		}, channel, false, true)
  1503  		require.Nil(t, err)
  1504  		_, err = th.App.CreatePost(&model.Post{
  1505  			UserId:    user1.Id,
  1506  			ChannelId: channel.Id,
  1507  			Message:   "test2",
  1508  			Type:      model.POST_ADD_TO_CHANNEL,
  1509  			Props: map[string]interface{}{
  1510  				model.POST_PROPS_ADDED_USER_ID: user2.Id,
  1511  			},
  1512  		}, channel, false, true)
  1513  		require.Nil(t, err)
  1514  		_, err = th.App.CreatePost(&model.Post{
  1515  			UserId:    user1.Id,
  1516  			ChannelId: channel.Id,
  1517  			Message:   "test3",
  1518  			Type:      model.POST_ADD_TO_CHANNEL,
  1519  			Props: map[string]interface{}{
  1520  				model.POST_PROPS_ADDED_USER_ID: user2.Id,
  1521  			},
  1522  		}, channel, false, true)
  1523  		require.Nil(t, err)
  1524  
  1525  		// should be mentioned by post2 and post3
  1526  
  1527  		count, err := th.App.countMentionsFromPost(user2, post1)
  1528  
  1529  		assert.Nil(t, err)
  1530  		assert.Equal(t, 2, count)
  1531  	})
  1532  
  1533  	t.Run("should return the number of posts made by the other user for a direct channel", func(t *testing.T) {
  1534  		th := Setup(t).InitBasic()
  1535  		defer th.TearDown()
  1536  
  1537  		user1 := th.BasicUser
  1538  		user2 := th.BasicUser2
  1539  
  1540  		channel, err := th.App.createDirectChannel(user1.Id, user2.Id)
  1541  		require.Nil(t, err)
  1542  
  1543  		post1, err := th.App.CreatePost(&model.Post{
  1544  			UserId:    user1.Id,
  1545  			ChannelId: channel.Id,
  1546  			Message:   "test",
  1547  		}, channel, false, true)
  1548  		require.Nil(t, err)
  1549  
  1550  		_, err = th.App.CreatePost(&model.Post{
  1551  			UserId:    user1.Id,
  1552  			ChannelId: channel.Id,
  1553  			Message:   "test2",
  1554  		}, channel, false, true)
  1555  		require.Nil(t, err)
  1556  
  1557  		count, err := th.App.countMentionsFromPost(user2, post1)
  1558  
  1559  		assert.Nil(t, err)
  1560  		assert.Equal(t, 2, count)
  1561  
  1562  		count, err = th.App.countMentionsFromPost(user1, post1)
  1563  
  1564  		assert.Nil(t, err)
  1565  		assert.Equal(t, 0, count)
  1566  	})
  1567  
  1568  	t.Run("should not count mentions from the before the given post", func(t *testing.T) {
  1569  		th := Setup(t).InitBasic()
  1570  		defer th.TearDown()
  1571  
  1572  		user1 := th.BasicUser
  1573  		user2 := th.BasicUser2
  1574  
  1575  		channel := th.CreateChannel(th.BasicTeam)
  1576  		th.AddUserToChannel(user2, channel)
  1577  
  1578  		_, err := th.App.CreatePost(&model.Post{
  1579  			UserId:    user1.Id,
  1580  			ChannelId: channel.Id,
  1581  			Message:   fmt.Sprintf("@%s", user2.Username),
  1582  		}, channel, false, true)
  1583  		require.Nil(t, err)
  1584  		post2, err := th.App.CreatePost(&model.Post{
  1585  			UserId:    user1.Id,
  1586  			ChannelId: channel.Id,
  1587  			Message:   "test2",
  1588  		}, channel, false, true)
  1589  		require.Nil(t, err)
  1590  		_, err = th.App.CreatePost(&model.Post{
  1591  			UserId:    user1.Id,
  1592  			ChannelId: channel.Id,
  1593  			Message:   fmt.Sprintf("@%s", user2.Username),
  1594  		}, channel, false, true)
  1595  		require.Nil(t, err)
  1596  
  1597  		// post1 and post3 should mention the user, but we only count post3
  1598  
  1599  		count, err := th.App.countMentionsFromPost(user2, post2)
  1600  
  1601  		assert.Nil(t, err)
  1602  		assert.Equal(t, 1, count)
  1603  	})
  1604  
  1605  	t.Run("should not count mentions from the user's own posts", func(t *testing.T) {
  1606  		th := Setup(t).InitBasic()
  1607  		defer th.TearDown()
  1608  
  1609  		user1 := th.BasicUser
  1610  		user2 := th.BasicUser2
  1611  
  1612  		channel := th.CreateChannel(th.BasicTeam)
  1613  		th.AddUserToChannel(user2, channel)
  1614  
  1615  		post1, err := th.App.CreatePost(&model.Post{
  1616  			UserId:    user1.Id,
  1617  			ChannelId: channel.Id,
  1618  			Message:   fmt.Sprintf("@%s", user2.Username),
  1619  		}, channel, false, true)
  1620  		require.Nil(t, err)
  1621  		_, err = th.App.CreatePost(&model.Post{
  1622  			UserId:    user2.Id,
  1623  			ChannelId: channel.Id,
  1624  			Message:   fmt.Sprintf("@%s", user2.Username),
  1625  		}, channel, false, true)
  1626  		require.Nil(t, err)
  1627  
  1628  		// post2 should mention the user
  1629  
  1630  		count, err := th.App.countMentionsFromPost(user2, post1)
  1631  
  1632  		assert.Nil(t, err)
  1633  		assert.Equal(t, 1, count)
  1634  	})
  1635  
  1636  	t.Run("should include comments made before the given post when counting comment mentions", func(t *testing.T) {
  1637  		th := Setup(t).InitBasic()
  1638  		defer th.TearDown()
  1639  
  1640  		user1 := th.BasicUser
  1641  		user2 := th.BasicUser2
  1642  
  1643  		channel := th.CreateChannel(th.BasicTeam)
  1644  		th.AddUserToChannel(user2, channel)
  1645  
  1646  		user2.NotifyProps[model.COMMENTS_NOTIFY_PROP] = model.COMMENTS_NOTIFY_ANY
  1647  
  1648  		post1, err := th.App.CreatePost(&model.Post{
  1649  			UserId:    user1.Id,
  1650  			ChannelId: channel.Id,
  1651  			Message:   "test1",
  1652  		}, channel, false, true)
  1653  		require.Nil(t, err)
  1654  		_, err = th.App.CreatePost(&model.Post{
  1655  			UserId:    user2.Id,
  1656  			ChannelId: channel.Id,
  1657  			RootId:    post1.Id,
  1658  			Message:   "test2",
  1659  		}, channel, false, true)
  1660  		require.Nil(t, err)
  1661  		post3, err := th.App.CreatePost(&model.Post{
  1662  			UserId:    user1.Id,
  1663  			ChannelId: channel.Id,
  1664  			Message:   "test3",
  1665  		}, channel, false, true)
  1666  		require.Nil(t, err)
  1667  		_, err = th.App.CreatePost(&model.Post{
  1668  			UserId:    user1.Id,
  1669  			ChannelId: channel.Id,
  1670  			RootId:    post1.Id,
  1671  			Message:   "test4",
  1672  		}, channel, false, true)
  1673  		require.Nil(t, err)
  1674  
  1675  		// post4 should mention the user
  1676  
  1677  		count, err := th.App.countMentionsFromPost(user2, post3)
  1678  
  1679  		assert.Nil(t, err)
  1680  		assert.Equal(t, 1, count)
  1681  	})
  1682  
  1683  	t.Run("should count mentions from the user's webhook posts", func(t *testing.T) {
  1684  		th := Setup(t).InitBasic()
  1685  		defer th.TearDown()
  1686  
  1687  		user1 := th.BasicUser
  1688  		user2 := th.BasicUser2
  1689  
  1690  		channel := th.CreateChannel(th.BasicTeam)
  1691  		th.AddUserToChannel(user2, channel)
  1692  
  1693  		post1, err := th.App.CreatePost(&model.Post{
  1694  			UserId:    user1.Id,
  1695  			ChannelId: channel.Id,
  1696  			Message:   "test1",
  1697  		}, channel, false, true)
  1698  		require.Nil(t, err)
  1699  		_, err = th.App.CreatePost(&model.Post{
  1700  			UserId:    user2.Id,
  1701  			ChannelId: channel.Id,
  1702  			Message:   fmt.Sprintf("@%s", user2.Username),
  1703  		}, channel, false, true)
  1704  		require.Nil(t, err)
  1705  		_, err = th.App.CreatePost(&model.Post{
  1706  			UserId:    user2.Id,
  1707  			ChannelId: channel.Id,
  1708  			Message:   fmt.Sprintf("@%s", user2.Username),
  1709  			Props: map[string]interface{}{
  1710  				"from_webhook": "true",
  1711  			},
  1712  		}, channel, false, true)
  1713  		require.Nil(t, err)
  1714  
  1715  		// post3 should mention the user
  1716  
  1717  		count, err := th.App.countMentionsFromPost(user2, post1)
  1718  
  1719  		assert.Nil(t, err)
  1720  		assert.Equal(t, 1, count)
  1721  	})
  1722  
  1723  	t.Run("should count multiple pages of mentions", func(t *testing.T) {
  1724  		th := Setup(t).InitBasic()
  1725  		defer th.TearDown()
  1726  
  1727  		user1 := th.BasicUser
  1728  		user2 := th.BasicUser2
  1729  
  1730  		channel := th.CreateChannel(th.BasicTeam)
  1731  		th.AddUserToChannel(user2, channel)
  1732  
  1733  		numPosts := 215
  1734  
  1735  		post1, err := th.App.CreatePost(&model.Post{
  1736  			UserId:    user1.Id,
  1737  			ChannelId: channel.Id,
  1738  			Message:   fmt.Sprintf("@%s", user2.Username),
  1739  		}, channel, false, true)
  1740  		require.Nil(t, err)
  1741  
  1742  		for i := 0; i < numPosts-1; i++ {
  1743  			_, err = th.App.CreatePost(&model.Post{
  1744  				UserId:    user1.Id,
  1745  				ChannelId: channel.Id,
  1746  				Message:   fmt.Sprintf("@%s", user2.Username),
  1747  			}, channel, false, true)
  1748  			require.Nil(t, err)
  1749  		}
  1750  
  1751  		// Every post should mention the user
  1752  
  1753  		count, err := th.App.countMentionsFromPost(user2, post1)
  1754  
  1755  		assert.Nil(t, err)
  1756  		assert.Equal(t, numPosts, count)
  1757  	})
  1758  }
  1759  
  1760  func TestFillInPostProps(t *testing.T) {
  1761  	t.Run("should not add disable group highlight to post props for user with group mention permissions", func(t *testing.T) {
  1762  		th := Setup(t).InitBasic()
  1763  		defer th.TearDown()
  1764  		th.App.Srv().SetLicense(model.NewTestLicense("ldap"))
  1765  
  1766  		user1 := th.BasicUser
  1767  
  1768  		channel := th.CreateChannel(th.BasicTeam)
  1769  
  1770  		post1, err := th.App.CreatePost(&model.Post{
  1771  			UserId:    user1.Id,
  1772  			ChannelId: channel.Id,
  1773  			Message:   "test123123 @group1 @group2 blah blah blah",
  1774  		}, channel, false, true)
  1775  		require.Nil(t, err)
  1776  
  1777  		err = th.App.FillInPostProps(post1, channel)
  1778  
  1779  		assert.Nil(t, err)
  1780  		assert.Equal(t, post1.Props, model.StringInterface{})
  1781  	})
  1782  
  1783  	t.Run("should not add disable group highlight to post props for app without license", func(t *testing.T) {
  1784  		th := Setup(t).InitBasic()
  1785  		defer th.TearDown()
  1786  
  1787  		id := model.NewId()
  1788  		guest := &model.User{
  1789  			Email:         "success+" + id + "@simulator.amazonses.com",
  1790  			Username:      "un_" + id,
  1791  			Nickname:      "nn_" + id,
  1792  			Password:      "Password1",
  1793  			EmailVerified: true,
  1794  		}
  1795  		guest, err := th.App.CreateGuest(guest)
  1796  		require.Nil(t, err)
  1797  		th.LinkUserToTeam(guest, th.BasicTeam)
  1798  
  1799  		channel := th.CreateChannel(th.BasicTeam)
  1800  		th.AddUserToChannel(guest, channel)
  1801  
  1802  		post1, err := th.App.CreatePost(&model.Post{
  1803  			UserId:    guest.Id,
  1804  			ChannelId: channel.Id,
  1805  			Message:   "test123123 @group1 @group2 blah blah blah",
  1806  		}, channel, false, true)
  1807  		require.Nil(t, err)
  1808  
  1809  		err = th.App.FillInPostProps(post1, channel)
  1810  
  1811  		assert.Nil(t, err)
  1812  		assert.Equal(t, post1.Props, model.StringInterface{})
  1813  	})
  1814  
  1815  	t.Run("should add disable group highlight to post props for guest user", func(t *testing.T) {
  1816  		th := Setup(t).InitBasic()
  1817  		defer th.TearDown()
  1818  		th.App.Srv().SetLicense(model.NewTestLicense("ldap"))
  1819  
  1820  		id := model.NewId()
  1821  		guest := &model.User{
  1822  			Email:         "success+" + id + "@simulator.amazonses.com",
  1823  			Username:      "un_" + id,
  1824  			Nickname:      "nn_" + id,
  1825  			Password:      "Password1",
  1826  			EmailVerified: true,
  1827  		}
  1828  		guest, err := th.App.CreateGuest(guest)
  1829  		require.Nil(t, err)
  1830  		th.LinkUserToTeam(guest, th.BasicTeam)
  1831  
  1832  		channel := th.CreateChannel(th.BasicTeam)
  1833  		th.AddUserToChannel(guest, channel)
  1834  
  1835  		post1, err := th.App.CreatePost(&model.Post{
  1836  			UserId:    guest.Id,
  1837  			ChannelId: channel.Id,
  1838  			Message:   "test123123 @group1 @group2 blah blah blah",
  1839  		}, channel, false, true)
  1840  		require.Nil(t, err)
  1841  
  1842  		err = th.App.FillInPostProps(post1, channel)
  1843  
  1844  		assert.Nil(t, err)
  1845  		assert.Equal(t, post1.Props, model.StringInterface{"disable_group_highlight": true})
  1846  	})
  1847  }