github.com/turgay/mattermost-server@v5.3.2-0.20181002173352-2945e8a2b0ce+incompatible/api4/post_test.go (about)

     1  // Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
     2  // See License.txt for license information.
     3  
     4  package api4
     5  
     6  import (
     7  	"encoding/json"
     8  	"fmt"
     9  	"net/http"
    10  	"net/http/httptest"
    11  	"net/url"
    12  	"reflect"
    13  	"strconv"
    14  	"strings"
    15  	"testing"
    16  	"time"
    17  
    18  	"github.com/stretchr/testify/assert"
    19  
    20  	"github.com/mattermost/mattermost-server/app"
    21  	"github.com/mattermost/mattermost-server/model"
    22  	"github.com/mattermost/mattermost-server/utils"
    23  )
    24  
    25  func TestCreatePost(t *testing.T) {
    26  	th := Setup().InitBasic().InitSystemAdmin()
    27  	defer th.TearDown()
    28  	Client := th.Client
    29  
    30  	post := &model.Post{ChannelId: th.BasicChannel.Id, Message: "#hashtag a" + model.NewId() + "a", Props: model.StringInterface{model.PROPS_ADD_CHANNEL_MEMBER: "no good"}}
    31  	rpost, resp := Client.CreatePost(post)
    32  	CheckNoError(t, resp)
    33  	CheckCreatedStatus(t, resp)
    34  
    35  	if rpost.Message != post.Message {
    36  		t.Fatal("message didn't match")
    37  	}
    38  
    39  	if rpost.Hashtags != "#hashtag" {
    40  		t.Fatal("hashtag didn't match")
    41  	}
    42  
    43  	if len(rpost.FileIds) != 0 {
    44  		t.Fatal("shouldn't have files")
    45  	}
    46  
    47  	if rpost.EditAt != 0 {
    48  		t.Fatal("newly created post shouldn't have EditAt set")
    49  	}
    50  
    51  	if rpost.Props[model.PROPS_ADD_CHANNEL_MEMBER] != nil {
    52  		t.Fatal("newly created post shouldn't have Props['add_channel_member'] set")
    53  	}
    54  
    55  	post.RootId = rpost.Id
    56  	post.ParentId = rpost.Id
    57  	_, resp = Client.CreatePost(post)
    58  	CheckNoError(t, resp)
    59  
    60  	post.RootId = "junk"
    61  	_, resp = Client.CreatePost(post)
    62  	CheckBadRequestStatus(t, resp)
    63  
    64  	post.RootId = rpost.Id
    65  	post.ParentId = "junk"
    66  	_, resp = Client.CreatePost(post)
    67  	CheckBadRequestStatus(t, resp)
    68  
    69  	post2 := &model.Post{ChannelId: th.BasicChannel2.Id, Message: "zz" + model.NewId() + "a", CreateAt: 123}
    70  	rpost2, _ := Client.CreatePost(post2)
    71  
    72  	if rpost2.CreateAt == post2.CreateAt {
    73  		t.Fatal("create at should not match")
    74  	}
    75  
    76  	post.RootId = ""
    77  	post.ParentId = ""
    78  	post.Type = model.POST_SYSTEM_GENERIC
    79  	_, resp = Client.CreatePost(post)
    80  	CheckBadRequestStatus(t, resp)
    81  
    82  	post.Type = ""
    83  	post.RootId = rpost2.Id
    84  	post.ParentId = rpost2.Id
    85  	_, resp = Client.CreatePost(post)
    86  	CheckBadRequestStatus(t, resp)
    87  
    88  	post.RootId = ""
    89  	post.ParentId = ""
    90  	post.ChannelId = "junk"
    91  	_, resp = Client.CreatePost(post)
    92  	CheckForbiddenStatus(t, resp)
    93  
    94  	post.ChannelId = model.NewId()
    95  	_, resp = Client.CreatePost(post)
    96  	CheckForbiddenStatus(t, resp)
    97  
    98  	if r, err := Client.DoApiPost("/posts", "garbage"); err == nil {
    99  		t.Fatal("should have errored")
   100  	} else {
   101  		if r.StatusCode != http.StatusBadRequest {
   102  			t.Log("actual: " + strconv.Itoa(r.StatusCode))
   103  			t.Log("expected: " + strconv.Itoa(http.StatusBadRequest))
   104  			t.Fatal("wrong status code")
   105  		}
   106  	}
   107  
   108  	Client.Logout()
   109  	_, resp = Client.CreatePost(post)
   110  	CheckUnauthorizedStatus(t, resp)
   111  
   112  	post.ChannelId = th.BasicChannel.Id
   113  	post.CreateAt = 123
   114  	rpost, resp = th.SystemAdminClient.CreatePost(post)
   115  	CheckNoError(t, resp)
   116  
   117  	if rpost.CreateAt != post.CreateAt {
   118  		t.Fatal("create at should match")
   119  	}
   120  }
   121  
   122  func TestCreatePostEphemeral(t *testing.T) {
   123  	th := Setup().InitBasic().InitSystemAdmin()
   124  	defer th.TearDown()
   125  	Client := th.SystemAdminClient
   126  
   127  	ephemeralPost := &model.PostEphemeral{
   128  		UserID: th.BasicUser2.Id,
   129  		Post:   &model.Post{ChannelId: th.BasicChannel.Id, Message: "a" + model.NewId() + "a", Props: model.StringInterface{model.PROPS_ADD_CHANNEL_MEMBER: "no good"}},
   130  	}
   131  
   132  	rpost, resp := Client.CreatePostEphemeral(ephemeralPost)
   133  	CheckNoError(t, resp)
   134  	CheckCreatedStatus(t, resp)
   135  
   136  	if rpost.Message != ephemeralPost.Post.Message {
   137  		t.Fatal("message didn't match")
   138  	}
   139  
   140  	if rpost.EditAt != 0 {
   141  		t.Fatal("newly created ephemeral post shouldn't have EditAt set")
   142  	}
   143  
   144  	if r, err := Client.DoApiPost("/posts/ephemeral", "garbage"); err == nil {
   145  		t.Fatal("should have errored")
   146  	} else {
   147  		if r.StatusCode != http.StatusBadRequest {
   148  			t.Log("actual: " + strconv.Itoa(r.StatusCode))
   149  			t.Log("expected: " + strconv.Itoa(http.StatusBadRequest))
   150  			t.Fatal("wrong status code")
   151  		}
   152  	}
   153  
   154  	Client.Logout()
   155  	_, resp = Client.CreatePostEphemeral(ephemeralPost)
   156  	CheckUnauthorizedStatus(t, resp)
   157  
   158  	Client = th.Client
   159  	_, resp = Client.CreatePostEphemeral(ephemeralPost)
   160  	CheckForbiddenStatus(t, resp)
   161  }
   162  
   163  func testCreatePostWithOutgoingHook(
   164  	t *testing.T,
   165  	hookContentType, expectedContentType, message, triggerWord string,
   166  	fileIds []string,
   167  	triggerWhen int,
   168  	commentPostType bool,
   169  ) {
   170  	th := Setup().InitBasic().InitSystemAdmin()
   171  	defer th.TearDown()
   172  	user := th.SystemAdminUser
   173  	team := th.BasicTeam
   174  	channel := th.BasicChannel
   175  
   176  	enableOutgoingWebhooks := th.App.Config().ServiceSettings.EnableOutgoingWebhooks
   177  	allowedUntrustedInternalConnections := th.App.Config().ServiceSettings.AllowedUntrustedInternalConnections
   178  	defer func() {
   179  		th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableOutgoingWebhooks = enableOutgoingWebhooks })
   180  		th.App.UpdateConfig(func(cfg *model.Config) {
   181  			cfg.ServiceSettings.AllowedUntrustedInternalConnections = allowedUntrustedInternalConnections
   182  		})
   183  	}()
   184  
   185  	th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableOutgoingWebhooks = true })
   186  	th.App.UpdateConfig(func(cfg *model.Config) {
   187  		*cfg.ServiceSettings.AllowedUntrustedInternalConnections = "localhost 127.0.0.1"
   188  	})
   189  
   190  	var hook *model.OutgoingWebhook
   191  	var post *model.Post
   192  
   193  	// Create a test server that is the target of the outgoing webhook. It will
   194  	// validate the webhook body fields and write to the success channel on
   195  	// success/failure.
   196  	success := make(chan bool)
   197  	wait := make(chan bool, 1)
   198  	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   199  		<-wait
   200  
   201  		requestContentType := r.Header.Get("Content-Type")
   202  		if requestContentType != expectedContentType {
   203  			t.Logf("Content-Type is %s, should be %s", requestContentType, expectedContentType)
   204  			success <- false
   205  			return
   206  		}
   207  
   208  		expectedPayload := &model.OutgoingWebhookPayload{
   209  			Token:       hook.Token,
   210  			TeamId:      hook.TeamId,
   211  			TeamDomain:  team.Name,
   212  			ChannelId:   post.ChannelId,
   213  			ChannelName: channel.Name,
   214  			Timestamp:   post.CreateAt,
   215  			UserId:      post.UserId,
   216  			UserName:    user.Username,
   217  			PostId:      post.Id,
   218  			Text:        post.Message,
   219  			TriggerWord: triggerWord,
   220  			FileIds:     strings.Join(post.FileIds, ","),
   221  		}
   222  
   223  		// depending on the Content-Type, we expect to find a JSON or form encoded payload
   224  		if requestContentType == "application/json" {
   225  			decoder := json.NewDecoder(r.Body)
   226  			o := &model.OutgoingWebhookPayload{}
   227  			decoder.Decode(&o)
   228  
   229  			if !reflect.DeepEqual(expectedPayload, o) {
   230  				t.Logf("JSON payload is %+v, should be %+v", o, expectedPayload)
   231  				success <- false
   232  				return
   233  			}
   234  		} else {
   235  			err := r.ParseForm()
   236  			if err != nil {
   237  				t.Logf("Error parsing form: %q", err)
   238  				success <- false
   239  				return
   240  			}
   241  
   242  			expectedFormValues, _ := url.ParseQuery(expectedPayload.ToFormValues())
   243  
   244  			if !reflect.DeepEqual(expectedFormValues, r.Form) {
   245  				t.Logf("Form values are: %q\n, should be: %q\n", r.Form, expectedFormValues)
   246  				success <- false
   247  				return
   248  			}
   249  		}
   250  
   251  		respPostType := "" //if is empty or post will do a normal post.
   252  		if commentPostType {
   253  			respPostType = model.OUTGOING_HOOK_RESPONSE_TYPE_COMMENT
   254  		}
   255  
   256  		outGoingHookResponse := &model.OutgoingWebhookResponse{
   257  			Text:         model.NewString("some test text"),
   258  			Username:     "TestCommandServer",
   259  			IconURL:      "https://www.mattermost.org/wp-content/uploads/2016/04/icon.png",
   260  			Type:         "custom_as",
   261  			ResponseType: respPostType,
   262  		}
   263  
   264  		fmt.Fprintf(w, outGoingHookResponse.ToJson())
   265  		success <- true
   266  	}))
   267  	defer ts.Close()
   268  
   269  	// create an outgoing webhook, passing it the test server URL
   270  	var triggerWords []string
   271  	if triggerWord != "" {
   272  		triggerWords = []string{triggerWord}
   273  	}
   274  
   275  	hook = &model.OutgoingWebhook{
   276  		ChannelId:    channel.Id,
   277  		TeamId:       team.Id,
   278  		ContentType:  hookContentType,
   279  		TriggerWords: triggerWords,
   280  		TriggerWhen:  triggerWhen,
   281  		CallbackURLs: []string{ts.URL},
   282  	}
   283  
   284  	hook, resp := th.SystemAdminClient.CreateOutgoingWebhook(hook)
   285  	CheckNoError(t, resp)
   286  
   287  	// create a post to trigger the webhook
   288  	post = &model.Post{
   289  		ChannelId: channel.Id,
   290  		Message:   message,
   291  		FileIds:   fileIds,
   292  	}
   293  
   294  	post, resp = th.SystemAdminClient.CreatePost(post)
   295  	CheckNoError(t, resp)
   296  
   297  	wait <- true
   298  
   299  	// We wait for the test server to write to the success channel and we make
   300  	// the test fail if that doesn't happen before the timeout.
   301  	select {
   302  	case ok := <-success:
   303  		if !ok {
   304  			t.Fatal("Test server did send an invalid webhook.")
   305  		}
   306  	case <-time.After(time.Second):
   307  		t.Fatal("Timeout, test server did not send the webhook.")
   308  	}
   309  
   310  	if commentPostType {
   311  		time.Sleep(time.Millisecond * 100)
   312  		postList, resp := th.SystemAdminClient.GetPostThread(post.Id, "")
   313  		CheckNoError(t, resp)
   314  		if postList.Order[0] != post.Id {
   315  			t.Fatal("wrong order")
   316  		}
   317  
   318  		if _, ok := postList.Posts[post.Id]; !ok {
   319  			t.Fatal("should have had post")
   320  		}
   321  
   322  		if len(postList.Posts) != 2 {
   323  			t.Fatal("should have 2 posts")
   324  		}
   325  
   326  	}
   327  }
   328  
   329  func TestCreatePostWithOutgoingHook_form_urlencoded(t *testing.T) {
   330  	testCreatePostWithOutgoingHook(t, "application/x-www-form-urlencoded", "application/x-www-form-urlencoded", "triggerword lorem ipsum", "triggerword", []string{"file_id_1"}, app.TRIGGERWORDS_EXACT_MATCH, false)
   331  	testCreatePostWithOutgoingHook(t, "application/x-www-form-urlencoded", "application/x-www-form-urlencoded", "triggerwordaaazzz lorem ipsum", "triggerword", []string{"file_id_1"}, app.TRIGGERWORDS_STARTS_WITH, false)
   332  	testCreatePostWithOutgoingHook(t, "application/x-www-form-urlencoded", "application/x-www-form-urlencoded", "", "", []string{"file_id_1"}, app.TRIGGERWORDS_EXACT_MATCH, false)
   333  	testCreatePostWithOutgoingHook(t, "application/x-www-form-urlencoded", "application/x-www-form-urlencoded", "", "", []string{"file_id_1"}, app.TRIGGERWORDS_STARTS_WITH, false)
   334  	testCreatePostWithOutgoingHook(t, "application/x-www-form-urlencoded", "application/x-www-form-urlencoded", "triggerword lorem ipsum", "triggerword", []string{"file_id_1"}, app.TRIGGERWORDS_EXACT_MATCH, true)
   335  	testCreatePostWithOutgoingHook(t, "application/x-www-form-urlencoded", "application/x-www-form-urlencoded", "triggerwordaaazzz lorem ipsum", "triggerword", []string{"file_id_1"}, app.TRIGGERWORDS_STARTS_WITH, true)
   336  }
   337  
   338  func TestCreatePostWithOutgoingHook_json(t *testing.T) {
   339  	testCreatePostWithOutgoingHook(t, "application/json", "application/json", "triggerword lorem ipsum", "triggerword", []string{"file_id_1, file_id_2"}, app.TRIGGERWORDS_EXACT_MATCH, false)
   340  	testCreatePostWithOutgoingHook(t, "application/json", "application/json", "triggerwordaaazzz lorem ipsum", "triggerword", []string{"file_id_1, file_id_2"}, app.TRIGGERWORDS_STARTS_WITH, false)
   341  	testCreatePostWithOutgoingHook(t, "application/json", "application/json", "triggerword lorem ipsum", "", []string{"file_id_1"}, app.TRIGGERWORDS_EXACT_MATCH, false)
   342  	testCreatePostWithOutgoingHook(t, "application/json", "application/json", "triggerwordaaazzz lorem ipsum", "", []string{"file_id_1"}, app.TRIGGERWORDS_STARTS_WITH, false)
   343  	testCreatePostWithOutgoingHook(t, "application/json", "application/json", "triggerword lorem ipsum", "triggerword", []string{"file_id_1, file_id_2"}, app.TRIGGERWORDS_EXACT_MATCH, true)
   344  	testCreatePostWithOutgoingHook(t, "application/json", "application/json", "triggerwordaaazzz lorem ipsum", "", []string{"file_id_1"}, app.TRIGGERWORDS_STARTS_WITH, true)
   345  }
   346  
   347  // hooks created before we added the ContentType field should be considered as
   348  // application/x-www-form-urlencoded
   349  func TestCreatePostWithOutgoingHook_no_content_type(t *testing.T) {
   350  	testCreatePostWithOutgoingHook(t, "", "application/x-www-form-urlencoded", "triggerword lorem ipsum", "triggerword", []string{"file_id_1"}, app.TRIGGERWORDS_EXACT_MATCH, false)
   351  	testCreatePostWithOutgoingHook(t, "", "application/x-www-form-urlencoded", "triggerwordaaazzz lorem ipsum", "triggerword", []string{"file_id_1"}, app.TRIGGERWORDS_STARTS_WITH, false)
   352  	testCreatePostWithOutgoingHook(t, "", "application/x-www-form-urlencoded", "triggerword lorem ipsum", "", []string{"file_id_1, file_id_2"}, app.TRIGGERWORDS_EXACT_MATCH, false)
   353  	testCreatePostWithOutgoingHook(t, "", "application/x-www-form-urlencoded", "triggerwordaaazzz lorem ipsum", "", []string{"file_id_1, file_id_2"}, app.TRIGGERWORDS_STARTS_WITH, false)
   354  	testCreatePostWithOutgoingHook(t, "", "application/x-www-form-urlencoded", "triggerword lorem ipsum", "triggerword", []string{"file_id_1"}, app.TRIGGERWORDS_EXACT_MATCH, true)
   355  	testCreatePostWithOutgoingHook(t, "", "application/x-www-form-urlencoded", "triggerword lorem ipsum", "", []string{"file_id_1, file_id_2"}, app.TRIGGERWORDS_EXACT_MATCH, true)
   356  }
   357  
   358  func TestCreatePostPublic(t *testing.T) {
   359  	th := Setup().InitBasic().InitSystemAdmin()
   360  	defer th.TearDown()
   361  	Client := th.Client
   362  
   363  	post := &model.Post{ChannelId: th.BasicChannel.Id, Message: "#hashtag a" + model.NewId() + "a"}
   364  
   365  	user := model.User{Email: th.GenerateTestEmail(), Nickname: "Joram Wilander", Password: "hello1", Username: GenerateTestUsername(), Roles: model.SYSTEM_USER_ROLE_ID}
   366  
   367  	ruser, resp := Client.CreateUser(&user)
   368  	CheckNoError(t, resp)
   369  
   370  	Client.Login(user.Email, user.Password)
   371  
   372  	_, resp = Client.CreatePost(post)
   373  	CheckForbiddenStatus(t, resp)
   374  
   375  	th.App.UpdateUserRoles(ruser.Id, model.SYSTEM_USER_ROLE_ID+" "+model.SYSTEM_POST_ALL_PUBLIC_ROLE_ID, false)
   376  	th.App.InvalidateAllCaches()
   377  
   378  	Client.Login(user.Email, user.Password)
   379  
   380  	_, resp = Client.CreatePost(post)
   381  	CheckNoError(t, resp)
   382  
   383  	post.ChannelId = th.BasicPrivateChannel.Id
   384  	_, resp = Client.CreatePost(post)
   385  	CheckForbiddenStatus(t, resp)
   386  
   387  	th.App.UpdateUserRoles(ruser.Id, model.SYSTEM_USER_ROLE_ID, false)
   388  	th.App.JoinUserToTeam(th.BasicTeam, ruser, "")
   389  	th.App.UpdateTeamMemberRoles(th.BasicTeam.Id, ruser.Id, model.TEAM_USER_ROLE_ID+" "+model.TEAM_POST_ALL_PUBLIC_ROLE_ID)
   390  	th.App.InvalidateAllCaches()
   391  
   392  	Client.Login(user.Email, user.Password)
   393  
   394  	post.ChannelId = th.BasicPrivateChannel.Id
   395  	_, resp = Client.CreatePost(post)
   396  	CheckForbiddenStatus(t, resp)
   397  
   398  	post.ChannelId = th.BasicChannel.Id
   399  	_, resp = Client.CreatePost(post)
   400  	CheckNoError(t, resp)
   401  }
   402  
   403  func TestCreatePostAll(t *testing.T) {
   404  	th := Setup().InitBasic().InitSystemAdmin()
   405  	defer th.TearDown()
   406  	Client := th.Client
   407  
   408  	post := &model.Post{ChannelId: th.BasicChannel.Id, Message: "#hashtag a" + model.NewId() + "a"}
   409  
   410  	user := model.User{Email: th.GenerateTestEmail(), Nickname: "Joram Wilander", Password: "hello1", Username: GenerateTestUsername(), Roles: model.SYSTEM_USER_ROLE_ID}
   411  
   412  	directChannel, _ := th.App.CreateDirectChannel(th.BasicUser.Id, th.BasicUser2.Id)
   413  
   414  	ruser, resp := Client.CreateUser(&user)
   415  	CheckNoError(t, resp)
   416  
   417  	Client.Login(user.Email, user.Password)
   418  
   419  	_, resp = Client.CreatePost(post)
   420  	CheckForbiddenStatus(t, resp)
   421  
   422  	th.App.UpdateUserRoles(ruser.Id, model.SYSTEM_USER_ROLE_ID+" "+model.SYSTEM_POST_ALL_ROLE_ID, false)
   423  	th.App.InvalidateAllCaches()
   424  
   425  	Client.Login(user.Email, user.Password)
   426  
   427  	_, resp = Client.CreatePost(post)
   428  	CheckNoError(t, resp)
   429  
   430  	post.ChannelId = th.BasicPrivateChannel.Id
   431  	_, resp = Client.CreatePost(post)
   432  	CheckNoError(t, resp)
   433  
   434  	post.ChannelId = directChannel.Id
   435  	_, resp = Client.CreatePost(post)
   436  	CheckNoError(t, resp)
   437  
   438  	th.App.UpdateUserRoles(ruser.Id, model.SYSTEM_USER_ROLE_ID, false)
   439  	th.App.JoinUserToTeam(th.BasicTeam, ruser, "")
   440  	th.App.UpdateTeamMemberRoles(th.BasicTeam.Id, ruser.Id, model.TEAM_USER_ROLE_ID+" "+model.TEAM_POST_ALL_ROLE_ID)
   441  	th.App.InvalidateAllCaches()
   442  
   443  	Client.Login(user.Email, user.Password)
   444  
   445  	post.ChannelId = th.BasicPrivateChannel.Id
   446  	_, resp = Client.CreatePost(post)
   447  	CheckNoError(t, resp)
   448  
   449  	post.ChannelId = th.BasicChannel.Id
   450  	_, resp = Client.CreatePost(post)
   451  	CheckNoError(t, resp)
   452  
   453  	post.ChannelId = directChannel.Id
   454  	_, resp = Client.CreatePost(post)
   455  	CheckForbiddenStatus(t, resp)
   456  }
   457  
   458  func TestCreatePostSendOutOfChannelMentions(t *testing.T) {
   459  	th := Setup().InitBasic().InitSystemAdmin()
   460  	defer th.TearDown()
   461  	Client := th.Client
   462  
   463  	WebSocketClient, err := th.CreateWebSocketClient()
   464  	if err != nil {
   465  		t.Fatal(err)
   466  	}
   467  	WebSocketClient.Listen()
   468  
   469  	inChannelUser := th.CreateUser()
   470  	th.LinkUserToTeam(inChannelUser, th.BasicTeam)
   471  	th.App.AddUserToChannel(inChannelUser, th.BasicChannel)
   472  
   473  	post1 := &model.Post{ChannelId: th.BasicChannel.Id, Message: "@" + inChannelUser.Username}
   474  	_, resp := Client.CreatePost(post1)
   475  	CheckNoError(t, resp)
   476  	CheckCreatedStatus(t, resp)
   477  
   478  	timeout := time.After(300 * time.Millisecond)
   479  	waiting := true
   480  	for waiting {
   481  		select {
   482  		case event := <-WebSocketClient.EventChannel:
   483  			if event.Event == model.WEBSOCKET_EVENT_EPHEMERAL_MESSAGE {
   484  				t.Fatal("should not have ephemeral message event")
   485  			}
   486  
   487  		case <-timeout:
   488  			waiting = false
   489  		}
   490  	}
   491  
   492  	outOfChannelUser := th.CreateUser()
   493  	th.LinkUserToTeam(outOfChannelUser, th.BasicTeam)
   494  
   495  	post2 := &model.Post{ChannelId: th.BasicChannel.Id, Message: "@" + outOfChannelUser.Username}
   496  	_, resp = Client.CreatePost(post2)
   497  	CheckNoError(t, resp)
   498  	CheckCreatedStatus(t, resp)
   499  
   500  	timeout = time.After(300 * time.Millisecond)
   501  	waiting = true
   502  	for waiting {
   503  		select {
   504  		case event := <-WebSocketClient.EventChannel:
   505  			if event.Event != model.WEBSOCKET_EVENT_EPHEMERAL_MESSAGE {
   506  				// Ignore any other events
   507  				continue
   508  			}
   509  
   510  			wpost := model.PostFromJson(strings.NewReader(event.Data["post"].(string)))
   511  			if acm, ok := wpost.Props[model.PROPS_ADD_CHANNEL_MEMBER].(map[string]interface{}); !ok {
   512  				t.Fatal("should have received ephemeral post with 'add_channel_member' in props")
   513  			} else {
   514  				if acm["post_id"] == nil || acm["user_ids"] == nil || acm["usernames"] == nil {
   515  					t.Fatal("should not be nil")
   516  				}
   517  			}
   518  			waiting = false
   519  		case <-timeout:
   520  			t.Fatal("timed out waiting for ephemeral message event")
   521  		}
   522  	}
   523  }
   524  
   525  func TestUpdatePost(t *testing.T) {
   526  	th := Setup().InitBasic().InitSystemAdmin()
   527  	defer th.TearDown()
   528  	Client := th.Client
   529  	channel := th.BasicChannel
   530  
   531  	th.App.SetLicense(model.NewTestLicense())
   532  
   533  	post := &model.Post{ChannelId: channel.Id, Message: "zz" + model.NewId() + "a"}
   534  	rpost, resp := Client.CreatePost(post)
   535  	CheckNoError(t, resp)
   536  
   537  	if rpost.Message != post.Message {
   538  		t.Fatal("full name didn't match")
   539  	}
   540  
   541  	if rpost.EditAt != 0 {
   542  		t.Fatal("Newly created post shouldn't have EditAt set")
   543  	}
   544  
   545  	msg := "zz" + model.NewId() + " update post"
   546  	rpost.Message = msg
   547  	rpost.UserId = ""
   548  
   549  	rupost, resp := Client.UpdatePost(rpost.Id, rpost)
   550  	CheckNoError(t, resp)
   551  
   552  	if rupost.Message != msg {
   553  		t.Fatal("failed to updates")
   554  	}
   555  	if rupost.EditAt == 0 {
   556  		t.Fatal("EditAt not updated for post")
   557  	}
   558  
   559  	msg1 := "#hashtag a" + model.NewId() + " update post again"
   560  	rpost.Message = msg1
   561  	rpost.Props[model.PROPS_ADD_CHANNEL_MEMBER] = "no good"
   562  	rrupost, resp := Client.UpdatePost(rpost.Id, rpost)
   563  	CheckNoError(t, resp)
   564  
   565  	if rrupost.Message != msg1 && rrupost.Hashtags != "#hashtag" {
   566  		t.Fatal("failed to updates")
   567  	}
   568  
   569  	if rrupost.Props[model.PROPS_ADD_CHANNEL_MEMBER] != nil {
   570  		t.Fatal("failed to sanitize Props['add_channel_member'], should be nil")
   571  	}
   572  
   573  	rpost2, err := th.App.CreatePost(&model.Post{ChannelId: channel.Id, Message: "zz" + model.NewId() + "a", Type: model.POST_JOIN_LEAVE, UserId: th.BasicUser.Id}, channel, false)
   574  	if err != nil {
   575  		t.Fatal(err)
   576  	}
   577  
   578  	up2 := &model.Post{Id: rpost2.Id, ChannelId: channel.Id, Message: "zz" + model.NewId() + " update post 2"}
   579  	_, resp = Client.UpdatePost(rpost2.Id, up2)
   580  	CheckBadRequestStatus(t, resp)
   581  
   582  	Client.Logout()
   583  	_, resp = Client.UpdatePost(rpost.Id, rpost)
   584  	CheckUnauthorizedStatus(t, resp)
   585  
   586  	th.LoginBasic2()
   587  	_, resp = Client.UpdatePost(rpost.Id, rpost)
   588  	CheckForbiddenStatus(t, resp)
   589  
   590  	Client.Logout()
   591  
   592  	th.LoginTeamAdmin()
   593  	_, resp = Client.UpdatePost(rpost.Id, rpost)
   594  	CheckForbiddenStatus(t, resp)
   595  
   596  	Client.Logout()
   597  
   598  	_, resp = th.SystemAdminClient.UpdatePost(rpost.Id, rpost)
   599  	CheckNoError(t, resp)
   600  }
   601  
   602  func TestUpdateOthersPostInDirectMessageChannel(t *testing.T) {
   603  	// This test checks that a sysadmin with the "EDIT_OTHERS_POSTS" permission can edit someone else's post in a
   604  	// channel without a team (DM/GM). This indirectly checks for the proper cascading all the way to system-wide roles
   605  	// on the user object of permissions based on a post in a channel with no team ID.
   606  	th := Setup().InitBasic().InitSystemAdmin()
   607  	defer th.TearDown()
   608  
   609  	dmChannel := th.CreateDmChannel(th.SystemAdminUser)
   610  
   611  	post := &model.Post{
   612  		Message:       "asd",
   613  		ChannelId:     dmChannel.Id,
   614  		PendingPostId: model.NewId() + ":" + fmt.Sprint(model.GetMillis()),
   615  		UserId:        th.BasicUser.Id,
   616  		CreateAt:      0,
   617  	}
   618  
   619  	post, resp := th.Client.CreatePost(post)
   620  	CheckNoError(t, resp)
   621  
   622  	post.Message = "changed"
   623  	post, resp = th.SystemAdminClient.UpdatePost(post.Id, post)
   624  	CheckNoError(t, resp)
   625  }
   626  
   627  func TestPatchPost(t *testing.T) {
   628  	th := Setup().InitBasic().InitSystemAdmin()
   629  	defer th.TearDown()
   630  	Client := th.Client
   631  	channel := th.BasicChannel
   632  
   633  	th.App.SetLicense(model.NewTestLicense())
   634  
   635  	post := &model.Post{
   636  		ChannelId:    channel.Id,
   637  		IsPinned:     true,
   638  		Message:      "#hashtag a message",
   639  		Props:        model.StringInterface{"channel_header": "old_header"},
   640  		FileIds:      model.StringArray{"file1", "file2"},
   641  		HasReactions: true,
   642  	}
   643  	post, _ = Client.CreatePost(post)
   644  
   645  	patch := &model.PostPatch{}
   646  
   647  	patch.IsPinned = model.NewBool(false)
   648  	patch.Message = model.NewString("#otherhashtag other message")
   649  	patch.Props = new(model.StringInterface)
   650  	*patch.Props = model.StringInterface{"channel_header": "new_header"}
   651  	patch.FileIds = new(model.StringArray)
   652  	*patch.FileIds = model.StringArray{"file1", "otherfile2", "otherfile3"}
   653  	patch.HasReactions = model.NewBool(false)
   654  
   655  	rpost, resp := Client.PatchPost(post.Id, patch)
   656  	CheckNoError(t, resp)
   657  
   658  	if rpost.IsPinned {
   659  		t.Fatal("IsPinned did not update properly")
   660  	}
   661  	if rpost.Message != "#otherhashtag other message" {
   662  		t.Fatal("Message did not update properly")
   663  	}
   664  	if len(rpost.Props) != 1 {
   665  		t.Fatal("Props did not update properly")
   666  	}
   667  	if !reflect.DeepEqual(rpost.Props, *patch.Props) {
   668  		t.Fatal("Props did not update properly")
   669  	}
   670  	if rpost.Hashtags != "#otherhashtag" {
   671  		t.Fatal("Message did not update properly")
   672  	}
   673  	if len(rpost.FileIds) != 3 {
   674  		t.Fatal("FileIds did not update properly")
   675  	}
   676  	if !reflect.DeepEqual(rpost.FileIds, *patch.FileIds) {
   677  		t.Fatal("FileIds did not update properly")
   678  	}
   679  	if rpost.HasReactions {
   680  		t.Fatal("HasReactions did not update properly")
   681  	}
   682  
   683  	if r, err := Client.DoApiPut("/posts/"+post.Id+"/patch", "garbage"); err == nil {
   684  		t.Fatal("should have errored")
   685  	} else {
   686  		if r.StatusCode != http.StatusBadRequest {
   687  			t.Log("actual: " + strconv.Itoa(r.StatusCode))
   688  			t.Log("expected: " + strconv.Itoa(http.StatusBadRequest))
   689  			t.Fatal("wrong status code")
   690  		}
   691  	}
   692  
   693  	_, resp = Client.PatchPost("junk", patch)
   694  	CheckBadRequestStatus(t, resp)
   695  
   696  	_, resp = Client.PatchPost(GenerateTestId(), patch)
   697  	CheckForbiddenStatus(t, resp)
   698  
   699  	Client.Logout()
   700  	_, resp = Client.PatchPost(post.Id, patch)
   701  	CheckUnauthorizedStatus(t, resp)
   702  
   703  	th.LoginBasic2()
   704  	_, resp = Client.PatchPost(post.Id, patch)
   705  	CheckForbiddenStatus(t, resp)
   706  
   707  	th.LoginTeamAdmin()
   708  	_, resp = Client.PatchPost(post.Id, patch)
   709  	CheckForbiddenStatus(t, resp)
   710  
   711  	_, resp = th.SystemAdminClient.PatchPost(post.Id, patch)
   712  	CheckNoError(t, resp)
   713  }
   714  
   715  func TestPinPost(t *testing.T) {
   716  	th := Setup().InitBasic().InitSystemAdmin()
   717  	defer th.TearDown()
   718  	Client := th.Client
   719  
   720  	post := th.BasicPost
   721  	pass, resp := Client.PinPost(post.Id)
   722  	CheckNoError(t, resp)
   723  
   724  	if !pass {
   725  		t.Fatal("should have passed")
   726  	}
   727  
   728  	if rpost, err := th.App.GetSinglePost(post.Id); err != nil && !rpost.IsPinned {
   729  		t.Fatal("failed to pin post")
   730  	}
   731  
   732  	pass, resp = Client.PinPost("junk")
   733  	CheckBadRequestStatus(t, resp)
   734  
   735  	if pass {
   736  		t.Fatal("should have failed")
   737  	}
   738  
   739  	_, resp = Client.PinPost(GenerateTestId())
   740  	CheckForbiddenStatus(t, resp)
   741  
   742  	Client.Logout()
   743  	_, resp = Client.PinPost(post.Id)
   744  	CheckUnauthorizedStatus(t, resp)
   745  
   746  	_, resp = th.SystemAdminClient.PinPost(post.Id)
   747  	CheckNoError(t, resp)
   748  }
   749  
   750  func TestUnpinPost(t *testing.T) {
   751  	th := Setup().InitBasic().InitSystemAdmin()
   752  	defer th.TearDown()
   753  	Client := th.Client
   754  
   755  	pinnedPost := th.CreatePinnedPost()
   756  	pass, resp := Client.UnpinPost(pinnedPost.Id)
   757  	CheckNoError(t, resp)
   758  
   759  	if !pass {
   760  		t.Fatal("should have passed")
   761  	}
   762  
   763  	if rpost, err := th.App.GetSinglePost(pinnedPost.Id); err != nil && rpost.IsPinned {
   764  		t.Fatal("failed to pin post")
   765  	}
   766  
   767  	pass, resp = Client.UnpinPost("junk")
   768  	CheckBadRequestStatus(t, resp)
   769  
   770  	if pass {
   771  		t.Fatal("should have failed")
   772  	}
   773  
   774  	_, resp = Client.UnpinPost(GenerateTestId())
   775  	CheckForbiddenStatus(t, resp)
   776  
   777  	Client.Logout()
   778  	_, resp = Client.UnpinPost(pinnedPost.Id)
   779  	CheckUnauthorizedStatus(t, resp)
   780  
   781  	_, resp = th.SystemAdminClient.UnpinPost(pinnedPost.Id)
   782  	CheckNoError(t, resp)
   783  }
   784  
   785  func TestGetPostsForChannel(t *testing.T) {
   786  	th := Setup().InitBasic().InitSystemAdmin()
   787  	defer th.TearDown()
   788  	Client := th.Client
   789  
   790  	post1 := th.CreatePost()
   791  	post2 := th.CreatePost()
   792  	post3 := &model.Post{ChannelId: th.BasicChannel.Id, Message: "zz" + model.NewId() + "a", RootId: post1.Id}
   793  	post3, _ = Client.CreatePost(post3)
   794  
   795  	time.Sleep(300 * time.Millisecond)
   796  	since := model.GetMillis()
   797  	time.Sleep(300 * time.Millisecond)
   798  
   799  	post4 := th.CreatePost()
   800  
   801  	posts, resp := Client.GetPostsForChannel(th.BasicChannel.Id, 0, 60, "")
   802  	CheckNoError(t, resp)
   803  
   804  	if posts.Order[0] != post4.Id {
   805  		t.Fatal("wrong order")
   806  	}
   807  
   808  	if posts.Order[1] != post3.Id {
   809  		t.Fatal("wrong order")
   810  	}
   811  
   812  	if posts.Order[2] != post2.Id {
   813  		t.Fatal("wrong order")
   814  	}
   815  
   816  	if posts.Order[3] != post1.Id {
   817  		t.Fatal("wrong order")
   818  	}
   819  
   820  	posts, resp = Client.GetPostsForChannel(th.BasicChannel.Id, 0, 3, resp.Etag)
   821  	CheckEtag(t, posts, resp)
   822  
   823  	posts, resp = Client.GetPostsForChannel(th.BasicChannel.Id, 0, 3, "")
   824  	CheckNoError(t, resp)
   825  
   826  	if len(posts.Order) != 3 {
   827  		t.Fatal("wrong number returned")
   828  	}
   829  
   830  	if _, ok := posts.Posts[post3.Id]; !ok {
   831  		t.Fatal("missing comment")
   832  	}
   833  
   834  	if _, ok := posts.Posts[post1.Id]; !ok {
   835  		t.Fatal("missing root post")
   836  	}
   837  
   838  	posts, resp = Client.GetPostsForChannel(th.BasicChannel.Id, 1, 1, "")
   839  	CheckNoError(t, resp)
   840  
   841  	if posts.Order[0] != post3.Id {
   842  		t.Fatal("wrong order")
   843  	}
   844  
   845  	posts, resp = Client.GetPostsForChannel(th.BasicChannel.Id, 10000, 10000, "")
   846  	CheckNoError(t, resp)
   847  
   848  	if len(posts.Order) != 0 {
   849  		t.Fatal("should be no posts")
   850  	}
   851  
   852  	post5 := th.CreatePost()
   853  
   854  	posts, resp = Client.GetPostsSince(th.BasicChannel.Id, since)
   855  	CheckNoError(t, resp)
   856  
   857  	if len(posts.Posts) != 2 {
   858  		t.Log(posts.Posts)
   859  		t.Fatal("should return 2 posts")
   860  	}
   861  
   862  	found := make([]bool, 2)
   863  	for _, p := range posts.Posts {
   864  		if p.CreateAt < since {
   865  			t.Fatal("bad create at for post returned")
   866  		}
   867  		if p.Id == post4.Id {
   868  			found[0] = true
   869  		} else if p.Id == post5.Id {
   870  			found[1] = true
   871  		}
   872  	}
   873  
   874  	for _, f := range found {
   875  		if !f {
   876  			t.Fatal("missing post")
   877  		}
   878  	}
   879  
   880  	_, resp = Client.GetPostsForChannel("", 0, 60, "")
   881  	CheckBadRequestStatus(t, resp)
   882  
   883  	_, resp = Client.GetPostsForChannel("junk", 0, 60, "")
   884  	CheckBadRequestStatus(t, resp)
   885  
   886  	_, resp = Client.GetPostsForChannel(model.NewId(), 0, 60, "")
   887  	CheckForbiddenStatus(t, resp)
   888  
   889  	Client.Logout()
   890  	_, resp = Client.GetPostsForChannel(model.NewId(), 0, 60, "")
   891  	CheckUnauthorizedStatus(t, resp)
   892  
   893  	_, resp = th.SystemAdminClient.GetPostsForChannel(th.BasicChannel.Id, 0, 60, "")
   894  	CheckNoError(t, resp)
   895  }
   896  
   897  func TestGetFlaggedPostsForUser(t *testing.T) {
   898  	th := Setup().InitBasic().InitSystemAdmin()
   899  	defer th.TearDown()
   900  	Client := th.Client
   901  	user := th.BasicUser
   902  	team1 := th.BasicTeam
   903  	channel1 := th.BasicChannel
   904  	post1 := th.CreatePost()
   905  	channel2 := th.CreatePublicChannel()
   906  	post2 := th.CreatePostWithClient(Client, channel2)
   907  
   908  	preference := model.Preference{
   909  		UserId:   user.Id,
   910  		Category: model.PREFERENCE_CATEGORY_FLAGGED_POST,
   911  		Name:     post1.Id,
   912  		Value:    "true",
   913  	}
   914  	Client.UpdatePreferences(user.Id, &model.Preferences{preference})
   915  	preference.Name = post2.Id
   916  	Client.UpdatePreferences(user.Id, &model.Preferences{preference})
   917  
   918  	opl := model.NewPostList()
   919  	opl.AddPost(post1)
   920  	opl.AddOrder(post1.Id)
   921  
   922  	rpl, resp := Client.GetFlaggedPostsForUserInChannel(user.Id, channel1.Id, 0, 10)
   923  	CheckNoError(t, resp)
   924  
   925  	if len(rpl.Posts) != 1 {
   926  		t.Fatal("should have returned 1 post")
   927  	}
   928  
   929  	if !reflect.DeepEqual(rpl.Posts, opl.Posts) {
   930  		t.Fatal("posts should have matched")
   931  	}
   932  
   933  	rpl, resp = Client.GetFlaggedPostsForUserInChannel(user.Id, channel1.Id, 0, 1)
   934  	CheckNoError(t, resp)
   935  
   936  	if len(rpl.Posts) != 1 {
   937  		t.Fatal("should have returned 1 post")
   938  	}
   939  
   940  	rpl, resp = Client.GetFlaggedPostsForUserInChannel(user.Id, channel1.Id, 1, 1)
   941  	CheckNoError(t, resp)
   942  
   943  	if len(rpl.Posts) != 0 {
   944  		t.Fatal("should be empty")
   945  	}
   946  
   947  	rpl, resp = Client.GetFlaggedPostsForUserInChannel(user.Id, GenerateTestId(), 0, 10)
   948  	CheckNoError(t, resp)
   949  
   950  	if len(rpl.Posts) != 0 {
   951  		t.Fatal("should be empty")
   952  	}
   953  
   954  	rpl, resp = Client.GetFlaggedPostsForUserInChannel(user.Id, "junk", 0, 10)
   955  	CheckBadRequestStatus(t, resp)
   956  
   957  	if rpl != nil {
   958  		t.Fatal("should be nil")
   959  	}
   960  
   961  	opl.AddPost(post2)
   962  	opl.AddOrder(post2.Id)
   963  
   964  	rpl, resp = Client.GetFlaggedPostsForUserInTeam(user.Id, team1.Id, 0, 10)
   965  	CheckNoError(t, resp)
   966  
   967  	if len(rpl.Posts) != 2 {
   968  		t.Fatal("should have returned 2 posts")
   969  	}
   970  
   971  	if !reflect.DeepEqual(rpl.Posts, opl.Posts) {
   972  		t.Fatal("posts should have matched")
   973  	}
   974  
   975  	rpl, resp = Client.GetFlaggedPostsForUserInTeam(user.Id, team1.Id, 0, 1)
   976  	CheckNoError(t, resp)
   977  
   978  	if len(rpl.Posts) != 1 {
   979  		t.Fatal("should have returned 1 post")
   980  	}
   981  
   982  	rpl, resp = Client.GetFlaggedPostsForUserInTeam(user.Id, team1.Id, 1, 1)
   983  	CheckNoError(t, resp)
   984  
   985  	if len(rpl.Posts) != 1 {
   986  		t.Fatal("should have returned 1 post")
   987  	}
   988  
   989  	rpl, resp = Client.GetFlaggedPostsForUserInTeam(user.Id, team1.Id, 1000, 10)
   990  	CheckNoError(t, resp)
   991  
   992  	if len(rpl.Posts) != 0 {
   993  		t.Fatal("should be empty")
   994  	}
   995  
   996  	rpl, resp = Client.GetFlaggedPostsForUserInTeam(user.Id, GenerateTestId(), 0, 10)
   997  	CheckNoError(t, resp)
   998  
   999  	if len(rpl.Posts) != 0 {
  1000  		t.Fatal("should be empty")
  1001  	}
  1002  
  1003  	rpl, resp = Client.GetFlaggedPostsForUserInTeam(user.Id, "junk", 0, 10)
  1004  	CheckBadRequestStatus(t, resp)
  1005  
  1006  	if rpl != nil {
  1007  		t.Fatal("should be nil")
  1008  	}
  1009  
  1010  	channel3 := th.CreatePrivateChannel()
  1011  	post4 := th.CreatePostWithClient(Client, channel3)
  1012  
  1013  	preference.Name = post4.Id
  1014  	Client.UpdatePreferences(user.Id, &model.Preferences{preference})
  1015  
  1016  	opl.AddPost(post4)
  1017  	opl.AddOrder(post4.Id)
  1018  
  1019  	rpl, resp = Client.GetFlaggedPostsForUser(user.Id, 0, 10)
  1020  	CheckNoError(t, resp)
  1021  
  1022  	if len(rpl.Posts) != 3 {
  1023  		t.Fatal("should have returned 3 posts")
  1024  	}
  1025  
  1026  	if !reflect.DeepEqual(rpl.Posts, opl.Posts) {
  1027  		t.Fatal("posts should have matched")
  1028  	}
  1029  
  1030  	rpl, resp = Client.GetFlaggedPostsForUser(user.Id, 0, 2)
  1031  	CheckNoError(t, resp)
  1032  
  1033  	if len(rpl.Posts) != 2 {
  1034  		t.Fatal("should have returned 2 posts")
  1035  	}
  1036  
  1037  	rpl, resp = Client.GetFlaggedPostsForUser(user.Id, 2, 2)
  1038  	CheckNoError(t, resp)
  1039  
  1040  	if len(rpl.Posts) != 1 {
  1041  		t.Fatal("should have returned 1 post")
  1042  	}
  1043  
  1044  	rpl, resp = Client.GetFlaggedPostsForUser(user.Id, 1000, 10)
  1045  	CheckNoError(t, resp)
  1046  
  1047  	if len(rpl.Posts) != 0 {
  1048  		t.Fatal("should be empty")
  1049  	}
  1050  
  1051  	_, resp = Client.GetFlaggedPostsForUser("junk", 0, 10)
  1052  	CheckBadRequestStatus(t, resp)
  1053  
  1054  	_, resp = Client.GetFlaggedPostsForUser(GenerateTestId(), 0, 10)
  1055  	CheckForbiddenStatus(t, resp)
  1056  
  1057  	Client.Logout()
  1058  
  1059  	_, resp = Client.GetFlaggedPostsForUserInChannel(user.Id, channel1.Id, 0, 10)
  1060  	CheckUnauthorizedStatus(t, resp)
  1061  
  1062  	_, resp = Client.GetFlaggedPostsForUserInTeam(user.Id, team1.Id, 0, 10)
  1063  	CheckUnauthorizedStatus(t, resp)
  1064  
  1065  	_, resp = Client.GetFlaggedPostsForUser(user.Id, 0, 10)
  1066  	CheckUnauthorizedStatus(t, resp)
  1067  
  1068  	_, resp = th.SystemAdminClient.GetFlaggedPostsForUserInChannel(user.Id, channel1.Id, 0, 10)
  1069  	CheckNoError(t, resp)
  1070  
  1071  	_, resp = th.SystemAdminClient.GetFlaggedPostsForUserInTeam(user.Id, team1.Id, 0, 10)
  1072  	CheckNoError(t, resp)
  1073  
  1074  	_, resp = th.SystemAdminClient.GetFlaggedPostsForUser(user.Id, 0, 10)
  1075  	CheckNoError(t, resp)
  1076  }
  1077  
  1078  func TestGetPostsAfterAndBefore(t *testing.T) {
  1079  	th := Setup().InitBasic()
  1080  	defer th.TearDown()
  1081  	Client := th.Client
  1082  
  1083  	post1 := th.CreatePost()
  1084  	post2 := th.CreatePost()
  1085  	post3 := th.CreatePost()
  1086  	post4 := th.CreatePost()
  1087  	post5 := th.CreatePost()
  1088  
  1089  	posts, resp := Client.GetPostsBefore(th.BasicChannel.Id, post3.Id, 0, 100, "")
  1090  	CheckNoError(t, resp)
  1091  
  1092  	found := make([]bool, 2)
  1093  	for _, p := range posts.Posts {
  1094  		if p.Id == post1.Id {
  1095  			found[0] = true
  1096  		} else if p.Id == post2.Id {
  1097  			found[1] = true
  1098  		}
  1099  
  1100  		if p.Id == post4.Id || p.Id == post5.Id {
  1101  			t.Fatal("returned posts after")
  1102  		}
  1103  	}
  1104  
  1105  	for _, f := range found {
  1106  		if !f {
  1107  			t.Fatal("missing post")
  1108  		}
  1109  	}
  1110  
  1111  	posts, resp = Client.GetPostsBefore(th.BasicChannel.Id, post3.Id, 1, 1, "")
  1112  	CheckNoError(t, resp)
  1113  
  1114  	if len(posts.Posts) != 1 {
  1115  		t.Fatal("too many posts returned")
  1116  	}
  1117  
  1118  	posts, resp = Client.GetPostsBefore(th.BasicChannel.Id, "junk", 1, 1, "")
  1119  	CheckNoError(t, resp)
  1120  
  1121  	if len(posts.Posts) != 0 {
  1122  		t.Fatal("should have no posts")
  1123  	}
  1124  
  1125  	posts, resp = Client.GetPostsAfter(th.BasicChannel.Id, post3.Id, 0, 100, "")
  1126  	CheckNoError(t, resp)
  1127  
  1128  	found = make([]bool, 2)
  1129  	for _, p := range posts.Posts {
  1130  		if p.Id == post4.Id {
  1131  			found[0] = true
  1132  		} else if p.Id == post5.Id {
  1133  			found[1] = true
  1134  		}
  1135  
  1136  		if p.Id == post1.Id || p.Id == post2.Id {
  1137  			t.Fatal("returned posts before")
  1138  		}
  1139  	}
  1140  
  1141  	for _, f := range found {
  1142  		if !f {
  1143  			t.Fatal("missing post")
  1144  		}
  1145  	}
  1146  
  1147  	posts, resp = Client.GetPostsAfter(th.BasicChannel.Id, post3.Id, 1, 1, "")
  1148  	CheckNoError(t, resp)
  1149  
  1150  	if len(posts.Posts) != 1 {
  1151  		t.Fatal("too many posts returned")
  1152  	}
  1153  
  1154  	posts, resp = Client.GetPostsAfter(th.BasicChannel.Id, "junk", 1, 1, "")
  1155  	CheckNoError(t, resp)
  1156  
  1157  	if len(posts.Posts) != 0 {
  1158  		t.Fatal("should have no posts")
  1159  	}
  1160  }
  1161  
  1162  func TestGetPost(t *testing.T) {
  1163  	th := Setup().InitBasic().InitSystemAdmin()
  1164  	defer th.TearDown()
  1165  	Client := th.Client
  1166  
  1167  	post, resp := Client.GetPost(th.BasicPost.Id, "")
  1168  	CheckNoError(t, resp)
  1169  
  1170  	if post.Id != th.BasicPost.Id {
  1171  		t.Fatal("post ids don't match")
  1172  	}
  1173  
  1174  	post, resp = Client.GetPost(th.BasicPost.Id, resp.Etag)
  1175  	CheckEtag(t, post, resp)
  1176  
  1177  	_, resp = Client.GetPost("", "")
  1178  	CheckNotFoundStatus(t, resp)
  1179  
  1180  	_, resp = Client.GetPost("junk", "")
  1181  	CheckBadRequestStatus(t, resp)
  1182  
  1183  	_, resp = Client.GetPost(model.NewId(), "")
  1184  	CheckNotFoundStatus(t, resp)
  1185  
  1186  	Client.RemoveUserFromChannel(th.BasicChannel.Id, th.BasicUser.Id)
  1187  
  1188  	// Channel is public, should be able to read post
  1189  	_, resp = Client.GetPost(th.BasicPost.Id, "")
  1190  	CheckNoError(t, resp)
  1191  
  1192  	privatePost := th.CreatePostWithClient(Client, th.BasicPrivateChannel)
  1193  
  1194  	_, resp = Client.GetPost(privatePost.Id, "")
  1195  	CheckNoError(t, resp)
  1196  
  1197  	Client.RemoveUserFromChannel(th.BasicPrivateChannel.Id, th.BasicUser.Id)
  1198  
  1199  	// Channel is private, should not be able to read post
  1200  	_, resp = Client.GetPost(privatePost.Id, "")
  1201  	CheckForbiddenStatus(t, resp)
  1202  
  1203  	Client.Logout()
  1204  	_, resp = Client.GetPost(model.NewId(), "")
  1205  	CheckUnauthorizedStatus(t, resp)
  1206  
  1207  	_, resp = th.SystemAdminClient.GetPost(th.BasicPost.Id, "")
  1208  	CheckNoError(t, resp)
  1209  }
  1210  
  1211  func TestDeletePost(t *testing.T) {
  1212  	th := Setup().InitBasic().InitSystemAdmin()
  1213  	defer th.TearDown()
  1214  	Client := th.Client
  1215  
  1216  	_, resp := Client.DeletePost("")
  1217  	CheckNotFoundStatus(t, resp)
  1218  
  1219  	_, resp = Client.DeletePost("junk")
  1220  	CheckBadRequestStatus(t, resp)
  1221  
  1222  	_, resp = Client.DeletePost(th.BasicPost.Id)
  1223  	CheckForbiddenStatus(t, resp)
  1224  
  1225  	Client.Login(th.TeamAdminUser.Email, th.TeamAdminUser.Password)
  1226  	_, resp = Client.DeletePost(th.BasicPost.Id)
  1227  	CheckNoError(t, resp)
  1228  
  1229  	post := th.CreatePost()
  1230  	user := th.CreateUser()
  1231  
  1232  	Client.Logout()
  1233  	Client.Login(user.Email, user.Password)
  1234  
  1235  	_, resp = Client.DeletePost(post.Id)
  1236  	CheckForbiddenStatus(t, resp)
  1237  
  1238  	Client.Logout()
  1239  	_, resp = Client.DeletePost(model.NewId())
  1240  	CheckUnauthorizedStatus(t, resp)
  1241  
  1242  	status, resp := th.SystemAdminClient.DeletePost(post.Id)
  1243  	if !status {
  1244  		t.Fatal("post should return status OK")
  1245  	}
  1246  	CheckNoError(t, resp)
  1247  }
  1248  
  1249  func TestGetPostThread(t *testing.T) {
  1250  	th := Setup().InitBasic().InitSystemAdmin()
  1251  	defer th.TearDown()
  1252  	Client := th.Client
  1253  
  1254  	post := &model.Post{ChannelId: th.BasicChannel.Id, Message: "zz" + model.NewId() + "a", RootId: th.BasicPost.Id}
  1255  	post, _ = Client.CreatePost(post)
  1256  
  1257  	list, resp := Client.GetPostThread(th.BasicPost.Id, "")
  1258  	CheckNoError(t, resp)
  1259  
  1260  	var list2 *model.PostList
  1261  	list2, resp = Client.GetPostThread(th.BasicPost.Id, resp.Etag)
  1262  	CheckEtag(t, list2, resp)
  1263  
  1264  	if list.Order[0] != th.BasicPost.Id {
  1265  		t.Fatal("wrong order")
  1266  	}
  1267  
  1268  	if _, ok := list.Posts[th.BasicPost.Id]; !ok {
  1269  		t.Fatal("should have had post")
  1270  	}
  1271  
  1272  	if _, ok := list.Posts[post.Id]; !ok {
  1273  		t.Fatal("should have had post")
  1274  	}
  1275  
  1276  	_, resp = Client.GetPostThread("junk", "")
  1277  	CheckBadRequestStatus(t, resp)
  1278  
  1279  	_, resp = Client.GetPostThread(model.NewId(), "")
  1280  	CheckNotFoundStatus(t, resp)
  1281  
  1282  	Client.RemoveUserFromChannel(th.BasicChannel.Id, th.BasicUser.Id)
  1283  
  1284  	// Channel is public, should be able to read post
  1285  	_, resp = Client.GetPostThread(th.BasicPost.Id, "")
  1286  	CheckNoError(t, resp)
  1287  
  1288  	privatePost := th.CreatePostWithClient(Client, th.BasicPrivateChannel)
  1289  
  1290  	_, resp = Client.GetPostThread(privatePost.Id, "")
  1291  	CheckNoError(t, resp)
  1292  
  1293  	Client.RemoveUserFromChannel(th.BasicPrivateChannel.Id, th.BasicUser.Id)
  1294  
  1295  	// Channel is private, should not be able to read post
  1296  	_, resp = Client.GetPostThread(privatePost.Id, "")
  1297  	CheckForbiddenStatus(t, resp)
  1298  
  1299  	Client.Logout()
  1300  	_, resp = Client.GetPostThread(model.NewId(), "")
  1301  	CheckUnauthorizedStatus(t, resp)
  1302  
  1303  	_, resp = th.SystemAdminClient.GetPostThread(th.BasicPost.Id, "")
  1304  	CheckNoError(t, resp)
  1305  }
  1306  
  1307  func TestSearchPosts(t *testing.T) {
  1308  	th := Setup().InitBasic()
  1309  	defer th.TearDown()
  1310  	experimentalViewArchivedChannels := *th.App.Config().TeamSettings.ExperimentalViewArchivedChannels
  1311  	defer func() {
  1312  		th.App.UpdateConfig(func(cfg *model.Config) {
  1313  			cfg.TeamSettings.ExperimentalViewArchivedChannels = &experimentalViewArchivedChannels
  1314  		})
  1315  	}()
  1316  	th.App.UpdateConfig(func(cfg *model.Config) {
  1317  		*cfg.TeamSettings.ExperimentalViewArchivedChannels = true
  1318  	})
  1319  
  1320  	th.LoginBasic()
  1321  	Client := th.Client
  1322  
  1323  	message := "search for post1"
  1324  	_ = th.CreateMessagePost(message)
  1325  
  1326  	message = "search for post2"
  1327  	post2 := th.CreateMessagePost(message)
  1328  
  1329  	message = "#hashtag search for post3"
  1330  	post3 := th.CreateMessagePost(message)
  1331  
  1332  	message = "hashtag for post4"
  1333  	_ = th.CreateMessagePost(message)
  1334  
  1335  	archivedChannel := th.CreatePublicChannel()
  1336  	_ = th.CreateMessagePostWithClient(th.Client, archivedChannel, "#hashtag for post3")
  1337  	th.Client.DeleteChannel(archivedChannel.Id)
  1338  
  1339  	terms := "search"
  1340  	isOrSearch := false
  1341  	timezoneOffset := 5
  1342  	searchParams := model.SearchParameter{
  1343  		Terms:          &terms,
  1344  		IsOrSearch:     &isOrSearch,
  1345  		TimeZoneOffset: &timezoneOffset,
  1346  	}
  1347  	posts, resp := Client.SearchPostsWithParams(th.BasicTeam.Id, &searchParams)
  1348  	CheckNoError(t, resp)
  1349  	if len(posts.Order) != 3 {
  1350  		t.Fatal("wrong search")
  1351  	}
  1352  
  1353  	terms = "search"
  1354  	page := 0
  1355  	perPage := 2
  1356  	searchParams = model.SearchParameter{
  1357  		Terms:          &terms,
  1358  		IsOrSearch:     &isOrSearch,
  1359  		TimeZoneOffset: &timezoneOffset,
  1360  		Page:           &page,
  1361  		PerPage:        &perPage,
  1362  	}
  1363  	posts2, resp := Client.SearchPostsWithParams(th.BasicTeam.Id, &searchParams)
  1364  	CheckNoError(t, resp)
  1365  	if len(posts2.Order) != 3 { // We don't support paging for DB search yet, modify this when we do.
  1366  		t.Fatal("Wrong number of posts", len(posts2.Order))
  1367  	}
  1368  	assert.Equal(t, posts.Order[0], posts2.Order[0])
  1369  	assert.Equal(t, posts.Order[1], posts2.Order[1])
  1370  
  1371  	page = 1
  1372  	searchParams = model.SearchParameter{
  1373  		Terms:          &terms,
  1374  		IsOrSearch:     &isOrSearch,
  1375  		TimeZoneOffset: &timezoneOffset,
  1376  		Page:           &page,
  1377  		PerPage:        &perPage,
  1378  	}
  1379  	posts2, resp = Client.SearchPostsWithParams(th.BasicTeam.Id, &searchParams)
  1380  	CheckNoError(t, resp)
  1381  	if len(posts2.Order) != 0 { // We don't support paging for DB search yet, modify this when we do.
  1382  		t.Fatal("Wrong number of posts", len(posts2.Order))
  1383  	}
  1384  
  1385  	posts, resp = Client.SearchPosts(th.BasicTeam.Id, "search", false)
  1386  	CheckNoError(t, resp)
  1387  	if len(posts.Order) != 3 {
  1388  		t.Fatal("wrong search")
  1389  	}
  1390  
  1391  	posts, resp = Client.SearchPosts(th.BasicTeam.Id, "post2", false)
  1392  	CheckNoError(t, resp)
  1393  	if len(posts.Order) != 1 && posts.Order[0] == post2.Id {
  1394  		t.Fatal("wrong search")
  1395  	}
  1396  
  1397  	posts, resp = Client.SearchPosts(th.BasicTeam.Id, "#hashtag", false)
  1398  	CheckNoError(t, resp)
  1399  	if len(posts.Order) != 1 && posts.Order[0] == post3.Id {
  1400  		t.Fatal("wrong search")
  1401  	}
  1402  
  1403  	terms = "#hashtag"
  1404  	includeDeletedChannels := true
  1405  	searchParams = model.SearchParameter{
  1406  		Terms:                  &terms,
  1407  		IsOrSearch:             &isOrSearch,
  1408  		TimeZoneOffset:         &timezoneOffset,
  1409  		IncludeDeletedChannels: &includeDeletedChannels,
  1410  	}
  1411  	posts, resp = Client.SearchPostsWithParams(th.BasicTeam.Id, &searchParams)
  1412  	CheckNoError(t, resp)
  1413  	if len(posts.Order) != 2 {
  1414  		t.Fatal("wrong search")
  1415  	}
  1416  
  1417  	th.App.UpdateConfig(func(cfg *model.Config) {
  1418  		*cfg.TeamSettings.ExperimentalViewArchivedChannels = false
  1419  	})
  1420  
  1421  	posts, resp = Client.SearchPostsWithParams(th.BasicTeam.Id, &searchParams)
  1422  	CheckNoError(t, resp)
  1423  	if len(posts.Order) != 1 {
  1424  		t.Fatal("wrong search")
  1425  	}
  1426  
  1427  	if posts, _ = Client.SearchPosts(th.BasicTeam.Id, "*", false); len(posts.Order) != 0 {
  1428  		t.Fatal("searching for just * shouldn't return any results")
  1429  	}
  1430  
  1431  	posts, resp = Client.SearchPosts(th.BasicTeam.Id, "post1 post2", true)
  1432  	CheckNoError(t, resp)
  1433  
  1434  	if len(posts.Order) != 2 {
  1435  		t.Fatal("wrong search results")
  1436  	}
  1437  
  1438  	_, resp = Client.SearchPosts("junk", "#sgtitlereview", false)
  1439  	CheckBadRequestStatus(t, resp)
  1440  
  1441  	_, resp = Client.SearchPosts(model.NewId(), "#sgtitlereview", false)
  1442  	CheckForbiddenStatus(t, resp)
  1443  
  1444  	_, resp = Client.SearchPosts(th.BasicTeam.Id, "", false)
  1445  	CheckBadRequestStatus(t, resp)
  1446  
  1447  	Client.Logout()
  1448  	_, resp = Client.SearchPosts(th.BasicTeam.Id, "#sgtitlereview", false)
  1449  	CheckUnauthorizedStatus(t, resp)
  1450  }
  1451  
  1452  func TestSearchHashtagPosts(t *testing.T) {
  1453  	th := Setup().InitBasic()
  1454  	defer th.TearDown()
  1455  	th.LoginBasic()
  1456  	Client := th.Client
  1457  
  1458  	message := "#sgtitlereview with space"
  1459  	assert.NotNil(t, th.CreateMessagePost(message))
  1460  
  1461  	message = "#sgtitlereview\n with return"
  1462  	assert.NotNil(t, th.CreateMessagePost(message))
  1463  
  1464  	message = "no hashtag"
  1465  	assert.NotNil(t, th.CreateMessagePost(message))
  1466  
  1467  	posts, resp := Client.SearchPosts(th.BasicTeam.Id, "#sgtitlereview", false)
  1468  	CheckNoError(t, resp)
  1469  	if len(posts.Order) != 2 {
  1470  		t.Fatal("wrong search results")
  1471  	}
  1472  
  1473  	Client.Logout()
  1474  	_, resp = Client.SearchPosts(th.BasicTeam.Id, "#sgtitlereview", false)
  1475  	CheckUnauthorizedStatus(t, resp)
  1476  }
  1477  
  1478  func TestSearchPostsInChannel(t *testing.T) {
  1479  	th := Setup().InitBasic()
  1480  	defer th.TearDown()
  1481  	th.LoginBasic()
  1482  	Client := th.Client
  1483  
  1484  	channel := th.CreatePublicChannel()
  1485  
  1486  	message := "sgtitlereview with space"
  1487  	_ = th.CreateMessagePost(message)
  1488  
  1489  	message = "sgtitlereview\n with return"
  1490  	_ = th.CreateMessagePostWithClient(Client, th.BasicChannel2, message)
  1491  
  1492  	message = "other message with no return"
  1493  	_ = th.CreateMessagePostWithClient(Client, th.BasicChannel2, message)
  1494  
  1495  	message = "other message with no return"
  1496  	_ = th.CreateMessagePostWithClient(Client, channel, message)
  1497  
  1498  	if posts, _ := Client.SearchPosts(th.BasicTeam.Id, "channel:", false); len(posts.Order) != 0 {
  1499  		t.Fatalf("wrong number of posts returned %v", len(posts.Order))
  1500  	}
  1501  
  1502  	if posts, _ := Client.SearchPosts(th.BasicTeam.Id, "in:", false); len(posts.Order) != 0 {
  1503  		t.Fatalf("wrong number of posts returned %v", len(posts.Order))
  1504  	}
  1505  
  1506  	if posts, _ := Client.SearchPosts(th.BasicTeam.Id, "channel:"+th.BasicChannel.Name, false); len(posts.Order) != 2 {
  1507  		t.Fatalf("wrong number of posts returned %v", len(posts.Order))
  1508  	}
  1509  
  1510  	if posts, _ := Client.SearchPosts(th.BasicTeam.Id, "in:"+th.BasicChannel2.Name, false); len(posts.Order) != 2 {
  1511  		t.Fatalf("wrong number of posts returned %v", len(posts.Order))
  1512  	}
  1513  
  1514  	if posts, _ := Client.SearchPosts(th.BasicTeam.Id, "channel:"+th.BasicChannel2.Name, false); len(posts.Order) != 2 {
  1515  		t.Fatalf("wrong number of posts returned %v", len(posts.Order))
  1516  	}
  1517  
  1518  	if posts, _ := Client.SearchPosts(th.BasicTeam.Id, "ChAnNeL:"+th.BasicChannel2.Name, false); len(posts.Order) != 2 {
  1519  		t.Fatalf("wrong number of posts returned %v", len(posts.Order))
  1520  	}
  1521  
  1522  	if posts, _ := Client.SearchPosts(th.BasicTeam.Id, "sgtitlereview", false); len(posts.Order) != 2 {
  1523  		t.Fatalf("wrong number of posts returned %v", len(posts.Order))
  1524  	}
  1525  
  1526  	if posts, _ := Client.SearchPosts(th.BasicTeam.Id, "sgtitlereview channel:"+th.BasicChannel.Name, false); len(posts.Order) != 1 {
  1527  		t.Fatalf("wrong number of posts returned %v", len(posts.Order))
  1528  	}
  1529  
  1530  	if posts, _ := Client.SearchPosts(th.BasicTeam.Id, "sgtitlereview in: "+th.BasicChannel2.Name, false); len(posts.Order) != 1 {
  1531  		t.Fatalf("wrong number of posts returned %v", len(posts.Order))
  1532  	}
  1533  
  1534  	if posts, _ := Client.SearchPosts(th.BasicTeam.Id, "sgtitlereview channel: "+th.BasicChannel2.Name, false); len(posts.Order) != 1 {
  1535  		t.Fatalf("wrong number of posts returned %v", len(posts.Order))
  1536  	}
  1537  
  1538  	if posts, _ := Client.SearchPosts(th.BasicTeam.Id, "channel: "+th.BasicChannel2.Name+" channel: "+channel.Name, false); len(posts.Order) != 3 {
  1539  		t.Fatalf("wrong number of posts returned %v", len(posts.Order))
  1540  	}
  1541  
  1542  }
  1543  
  1544  func TestSearchPostsFromUser(t *testing.T) {
  1545  	th := Setup().InitBasic()
  1546  	defer th.TearDown()
  1547  	Client := th.Client
  1548  
  1549  	th.LoginTeamAdmin()
  1550  	user := th.CreateUser()
  1551  	th.LinkUserToTeam(user, th.BasicTeam)
  1552  	th.App.AddUserToChannel(user, th.BasicChannel)
  1553  	th.App.AddUserToChannel(user, th.BasicChannel2)
  1554  
  1555  	message := "sgtitlereview with space"
  1556  	_ = th.CreateMessagePost(message)
  1557  
  1558  	Client.Logout()
  1559  	th.LoginBasic2()
  1560  
  1561  	message = "sgtitlereview\n with return"
  1562  	_ = th.CreateMessagePostWithClient(Client, th.BasicChannel2, message)
  1563  
  1564  	if posts, _ := Client.SearchPosts(th.BasicTeam.Id, "from: "+th.TeamAdminUser.Username, false); len(posts.Order) != 2 {
  1565  		t.Fatalf("wrong number of posts returned %v", len(posts.Order))
  1566  	}
  1567  
  1568  	if posts, _ := Client.SearchPosts(th.BasicTeam.Id, "from: "+th.BasicUser2.Username, false); len(posts.Order) != 1 {
  1569  		t.Fatalf("wrong number of posts returned %v", len(posts.Order))
  1570  	}
  1571  
  1572  	if posts, _ := Client.SearchPosts(th.BasicTeam.Id, "from: "+th.BasicUser2.Username+" sgtitlereview", false); len(posts.Order) != 1 {
  1573  		t.Fatalf("wrong number of posts returned %v", len(posts.Order))
  1574  	}
  1575  
  1576  	message = "hullo"
  1577  	_ = th.CreateMessagePost(message)
  1578  
  1579  	if posts, _ := Client.SearchPosts(th.BasicTeam.Id, "from: "+th.BasicUser2.Username+" in:"+th.BasicChannel.Name, false); len(posts.Order) != 1 {
  1580  		t.Fatalf("wrong number of posts returned %v", len(posts.Order))
  1581  	}
  1582  
  1583  	Client.Login(user.Email, user.Password)
  1584  
  1585  	// wait for the join/leave messages to be created for user3 since they're done asynchronously
  1586  	time.Sleep(100 * time.Millisecond)
  1587  
  1588  	if posts, _ := Client.SearchPosts(th.BasicTeam.Id, "from: "+th.BasicUser2.Username, false); len(posts.Order) != 2 {
  1589  		t.Fatalf("wrong number of posts returned %v", len(posts.Order))
  1590  	}
  1591  
  1592  	if posts, _ := Client.SearchPosts(th.BasicTeam.Id, "from: "+th.BasicUser2.Username+" from: "+user.Username, false); len(posts.Order) != 2 {
  1593  		t.Fatalf("wrong number of posts returned %v", len(posts.Order))
  1594  	}
  1595  
  1596  	if posts, _ := Client.SearchPosts(th.BasicTeam.Id, "from: "+th.BasicUser2.Username+" from: "+user.Username+" in:"+th.BasicChannel2.Name, false); len(posts.Order) != 1 {
  1597  		t.Fatalf("wrong number of posts returned %v", len(posts.Order))
  1598  	}
  1599  
  1600  	message = "coconut"
  1601  	_ = th.CreateMessagePostWithClient(Client, th.BasicChannel2, message)
  1602  
  1603  	if posts, _ := Client.SearchPosts(th.BasicTeam.Id, "from: "+th.BasicUser2.Username+" from: "+user.Username+" in:"+th.BasicChannel2.Name+" coconut", false); len(posts.Order) != 1 {
  1604  		t.Fatalf("wrong number of posts returned %v", len(posts.Order))
  1605  	}
  1606  }
  1607  
  1608  func TestSearchPostsWithDateFlags(t *testing.T) {
  1609  	th := Setup().InitBasic()
  1610  	defer th.TearDown()
  1611  	th.LoginBasic()
  1612  	Client := th.Client
  1613  
  1614  	message := "sgtitlereview\n with return"
  1615  	createDate := time.Date(2018, 8, 1, 5, 0, 0, 0, time.UTC)
  1616  	_ = th.CreateMessagePostNoClient(th.BasicChannel, message, utils.MillisFromTime(createDate))
  1617  
  1618  	message = "other message with no return"
  1619  	createDate = time.Date(2018, 8, 2, 5, 0, 0, 0, time.UTC)
  1620  	_ = th.CreateMessagePostNoClient(th.BasicChannel, message, utils.MillisFromTime(createDate))
  1621  
  1622  	message = "other message with no return"
  1623  	createDate = time.Date(2018, 8, 3, 5, 0, 0, 0, time.UTC)
  1624  	_ = th.CreateMessagePostNoClient(th.BasicChannel, message, utils.MillisFromTime(createDate))
  1625  
  1626  	posts, _ := Client.SearchPosts(th.BasicTeam.Id, "return", false)
  1627  	if len(posts.Order) != 3 {
  1628  		t.Fatalf("wrong number of posts returned %v", len(posts.Order))
  1629  	}
  1630  
  1631  	posts, _ = Client.SearchPosts(th.BasicTeam.Id, "on:", false)
  1632  	if len(posts.Order) != 0 {
  1633  		t.Fatalf("wrong number of posts returned %v", len(posts.Order))
  1634  	}
  1635  
  1636  	posts, _ = Client.SearchPosts(th.BasicTeam.Id, "after:", false)
  1637  	if len(posts.Order) != 0 {
  1638  		t.Fatalf("wrong number of posts returned %v", len(posts.Order))
  1639  	}
  1640  
  1641  	posts, _ = Client.SearchPosts(th.BasicTeam.Id, "before:", false)
  1642  	if len(posts.Order) != 0 {
  1643  		t.Fatalf("wrong number of posts returned %v", len(posts.Order))
  1644  	}
  1645  
  1646  	posts, _ = Client.SearchPosts(th.BasicTeam.Id, "on:2018-08-01", false)
  1647  	if len(posts.Order) != 1 {
  1648  		t.Fatalf("wrong number of posts returned %v", len(posts.Order))
  1649  	}
  1650  
  1651  	posts, _ = Client.SearchPosts(th.BasicTeam.Id, "after:2018-08-01", false)
  1652  	resultCount := 0
  1653  	for _, post := range posts.Posts {
  1654  		if post.UserId == th.BasicUser.Id {
  1655  			resultCount = resultCount + 1
  1656  		}
  1657  	}
  1658  	if resultCount != 2 {
  1659  		t.Fatalf("wrong number of posts returned %v", len(posts.Order))
  1660  	}
  1661  
  1662  	posts, _ = Client.SearchPosts(th.BasicTeam.Id, "before:2018-08-02", false)
  1663  	if len(posts.Order) != 1 {
  1664  		t.Fatalf("wrong number of posts returned %v", len(posts.Order))
  1665  	}
  1666  
  1667  	posts, _ = Client.SearchPosts(th.BasicTeam.Id, "before:2018-08-03 after:2018-08-02", false)
  1668  	if len(posts.Order) != 0 {
  1669  		t.Fatalf("wrong number of posts returned %v", len(posts.Order))
  1670  	}
  1671  
  1672  	posts, _ = Client.SearchPosts(th.BasicTeam.Id, "before:2018-08-03 after:2018-08-01", false)
  1673  	if len(posts.Order) != 1 {
  1674  		t.Fatalf("wrong number of posts returned %v", len(posts.Order))
  1675  	}
  1676  }
  1677  
  1678  func TestGetFileInfosForPost(t *testing.T) {
  1679  	th := Setup().InitBasic().InitSystemAdmin()
  1680  	defer th.TearDown()
  1681  	Client := th.Client
  1682  
  1683  	fileIds := make([]string, 3)
  1684  	if data, err := readTestFile("test.png"); err != nil {
  1685  		t.Fatal(err)
  1686  	} else {
  1687  		for i := 0; i < 3; i++ {
  1688  			fileResp, _ := Client.UploadFile(data, th.BasicChannel.Id, "test.png")
  1689  			fileIds[i] = fileResp.FileInfos[0].Id
  1690  		}
  1691  	}
  1692  
  1693  	post := &model.Post{ChannelId: th.BasicChannel.Id, Message: "zz" + model.NewId() + "a", FileIds: fileIds}
  1694  	post, _ = Client.CreatePost(post)
  1695  
  1696  	infos, resp := Client.GetFileInfosForPost(post.Id, "")
  1697  	CheckNoError(t, resp)
  1698  
  1699  	if len(infos) != 3 {
  1700  		t.Fatal("missing file infos")
  1701  	}
  1702  
  1703  	found := false
  1704  	for _, info := range infos {
  1705  		if info.Id == fileIds[0] {
  1706  			found = true
  1707  		}
  1708  	}
  1709  
  1710  	if !found {
  1711  		t.Fatal("missing file info")
  1712  	}
  1713  
  1714  	infos, resp = Client.GetFileInfosForPost(post.Id, resp.Etag)
  1715  	CheckEtag(t, infos, resp)
  1716  
  1717  	infos, resp = Client.GetFileInfosForPost(th.BasicPost.Id, "")
  1718  	CheckNoError(t, resp)
  1719  
  1720  	if len(infos) != 0 {
  1721  		t.Fatal("should have no file infos")
  1722  	}
  1723  
  1724  	_, resp = Client.GetFileInfosForPost("junk", "")
  1725  	CheckBadRequestStatus(t, resp)
  1726  
  1727  	_, resp = Client.GetFileInfosForPost(model.NewId(), "")
  1728  	CheckForbiddenStatus(t, resp)
  1729  
  1730  	Client.Logout()
  1731  	_, resp = Client.GetFileInfosForPost(model.NewId(), "")
  1732  	CheckUnauthorizedStatus(t, resp)
  1733  
  1734  	_, resp = th.SystemAdminClient.GetFileInfosForPost(th.BasicPost.Id, "")
  1735  	CheckNoError(t, resp)
  1736  }