github.com/gigforks/mattermost-server@v4.9.1-0.20180619094218-800d97fa55d0+incompatible/app/notification_test.go (about)

     1  // Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
     2  // See License.txt for license information.
     3  
     4  package app
     5  
     6  import (
     7  	"strings"
     8  	"testing"
     9  
    10  	"github.com/stretchr/testify/assert"
    11  
    12  	"github.com/mattermost/mattermost-server/model"
    13  	"github.com/mattermost/mattermost-server/utils"
    14  )
    15  
    16  func TestSendNotifications(t *testing.T) {
    17  	th := Setup().InitBasic()
    18  	defer th.TearDown()
    19  
    20  	th.App.AddUserToChannel(th.BasicUser2, th.BasicChannel)
    21  
    22  	post1, err := th.App.CreatePostMissingChannel(&model.Post{
    23  		UserId:    th.BasicUser.Id,
    24  		ChannelId: th.BasicChannel.Id,
    25  		Message:   "@" + th.BasicUser2.Username,
    26  		Type:      model.POST_ADD_TO_CHANNEL,
    27  		Props:     map[string]interface{}{model.POST_PROPS_ADDED_USER_ID: "junk"},
    28  	}, true)
    29  
    30  	if err != nil {
    31  		t.Fatal(err)
    32  	}
    33  
    34  	mentions, err := th.App.SendNotifications(post1, th.BasicTeam, th.BasicChannel, th.BasicUser, nil)
    35  	if err != nil {
    36  		t.Fatal(err)
    37  	} else if mentions == nil {
    38  		t.Log(mentions)
    39  		t.Fatal("user should have been mentioned")
    40  	} else if !utils.StringInSlice(th.BasicUser2.Id, mentions) {
    41  		t.Log(mentions)
    42  		t.Fatal("user should have been mentioned")
    43  	}
    44  
    45  	dm, err := th.App.CreateDirectChannel(th.BasicUser.Id, th.BasicUser2.Id)
    46  	if err != nil {
    47  		t.Fatal(err)
    48  	}
    49  
    50  	post2, err := th.App.CreatePostMissingChannel(&model.Post{
    51  		UserId:    th.BasicUser.Id,
    52  		ChannelId: dm.Id,
    53  		Message:   "dm message",
    54  	}, true)
    55  
    56  	if err != nil {
    57  		t.Fatal(err)
    58  	}
    59  
    60  	_, err = th.App.SendNotifications(post2, th.BasicTeam, dm, th.BasicUser, nil)
    61  	if err != nil {
    62  		t.Fatal(err)
    63  	}
    64  
    65  	th.App.UpdateActive(th.BasicUser2, false)
    66  	th.App.InvalidateAllCaches()
    67  
    68  	post3, err := th.App.CreatePostMissingChannel(&model.Post{
    69  		UserId:    th.BasicUser.Id,
    70  		ChannelId: dm.Id,
    71  		Message:   "dm message",
    72  	}, true)
    73  
    74  	if err != nil {
    75  		t.Fatal(err)
    76  	}
    77  
    78  	_, err = th.App.SendNotifications(post3, th.BasicTeam, dm, th.BasicUser, nil)
    79  	if err != nil {
    80  		t.Fatal(err)
    81  	}
    82  }
    83  
    84  func TestGetExplicitMentions(t *testing.T) {
    85  	id1 := model.NewId()
    86  	id2 := model.NewId()
    87  	id3 := model.NewId()
    88  
    89  	for name, tc := range map[string]struct {
    90  		Message  string
    91  		Keywords map[string][]string
    92  		Expected *ExplicitMentions
    93  	}{
    94  		"Nobody": {
    95  			Message:  "this is a message",
    96  			Keywords: map[string][]string{},
    97  			Expected: &ExplicitMentions{},
    98  		},
    99  		"NonexistentUser": {
   100  			Message: "this is a message for @user",
   101  			Expected: &ExplicitMentions{
   102  				OtherPotentialMentions: []string{"user"},
   103  			},
   104  		},
   105  		"OnePerson": {
   106  			Message:  "this is a message for @user",
   107  			Keywords: map[string][]string{"@user": {id1}},
   108  			Expected: &ExplicitMentions{
   109  				MentionedUserIds: map[string]bool{
   110  					id1: true,
   111  				},
   112  			},
   113  		},
   114  		"OnePersonWithPeriodAtEndOfUsername": {
   115  			Message:  "this is a message for @user.name.",
   116  			Keywords: map[string][]string{"@user.name.": {id1}},
   117  			Expected: &ExplicitMentions{
   118  				MentionedUserIds: map[string]bool{
   119  					id1: true,
   120  				},
   121  			},
   122  		},
   123  		"OnePersonWithPeriodAtEndOfUsernameButNotSimilarName": {
   124  			Message:  "this is a message for @user.name.",
   125  			Keywords: map[string][]string{"@user.name.": {id1}, "@user.name": {id2}},
   126  			Expected: &ExplicitMentions{
   127  				MentionedUserIds: map[string]bool{
   128  					id1: true,
   129  				},
   130  			},
   131  		},
   132  		"OnePersonAtEndOfSentence": {
   133  			Message:  "this is a message for @user.",
   134  			Keywords: map[string][]string{"@user": {id1}},
   135  			Expected: &ExplicitMentions{
   136  				MentionedUserIds: map[string]bool{
   137  					id1: true,
   138  				},
   139  			},
   140  		},
   141  		"OnePersonWithoutAtMention": {
   142  			Message:  "this is a message for @user",
   143  			Keywords: map[string][]string{"this": {id1}},
   144  			Expected: &ExplicitMentions{
   145  				MentionedUserIds: map[string]bool{
   146  					id1: true,
   147  				},
   148  				OtherPotentialMentions: []string{"user"},
   149  			},
   150  		},
   151  		"MultiplePeopleWithOneWord": {
   152  			Message:  "this is a message for @user",
   153  			Keywords: map[string][]string{"@user": {id1, id2}},
   154  			Expected: &ExplicitMentions{
   155  				MentionedUserIds: map[string]bool{
   156  					id1: true,
   157  					id2: true,
   158  				},
   159  			},
   160  		},
   161  		"OneOfMultiplePeople": {
   162  			Message:  "this is a message for @user",
   163  			Keywords: map[string][]string{"@user": {id1}, "@mention": {id2}},
   164  			Expected: &ExplicitMentions{
   165  				MentionedUserIds: map[string]bool{
   166  					id1: true,
   167  				},
   168  			},
   169  		},
   170  		"MultiplePeopleWithMultipleWords": {
   171  			Message:  "this is an @mention for @user",
   172  			Keywords: map[string][]string{"@user": {id1}, "@mention": {id2}},
   173  			Expected: &ExplicitMentions{
   174  				MentionedUserIds: map[string]bool{
   175  					id1: true,
   176  					id2: true,
   177  				},
   178  			},
   179  		},
   180  		"Channel": {
   181  			Message:  "this is an message for @channel",
   182  			Keywords: map[string][]string{"@channel": {id1, id2}},
   183  			Expected: &ExplicitMentions{
   184  				MentionedUserIds: map[string]bool{
   185  					id1: true,
   186  					id2: true,
   187  				},
   188  				ChannelMentioned: true,
   189  			},
   190  		},
   191  		"CapitalizedChannel": {
   192  			Message:  "this is an message for @cHaNNeL",
   193  			Keywords: map[string][]string{"@channel": {id1, id2}},
   194  			Expected: &ExplicitMentions{
   195  				MentionedUserIds: map[string]bool{
   196  					id1: true,
   197  					id2: true,
   198  				},
   199  				ChannelMentioned: true,
   200  			},
   201  		},
   202  		"All": {
   203  			Message:  "this is an message for @all",
   204  			Keywords: map[string][]string{"@all": {id1, id2}},
   205  			Expected: &ExplicitMentions{
   206  				MentionedUserIds: map[string]bool{
   207  					id1: true,
   208  					id2: true,
   209  				},
   210  				AllMentioned: true,
   211  			},
   212  		},
   213  		"CapitalizedAll": {
   214  			Message:  "this is an message for @ALL",
   215  			Keywords: map[string][]string{"@all": {id1, id2}},
   216  			Expected: &ExplicitMentions{
   217  				MentionedUserIds: map[string]bool{
   218  					id1: true,
   219  					id2: true,
   220  				},
   221  				AllMentioned: true,
   222  			},
   223  		},
   224  		"UserWithPeriod": {
   225  			Message:  "user.period doesn't complicate things at all by including periods in their username",
   226  			Keywords: map[string][]string{"user.period": {id1}, "user": {id2}},
   227  			Expected: &ExplicitMentions{
   228  				MentionedUserIds: map[string]bool{
   229  					id1: true,
   230  				},
   231  			},
   232  		},
   233  		"AtUserWithPeriodAtEndOfSentence": {
   234  			Message:  "this is a message for @user.period.",
   235  			Keywords: map[string][]string{"@user.period": {id1}},
   236  			Expected: &ExplicitMentions{
   237  				MentionedUserIds: map[string]bool{
   238  					id1: true,
   239  				},
   240  			},
   241  		},
   242  		"UserWithPeriodAtEndOfSentence": {
   243  			Message:  "this is a message for user.period.",
   244  			Keywords: map[string][]string{"user.period": {id1}},
   245  			Expected: &ExplicitMentions{
   246  				MentionedUserIds: map[string]bool{
   247  					id1: true,
   248  				},
   249  			},
   250  		},
   251  		"PotentialOutOfChannelUser": {
   252  			Message:  "this is an message for @potential and @user",
   253  			Keywords: map[string][]string{"@user": {id1}},
   254  			Expected: &ExplicitMentions{
   255  				MentionedUserIds: map[string]bool{
   256  					id1: true,
   257  				},
   258  				OtherPotentialMentions: []string{"potential"},
   259  			},
   260  		},
   261  		"PotentialOutOfChannelUserWithPeriod": {
   262  			Message: "this is an message for @potential.user",
   263  			Expected: &ExplicitMentions{
   264  				OtherPotentialMentions: []string{"potential.user"},
   265  			},
   266  		},
   267  		"InlineCode": {
   268  			Message:  "`this shouldn't mention @channel at all`",
   269  			Keywords: map[string][]string{},
   270  			Expected: &ExplicitMentions{},
   271  		},
   272  		"FencedCodeBlock": {
   273  			Message:  "```\nthis shouldn't mention @channel at all\n```",
   274  			Keywords: map[string][]string{},
   275  			Expected: &ExplicitMentions{},
   276  		},
   277  		"Emphasis": {
   278  			Message:  "*@aaa @bbb @ccc*",
   279  			Keywords: map[string][]string{"@aaa": {id1}, "@bbb": {id2}, "@ccc": {id3}},
   280  			Expected: &ExplicitMentions{
   281  				MentionedUserIds: map[string]bool{
   282  					id1: true,
   283  					id2: true,
   284  					id3: true,
   285  				},
   286  			},
   287  		},
   288  		"StrongEmphasis": {
   289  			Message:  "**@aaa @bbb @ccc**",
   290  			Keywords: map[string][]string{"@aaa": {id1}, "@bbb": {id2}, "@ccc": {id3}},
   291  			Expected: &ExplicitMentions{
   292  				MentionedUserIds: map[string]bool{
   293  					id1: true,
   294  					id2: true,
   295  					id3: true,
   296  				},
   297  			},
   298  		},
   299  		"Strikethrough": {
   300  			Message:  "~~@aaa @bbb @ccc~~",
   301  			Keywords: map[string][]string{"@aaa": {id1}, "@bbb": {id2}, "@ccc": {id3}},
   302  			Expected: &ExplicitMentions{
   303  				MentionedUserIds: map[string]bool{
   304  					id1: true,
   305  					id2: true,
   306  					id3: true,
   307  				},
   308  			},
   309  		},
   310  		"Heading": {
   311  			Message:  "### @aaa",
   312  			Keywords: map[string][]string{"@aaa": {id1}, "@bbb": {id2}, "@ccc": {id3}},
   313  			Expected: &ExplicitMentions{
   314  				MentionedUserIds: map[string]bool{
   315  					id1: true,
   316  				},
   317  			},
   318  		},
   319  		"BlockQuote": {
   320  			Message:  "> @aaa",
   321  			Keywords: map[string][]string{"@aaa": {id1}, "@bbb": {id2}, "@ccc": {id3}},
   322  			Expected: &ExplicitMentions{
   323  				MentionedUserIds: map[string]bool{
   324  					id1: true,
   325  				},
   326  			},
   327  		},
   328  		"Emoji": {
   329  			Message:  ":smile:",
   330  			Keywords: map[string][]string{"smile": {id1}, "smiley": {id2}, "smiley_cat": {id3}},
   331  			Expected: &ExplicitMentions{},
   332  		},
   333  		"NotEmoji": {
   334  			Message:  "smile",
   335  			Keywords: map[string][]string{"smile": {id1}, "smiley": {id2}, "smiley_cat": {id3}},
   336  			Expected: &ExplicitMentions{
   337  				MentionedUserIds: map[string]bool{
   338  					id1: true,
   339  				},
   340  			},
   341  		},
   342  		"UnclosedEmoji": {
   343  			Message:  ":smile",
   344  			Keywords: map[string][]string{"smile": {id1}, "smiley": {id2}, "smiley_cat": {id3}},
   345  			Expected: &ExplicitMentions{
   346  				MentionedUserIds: map[string]bool{
   347  					id1: true,
   348  				},
   349  			},
   350  		},
   351  		"UnopenedEmoji": {
   352  			Message:  "smile:",
   353  			Keywords: map[string][]string{"smile": {id1}, "smiley": {id2}, "smiley_cat": {id3}},
   354  			Expected: &ExplicitMentions{
   355  				MentionedUserIds: map[string]bool{
   356  					id1: true,
   357  				},
   358  			},
   359  		},
   360  		"IndentedCodeBlock": {
   361  			Message:  "    this shouldn't mention @channel at all",
   362  			Keywords: map[string][]string{},
   363  			Expected: &ExplicitMentions{},
   364  		},
   365  		"LinkTitle": {
   366  			Message:  `[foo](this "shouldn't mention @channel at all")`,
   367  			Keywords: map[string][]string{},
   368  			Expected: &ExplicitMentions{},
   369  		},
   370  		"MalformedInlineCode": {
   371  			Message:  "`this should mention @channel``",
   372  			Keywords: map[string][]string{},
   373  			Expected: &ExplicitMentions{
   374  				ChannelMentioned: true,
   375  			},
   376  		},
   377  
   378  		// The following tests cover cases where the message mentions @user.name, so we shouldn't assume that
   379  		// the user might be intending to mention some @user that isn't in the channel.
   380  		"Don't include potential mention that's part of an actual mention (without trailing period)": {
   381  			Message:  "this is an message for @user.name",
   382  			Keywords: map[string][]string{"@user.name": {id1}},
   383  			Expected: &ExplicitMentions{
   384  				MentionedUserIds: map[string]bool{
   385  					id1: true,
   386  				},
   387  			},
   388  		},
   389  		"Don't include potential mention that's part of an actual mention (with trailing period)": {
   390  			Message:  "this is an message for @user.name.",
   391  			Keywords: map[string][]string{"@user.name": {id1}},
   392  			Expected: &ExplicitMentions{
   393  				MentionedUserIds: map[string]bool{
   394  					id1: true,
   395  				},
   396  			},
   397  		},
   398  		"Don't include potential mention that's part of an actual mention (with multiple trailing periods)": {
   399  			Message:  "this is an message for @user.name...",
   400  			Keywords: map[string][]string{"@user.name": {id1}},
   401  			Expected: &ExplicitMentions{
   402  				MentionedUserIds: map[string]bool{
   403  					id1: true,
   404  				},
   405  			},
   406  		},
   407  		"Don't include potential mention that's part of an actual mention (containing and followed by multiple periods)": {
   408  			Message:  "this is an message for @user...name...",
   409  			Keywords: map[string][]string{"@user...name": {id1}},
   410  			Expected: &ExplicitMentions{
   411  				MentionedUserIds: map[string]bool{
   412  					id1: true,
   413  				},
   414  			},
   415  		},
   416  	} {
   417  		t.Run(name, func(t *testing.T) {
   418  			m := GetExplicitMentions(tc.Message, tc.Keywords)
   419  			if tc.Expected.MentionedUserIds == nil {
   420  				tc.Expected.MentionedUserIds = make(map[string]bool)
   421  			}
   422  			assert.EqualValues(t, tc.Expected, m)
   423  		})
   424  	}
   425  }
   426  
   427  func TestGetExplicitMentionsAtHere(t *testing.T) {
   428  	// test all the boundary cases that we know can break up terms (and those that we know won't)
   429  	cases := map[string]bool{
   430  		"":          false,
   431  		"here":      false,
   432  		"@here":     true,
   433  		" @here ":   true,
   434  		"\n@here\n": true,
   435  		"!@here!":   true,
   436  		"#@here#":   true,
   437  		"$@here$":   true,
   438  		"%@here%":   true,
   439  		"^@here^":   true,
   440  		"&@here&":   true,
   441  		"*@here*":   true,
   442  		"(@here(":   true,
   443  		")@here)":   true,
   444  		"-@here-":   true,
   445  		"_@here_":   false, // This case shouldn't mention since it would be mentioning "@here_"
   446  		"=@here=":   true,
   447  		"+@here+":   true,
   448  		"[@here[":   true,
   449  		"{@here{":   true,
   450  		"]@here]":   true,
   451  		"}@here}":   true,
   452  		"\\@here\\": true,
   453  		"|@here|":   true,
   454  		";@here;":   true,
   455  		":@here:":   false, // This case shouldn't trigger a mention since it follows the format of reactions e.g. :word:
   456  		"'@here'":   true,
   457  		"\"@here\"": true,
   458  		",@here,":   true,
   459  		"<@here<":   true,
   460  		".@here.":   true,
   461  		">@here>":   true,
   462  		"/@here/":   true,
   463  		"?@here?":   true,
   464  		"`@here`":   false, // This case shouldn't mention since it's a code block
   465  		"~@here~":   true,
   466  		"@HERE":     true,
   467  		"@hERe":     true,
   468  	}
   469  
   470  	for message, shouldMention := range cases {
   471  		if m := GetExplicitMentions(message, nil); m.HereMentioned && !shouldMention {
   472  			t.Fatalf("shouldn't have mentioned @here with \"%v\"", message)
   473  		} else if !m.HereMentioned && shouldMention {
   474  			t.Fatalf("should've mentioned @here with \"%v\"", message)
   475  		}
   476  	}
   477  
   478  	// mentioning @here and someone
   479  	id := model.NewId()
   480  	if m := GetExplicitMentions("@here @user @potential", map[string][]string{"@user": {id}}); !m.HereMentioned {
   481  		t.Fatal("should've mentioned @here with \"@here @user\"")
   482  	} else if len(m.MentionedUserIds) != 1 || !m.MentionedUserIds[id] {
   483  		t.Fatal("should've mentioned @user with \"@here @user\"")
   484  	} else if len(m.OtherPotentialMentions) > 1 {
   485  		t.Fatal("should've potential mentions for @potential")
   486  	}
   487  }
   488  
   489  func TestGetMentionKeywords(t *testing.T) {
   490  	th := Setup()
   491  	defer th.TearDown()
   492  
   493  	// user with username or custom mentions enabled
   494  	user1 := &model.User{
   495  		Id:        model.NewId(),
   496  		FirstName: "First",
   497  		Username:  "User",
   498  		NotifyProps: map[string]string{
   499  			"mention_keys": "User,@User,MENTION",
   500  		},
   501  	}
   502  
   503  	profiles := map[string]*model.User{user1.Id: user1}
   504  	mentions := th.App.GetMentionKeywordsInChannel(profiles, true)
   505  	if len(mentions) != 3 {
   506  		t.Fatal("should've returned three mention keywords")
   507  	} else if ids, ok := mentions["user"]; !ok || ids[0] != user1.Id {
   508  		t.Fatal("should've returned mention key of user")
   509  	} else if ids, ok := mentions["@user"]; !ok || ids[0] != user1.Id {
   510  		t.Fatal("should've returned mention key of @user")
   511  	} else if ids, ok := mentions["mention"]; !ok || ids[0] != user1.Id {
   512  		t.Fatal("should've returned mention key of mention")
   513  	}
   514  
   515  	// user with first name mention enabled
   516  	user2 := &model.User{
   517  		Id:        model.NewId(),
   518  		FirstName: "First",
   519  		Username:  "User",
   520  		NotifyProps: map[string]string{
   521  			"first_name": "true",
   522  		},
   523  	}
   524  
   525  	profiles = map[string]*model.User{user2.Id: user2}
   526  	mentions = th.App.GetMentionKeywordsInChannel(profiles, true)
   527  	if len(mentions) != 2 {
   528  		t.Fatal("should've returned two mention keyword")
   529  	} else if ids, ok := mentions["First"]; !ok || ids[0] != user2.Id {
   530  		t.Fatal("should've returned mention key of First")
   531  	}
   532  
   533  	// user with @channel/@all mentions enabled
   534  	user3 := &model.User{
   535  		Id:        model.NewId(),
   536  		FirstName: "First",
   537  		Username:  "User",
   538  		NotifyProps: map[string]string{
   539  			"channel": "true",
   540  		},
   541  	}
   542  
   543  	profiles = map[string]*model.User{user3.Id: user3}
   544  	mentions = th.App.GetMentionKeywordsInChannel(profiles, true)
   545  	if len(mentions) != 3 {
   546  		t.Fatal("should've returned three mention keywords")
   547  	} else if ids, ok := mentions["@channel"]; !ok || ids[0] != user3.Id {
   548  		t.Fatal("should've returned mention key of @channel")
   549  	} else if ids, ok := mentions["@all"]; !ok || ids[0] != user3.Id {
   550  		t.Fatal("should've returned mention key of @all")
   551  	}
   552  
   553  	// user with all types of mentions enabled
   554  	user4 := &model.User{
   555  		Id:        model.NewId(),
   556  		FirstName: "First",
   557  		Username:  "User",
   558  		NotifyProps: map[string]string{
   559  			"mention_keys": "User,@User,MENTION",
   560  			"first_name":   "true",
   561  			"channel":      "true",
   562  		},
   563  	}
   564  
   565  	profiles = map[string]*model.User{user4.Id: user4}
   566  	mentions = th.App.GetMentionKeywordsInChannel(profiles, true)
   567  	if len(mentions) != 6 {
   568  		t.Fatal("should've returned six mention keywords")
   569  	} else if ids, ok := mentions["user"]; !ok || ids[0] != user4.Id {
   570  		t.Fatal("should've returned mention key of user")
   571  	} else if ids, ok := mentions["@user"]; !ok || ids[0] != user4.Id {
   572  		t.Fatal("should've returned mention key of @user")
   573  	} else if ids, ok := mentions["mention"]; !ok || ids[0] != user4.Id {
   574  		t.Fatal("should've returned mention key of mention")
   575  	} else if ids, ok := mentions["First"]; !ok || ids[0] != user4.Id {
   576  		t.Fatal("should've returned mention key of First")
   577  	} else if ids, ok := mentions["@channel"]; !ok || ids[0] != user4.Id {
   578  		t.Fatal("should've returned mention key of @channel")
   579  	} else if ids, ok := mentions["@all"]; !ok || ids[0] != user4.Id {
   580  		t.Fatal("should've returned mention key of @all")
   581  	}
   582  
   583  	dup_count := func(list []string) map[string]int {
   584  
   585  		duplicate_frequency := make(map[string]int)
   586  
   587  		for _, item := range list {
   588  			// check if the item/element exist in the duplicate_frequency map
   589  
   590  			_, exist := duplicate_frequency[item]
   591  
   592  			if exist {
   593  				duplicate_frequency[item] += 1 // increase counter by 1 if already in the map
   594  			} else {
   595  				duplicate_frequency[item] = 1 // else start counting from 1
   596  			}
   597  		}
   598  		return duplicate_frequency
   599  	}
   600  
   601  	// multiple users but no more than MaxNotificationsPerChannel
   602  	th.App.UpdateConfig(func(cfg *model.Config) { *cfg.TeamSettings.MaxNotificationsPerChannel = 4 })
   603  	profiles = map[string]*model.User{
   604  		user1.Id: user1,
   605  		user2.Id: user2,
   606  		user3.Id: user3,
   607  		user4.Id: user4,
   608  	}
   609  	mentions = th.App.GetMentionKeywordsInChannel(profiles, true)
   610  	if len(mentions) != 6 {
   611  		t.Fatal("should've returned six mention keywords")
   612  	} else if ids, ok := mentions["user"]; !ok || len(ids) != 2 || (ids[0] != user1.Id && ids[1] != user1.Id) || (ids[0] != user4.Id && ids[1] != user4.Id) {
   613  		t.Fatal("should've mentioned user1 and user4 with user")
   614  	} else if ids := dup_count(mentions["@user"]); len(ids) != 4 || (ids[user1.Id] != 2) || (ids[user4.Id] != 2) {
   615  		t.Fatal("should've mentioned user1 and user4 with @user")
   616  	} else if ids, ok := mentions["mention"]; !ok || len(ids) != 2 || (ids[0] != user1.Id && ids[1] != user1.Id) || (ids[0] != user4.Id && ids[1] != user4.Id) {
   617  		t.Fatal("should've mentioned user1 and user4 with mention")
   618  	} else if ids, ok := mentions["First"]; !ok || len(ids) != 2 || (ids[0] != user2.Id && ids[1] != user2.Id) || (ids[0] != user4.Id && ids[1] != user4.Id) {
   619  		t.Fatal("should've mentioned user2 and user4 with First")
   620  	} else if ids, ok := mentions["@channel"]; !ok || len(ids) != 2 || (ids[0] != user3.Id && ids[1] != user3.Id) || (ids[0] != user4.Id && ids[1] != user4.Id) {
   621  		t.Fatal("should've mentioned user3 and user4 with @channel")
   622  	} else if ids, ok := mentions["@all"]; !ok || len(ids) != 2 || (ids[0] != user3.Id && ids[1] != user3.Id) || (ids[0] != user4.Id && ids[1] != user4.Id) {
   623  		t.Fatal("should've mentioned user3 and user4 with @all")
   624  	}
   625  
   626  	// multiple users and more than MaxNotificationsPerChannel
   627  	th.App.UpdateConfig(func(cfg *model.Config) { *cfg.TeamSettings.MaxNotificationsPerChannel = 3 })
   628  	mentions = th.App.GetMentionKeywordsInChannel(profiles, true)
   629  	if len(mentions) != 4 {
   630  		t.Fatal("should've returned four mention keywords")
   631  	} else if _, ok := mentions["@channel"]; ok {
   632  		t.Fatal("should not have mentioned any user with @channel")
   633  	} else if _, ok := mentions["@all"]; ok {
   634  		t.Fatal("should not have mentioned any user with @all")
   635  	} else if _, ok := mentions["@here"]; ok {
   636  		t.Fatal("should not have mentioned any user with @here")
   637  	}
   638  
   639  	// no special mentions
   640  	profiles = map[string]*model.User{
   641  		user1.Id: user1,
   642  	}
   643  	mentions = th.App.GetMentionKeywordsInChannel(profiles, false)
   644  	if len(mentions) != 3 {
   645  		t.Fatal("should've returned three mention keywords")
   646  	} else if ids, ok := mentions["user"]; !ok || len(ids) != 1 || ids[0] != user1.Id {
   647  		t.Fatal("should've mentioned user1 with user")
   648  	} else if ids, ok := mentions["@user"]; !ok || len(ids) != 2 || ids[0] != user1.Id || ids[1] != user1.Id {
   649  		t.Fatal("should've mentioned user1 twice with @user")
   650  	} else if ids, ok := mentions["mention"]; !ok || len(ids) != 1 || ids[0] != user1.Id {
   651  		t.Fatal("should've mentioned user1 with mention")
   652  	} else if _, ok := mentions["First"]; ok {
   653  		t.Fatal("should not have mentioned user1 with First")
   654  	} else if _, ok := mentions["@channel"]; ok {
   655  		t.Fatal("should not have mentioned any user with @channel")
   656  	} else if _, ok := mentions["@all"]; ok {
   657  		t.Fatal("should not have mentioned any user with @all")
   658  	} else if _, ok := mentions["@here"]; ok {
   659  		t.Fatal("should not have mentioned any user with @here")
   660  	}
   661  }
   662  
   663  func TestDoesNotifyPropsAllowPushNotification(t *testing.T) {
   664  	userNotifyProps := make(map[string]string)
   665  	channelNotifyProps := make(map[string]string)
   666  
   667  	user := &model.User{Id: model.NewId(), Email: "unit@test.com"}
   668  
   669  	post := &model.Post{UserId: user.Id, ChannelId: model.NewId()}
   670  
   671  	// When the post is a System Message
   672  	systemPost := &model.Post{UserId: user.Id, Type: model.POST_JOIN_CHANNEL}
   673  	userNotifyProps[model.PUSH_NOTIFY_PROP] = model.USER_NOTIFY_ALL
   674  	user.NotifyProps = userNotifyProps
   675  	if DoesNotifyPropsAllowPushNotification(user, channelNotifyProps, systemPost, false) {
   676  		t.Fatal("Should have returned false")
   677  	}
   678  
   679  	if DoesNotifyPropsAllowPushNotification(user, channelNotifyProps, systemPost, true) {
   680  		t.Fatal("Should have returned false")
   681  	}
   682  
   683  	// When default is ALL and no channel props is set
   684  	if !DoesNotifyPropsAllowPushNotification(user, channelNotifyProps, post, false) {
   685  		t.Fatal("Should have returned true")
   686  	}
   687  
   688  	if !DoesNotifyPropsAllowPushNotification(user, channelNotifyProps, post, true) {
   689  		t.Fatal("Should have returned true")
   690  	}
   691  
   692  	// When default is MENTION and no channel props is set
   693  	userNotifyProps[model.PUSH_NOTIFY_PROP] = model.USER_NOTIFY_MENTION
   694  	user.NotifyProps = userNotifyProps
   695  	if DoesNotifyPropsAllowPushNotification(user, channelNotifyProps, post, false) {
   696  		t.Fatal("Should have returned false")
   697  	}
   698  
   699  	if !DoesNotifyPropsAllowPushNotification(user, channelNotifyProps, post, true) {
   700  		t.Fatal("Should have returned true")
   701  	}
   702  
   703  	// When default is NONE and no channel props is set
   704  	userNotifyProps[model.PUSH_NOTIFY_PROP] = model.USER_NOTIFY_NONE
   705  	user.NotifyProps = userNotifyProps
   706  	if DoesNotifyPropsAllowPushNotification(user, channelNotifyProps, post, false) {
   707  		t.Fatal("Should have returned false")
   708  	}
   709  
   710  	if DoesNotifyPropsAllowPushNotification(user, channelNotifyProps, post, true) {
   711  		t.Fatal("Should have returned false")
   712  	}
   713  
   714  	// WHEN default is ALL and channel is DEFAULT
   715  	userNotifyProps[model.PUSH_NOTIFY_PROP] = model.USER_NOTIFY_ALL
   716  	user.NotifyProps = userNotifyProps
   717  	channelNotifyProps[model.PUSH_NOTIFY_PROP] = model.CHANNEL_NOTIFY_DEFAULT
   718  	if !DoesNotifyPropsAllowPushNotification(user, channelNotifyProps, post, false) {
   719  		t.Fatal("Should have returned true")
   720  	}
   721  
   722  	if !DoesNotifyPropsAllowPushNotification(user, channelNotifyProps, post, true) {
   723  		t.Fatal("Should have returned true")
   724  	}
   725  
   726  	// WHEN default is MENTION and channel is DEFAULT
   727  	userNotifyProps[model.PUSH_NOTIFY_PROP] = model.USER_NOTIFY_MENTION
   728  	user.NotifyProps = userNotifyProps
   729  	channelNotifyProps[model.PUSH_NOTIFY_PROP] = model.CHANNEL_NOTIFY_DEFAULT
   730  	if DoesNotifyPropsAllowPushNotification(user, channelNotifyProps, post, false) {
   731  		t.Fatal("Should have returned false")
   732  	}
   733  
   734  	if !DoesNotifyPropsAllowPushNotification(user, channelNotifyProps, post, true) {
   735  		t.Fatal("Should have returned true")
   736  	}
   737  
   738  	// WHEN default is NONE and channel is DEFAULT
   739  	userNotifyProps[model.PUSH_NOTIFY_PROP] = model.USER_NOTIFY_NONE
   740  	user.NotifyProps = userNotifyProps
   741  	channelNotifyProps[model.PUSH_NOTIFY_PROP] = model.CHANNEL_NOTIFY_DEFAULT
   742  	if DoesNotifyPropsAllowPushNotification(user, channelNotifyProps, post, false) {
   743  		t.Fatal("Should have returned false")
   744  	}
   745  
   746  	if DoesNotifyPropsAllowPushNotification(user, channelNotifyProps, post, true) {
   747  		t.Fatal("Should have returned false")
   748  	}
   749  
   750  	// WHEN default is ALL and channel is ALL
   751  	userNotifyProps[model.PUSH_NOTIFY_PROP] = model.USER_NOTIFY_ALL
   752  	user.NotifyProps = userNotifyProps
   753  	channelNotifyProps[model.PUSH_NOTIFY_PROP] = model.CHANNEL_NOTIFY_ALL
   754  	if !DoesNotifyPropsAllowPushNotification(user, channelNotifyProps, post, false) {
   755  		t.Fatal("Should have returned true")
   756  	}
   757  
   758  	if !DoesNotifyPropsAllowPushNotification(user, channelNotifyProps, post, true) {
   759  		t.Fatal("Should have returned true")
   760  	}
   761  
   762  	// WHEN default is MENTION and channel is ALL
   763  	userNotifyProps[model.PUSH_NOTIFY_PROP] = model.USER_NOTIFY_MENTION
   764  	user.NotifyProps = userNotifyProps
   765  	channelNotifyProps[model.PUSH_NOTIFY_PROP] = model.CHANNEL_NOTIFY_ALL
   766  	if !DoesNotifyPropsAllowPushNotification(user, channelNotifyProps, post, false) {
   767  		t.Fatal("Should have returned true")
   768  	}
   769  
   770  	if !DoesNotifyPropsAllowPushNotification(user, channelNotifyProps, post, true) {
   771  		t.Fatal("Should have returned true")
   772  	}
   773  
   774  	// WHEN default is NONE and channel is ALL
   775  	userNotifyProps[model.PUSH_NOTIFY_PROP] = model.USER_NOTIFY_NONE
   776  	user.NotifyProps = userNotifyProps
   777  	channelNotifyProps[model.PUSH_NOTIFY_PROP] = model.CHANNEL_NOTIFY_ALL
   778  	if !DoesNotifyPropsAllowPushNotification(user, channelNotifyProps, post, false) {
   779  		t.Fatal("Should have returned true")
   780  	}
   781  
   782  	if !DoesNotifyPropsAllowPushNotification(user, channelNotifyProps, post, true) {
   783  		t.Fatal("Should have returned true")
   784  	}
   785  
   786  	// WHEN default is ALL and channel is MENTION
   787  	userNotifyProps[model.PUSH_NOTIFY_PROP] = model.USER_NOTIFY_ALL
   788  	user.NotifyProps = userNotifyProps
   789  	channelNotifyProps[model.PUSH_NOTIFY_PROP] = model.CHANNEL_NOTIFY_MENTION
   790  	if DoesNotifyPropsAllowPushNotification(user, channelNotifyProps, post, false) {
   791  		t.Fatal("Should have returned false")
   792  	}
   793  
   794  	if !DoesNotifyPropsAllowPushNotification(user, channelNotifyProps, post, true) {
   795  		t.Fatal("Should have returned true")
   796  	}
   797  
   798  	// WHEN default is MENTION and channel is MENTION
   799  	userNotifyProps[model.PUSH_NOTIFY_PROP] = model.USER_NOTIFY_MENTION
   800  	user.NotifyProps = userNotifyProps
   801  	channelNotifyProps[model.PUSH_NOTIFY_PROP] = model.CHANNEL_NOTIFY_MENTION
   802  	if DoesNotifyPropsAllowPushNotification(user, channelNotifyProps, post, false) {
   803  		t.Fatal("Should have returned false")
   804  	}
   805  
   806  	if !DoesNotifyPropsAllowPushNotification(user, channelNotifyProps, post, true) {
   807  		t.Fatal("Should have returned true")
   808  	}
   809  
   810  	// WHEN default is NONE and channel is MENTION
   811  	userNotifyProps[model.PUSH_NOTIFY_PROP] = model.USER_NOTIFY_NONE
   812  	user.NotifyProps = userNotifyProps
   813  	channelNotifyProps[model.PUSH_NOTIFY_PROP] = model.CHANNEL_NOTIFY_MENTION
   814  	if DoesNotifyPropsAllowPushNotification(user, channelNotifyProps, post, false) {
   815  		t.Fatal("Should have returned false")
   816  	}
   817  
   818  	if !DoesNotifyPropsAllowPushNotification(user, channelNotifyProps, post, true) {
   819  		t.Fatal("Should have returned true")
   820  	}
   821  
   822  	// WHEN default is ALL and channel is NONE
   823  	userNotifyProps[model.PUSH_NOTIFY_PROP] = model.USER_NOTIFY_ALL
   824  	user.NotifyProps = userNotifyProps
   825  	channelNotifyProps[model.PUSH_NOTIFY_PROP] = model.CHANNEL_NOTIFY_NONE
   826  	if DoesNotifyPropsAllowPushNotification(user, channelNotifyProps, post, false) {
   827  		t.Fatal("Should have returned false")
   828  	}
   829  
   830  	if DoesNotifyPropsAllowPushNotification(user, channelNotifyProps, post, true) {
   831  		t.Fatal("Should have returned false")
   832  	}
   833  
   834  	// WHEN default is MENTION and channel is NONE
   835  	userNotifyProps[model.PUSH_NOTIFY_PROP] = model.USER_NOTIFY_MENTION
   836  	user.NotifyProps = userNotifyProps
   837  	channelNotifyProps[model.PUSH_NOTIFY_PROP] = model.CHANNEL_NOTIFY_NONE
   838  	if DoesNotifyPropsAllowPushNotification(user, channelNotifyProps, post, false) {
   839  		t.Fatal("Should have returned false")
   840  	}
   841  
   842  	if DoesNotifyPropsAllowPushNotification(user, channelNotifyProps, post, true) {
   843  		t.Fatal("Should have returned false")
   844  	}
   845  
   846  	// WHEN default is NONE and channel is NONE
   847  	userNotifyProps[model.PUSH_NOTIFY_PROP] = model.USER_NOTIFY_NONE
   848  	user.NotifyProps = userNotifyProps
   849  	channelNotifyProps[model.PUSH_NOTIFY_PROP] = model.CHANNEL_NOTIFY_NONE
   850  	if DoesNotifyPropsAllowPushNotification(user, channelNotifyProps, post, false) {
   851  		t.Fatal("Should have returned false")
   852  	}
   853  
   854  	if DoesNotifyPropsAllowPushNotification(user, channelNotifyProps, post, true) {
   855  		t.Fatal("Should have returned false")
   856  	}
   857  
   858  	// WHEN default is ALL and channel is MUTED
   859  	userNotifyProps[model.PUSH_NOTIFY_PROP] = model.USER_NOTIFY_ALL
   860  	user.NotifyProps = userNotifyProps
   861  	channelNotifyProps[model.MARK_UNREAD_NOTIFY_PROP] = model.CHANNEL_MARK_UNREAD_MENTION
   862  	if DoesNotifyPropsAllowPushNotification(user, channelNotifyProps, post, false) {
   863  		t.Fatal("Should have returned false")
   864  	}
   865  }
   866  
   867  func TestDoesStatusAllowPushNotification(t *testing.T) {
   868  	userNotifyProps := make(map[string]string)
   869  	userId := model.NewId()
   870  	channelId := model.NewId()
   871  
   872  	offline := &model.Status{UserId: userId, Status: model.STATUS_OFFLINE, Manual: false, LastActivityAt: 0, ActiveChannel: ""}
   873  	away := &model.Status{UserId: userId, Status: model.STATUS_AWAY, Manual: false, LastActivityAt: 0, ActiveChannel: ""}
   874  	online := &model.Status{UserId: userId, Status: model.STATUS_ONLINE, Manual: false, LastActivityAt: model.GetMillis(), ActiveChannel: ""}
   875  	dnd := &model.Status{UserId: userId, Status: model.STATUS_DND, Manual: true, LastActivityAt: model.GetMillis(), ActiveChannel: ""}
   876  
   877  	userNotifyProps["push_status"] = model.STATUS_ONLINE
   878  	// WHEN props is ONLINE and user is offline
   879  	if !DoesStatusAllowPushNotification(userNotifyProps, offline, channelId) {
   880  		t.Fatal("Should have been true")
   881  	}
   882  
   883  	if !DoesStatusAllowPushNotification(userNotifyProps, offline, "") {
   884  		t.Fatal("Should have been true")
   885  	}
   886  
   887  	// WHEN props is ONLINE and user is away
   888  	if !DoesStatusAllowPushNotification(userNotifyProps, away, channelId) {
   889  		t.Fatal("Should have been true")
   890  	}
   891  
   892  	if !DoesStatusAllowPushNotification(userNotifyProps, away, "") {
   893  		t.Fatal("Should have been true")
   894  	}
   895  
   896  	// WHEN props is ONLINE and user is online
   897  	if !DoesStatusAllowPushNotification(userNotifyProps, online, channelId) {
   898  		t.Fatal("Should have been true")
   899  	}
   900  
   901  	if DoesStatusAllowPushNotification(userNotifyProps, online, "") {
   902  		t.Fatal("Should have been false")
   903  	}
   904  
   905  	// WHEN props is ONLINE and user is dnd
   906  	if DoesStatusAllowPushNotification(userNotifyProps, dnd, channelId) {
   907  		t.Fatal("Should have been false")
   908  	}
   909  
   910  	if DoesStatusAllowPushNotification(userNotifyProps, dnd, "") {
   911  		t.Fatal("Should have been false")
   912  	}
   913  
   914  	userNotifyProps["push_status"] = model.STATUS_AWAY
   915  	// WHEN props is AWAY and user is offline
   916  	if !DoesStatusAllowPushNotification(userNotifyProps, offline, channelId) {
   917  		t.Fatal("Should have been true")
   918  	}
   919  
   920  	if !DoesStatusAllowPushNotification(userNotifyProps, offline, "") {
   921  		t.Fatal("Should have been true")
   922  	}
   923  
   924  	// WHEN props is AWAY and user is away
   925  	if !DoesStatusAllowPushNotification(userNotifyProps, away, channelId) {
   926  		t.Fatal("Should have been true")
   927  	}
   928  
   929  	if !DoesStatusAllowPushNotification(userNotifyProps, away, "") {
   930  		t.Fatal("Should have been true")
   931  	}
   932  
   933  	// WHEN props is AWAY and user is online
   934  	if DoesStatusAllowPushNotification(userNotifyProps, online, channelId) {
   935  		t.Fatal("Should have been false")
   936  	}
   937  
   938  	if DoesStatusAllowPushNotification(userNotifyProps, online, "") {
   939  		t.Fatal("Should have been false")
   940  	}
   941  
   942  	// WHEN props is AWAY and user is dnd
   943  	if DoesStatusAllowPushNotification(userNotifyProps, dnd, channelId) {
   944  		t.Fatal("Should have been false")
   945  	}
   946  
   947  	if DoesStatusAllowPushNotification(userNotifyProps, dnd, "") {
   948  		t.Fatal("Should have been false")
   949  	}
   950  
   951  	userNotifyProps["push_status"] = model.STATUS_OFFLINE
   952  	// WHEN props is OFFLINE and user is offline
   953  	if !DoesStatusAllowPushNotification(userNotifyProps, offline, channelId) {
   954  		t.Fatal("Should have been true")
   955  	}
   956  
   957  	if !DoesStatusAllowPushNotification(userNotifyProps, offline, "") {
   958  		t.Fatal("Should have been true")
   959  	}
   960  
   961  	// WHEN props is OFFLINE and user is away
   962  	if DoesStatusAllowPushNotification(userNotifyProps, away, channelId) {
   963  		t.Fatal("Should have been false")
   964  	}
   965  
   966  	if DoesStatusAllowPushNotification(userNotifyProps, away, "") {
   967  		t.Fatal("Should have been false")
   968  	}
   969  
   970  	// WHEN props is OFFLINE and user is online
   971  	if DoesStatusAllowPushNotification(userNotifyProps, online, channelId) {
   972  		t.Fatal("Should have been false")
   973  	}
   974  
   975  	if DoesStatusAllowPushNotification(userNotifyProps, online, "") {
   976  		t.Fatal("Should have been false")
   977  	}
   978  
   979  	// WHEN props is OFFLINE and user is dnd
   980  	if DoesStatusAllowPushNotification(userNotifyProps, dnd, channelId) {
   981  		t.Fatal("Should have been false")
   982  	}
   983  
   984  	if DoesStatusAllowPushNotification(userNotifyProps, dnd, "") {
   985  		t.Fatal("Should have been false")
   986  	}
   987  
   988  }
   989  
   990  func TestGetDirectMessageNotificationEmailSubject(t *testing.T) {
   991  	th := Setup()
   992  	defer th.TearDown()
   993  
   994  	expectedPrefix := "[http://localhost:8065] New Direct Message from sender on"
   995  	post := &model.Post{
   996  		CreateAt: 1501804801000,
   997  	}
   998  	translateFunc := utils.GetUserTranslations("en")
   999  	subject := getDirectMessageNotificationEmailSubject(post, translateFunc, "http://localhost:8065", "sender")
  1000  	if !strings.HasPrefix(subject, expectedPrefix) {
  1001  		t.Fatal("Expected subject line prefix '" + expectedPrefix + "', got " + subject)
  1002  	}
  1003  }
  1004  
  1005  func TestGetNotificationEmailSubject(t *testing.T) {
  1006  	th := Setup()
  1007  	defer th.TearDown()
  1008  
  1009  	expectedPrefix := "[http://localhost:8065] Notification in team on"
  1010  	post := &model.Post{
  1011  		CreateAt: 1501804801000,
  1012  	}
  1013  	translateFunc := utils.GetUserTranslations("en")
  1014  	subject := getNotificationEmailSubject(post, translateFunc, "http://localhost:8065", "team")
  1015  	if !strings.HasPrefix(subject, expectedPrefix) {
  1016  		t.Fatal("Expected subject line prefix '" + expectedPrefix + "', got " + subject)
  1017  	}
  1018  }
  1019  
  1020  func TestGetNotificationEmailBodyFullNotificationPublicChannel(t *testing.T) {
  1021  	th := Setup()
  1022  	defer th.TearDown()
  1023  
  1024  	recipient := &model.User{}
  1025  	post := &model.Post{
  1026  		Message: "This is the message",
  1027  	}
  1028  	channel := &model.Channel{
  1029  		DisplayName: "ChannelName",
  1030  		Type:        model.CHANNEL_OPEN,
  1031  	}
  1032  	senderName := "sender"
  1033  	teamName := "team"
  1034  	teamURL := "http://localhost:8065/" + teamName
  1035  	emailNotificationContentsType := model.EMAIL_NOTIFICATION_CONTENTS_FULL
  1036  	translateFunc := utils.GetUserTranslations("en")
  1037  
  1038  	body := th.App.getNotificationEmailBody(recipient, post, channel, senderName, teamName, teamURL, emailNotificationContentsType, translateFunc)
  1039  	if !strings.Contains(body, "You have a new notification.") {
  1040  		t.Fatal("Expected email text 'You have a new notification. Got " + body)
  1041  	}
  1042  	if !strings.Contains(body, "CHANNEL: "+channel.DisplayName) {
  1043  		t.Fatal("Expected email text 'CHANNEL: " + channel.DisplayName + "'. Got " + body)
  1044  	}
  1045  	if !strings.Contains(body, senderName+" - ") {
  1046  		t.Fatal("Expected email text '" + senderName + " - '. Got " + body)
  1047  	}
  1048  	if !strings.Contains(body, post.Message) {
  1049  		t.Fatal("Expected email text '" + post.Message + "'. Got " + body)
  1050  	}
  1051  	if !strings.Contains(body, teamURL) {
  1052  		t.Fatal("Expected email text '" + teamURL + "'. Got " + body)
  1053  	}
  1054  }
  1055  
  1056  func TestGetNotificationEmailBodyFullNotificationGroupChannel(t *testing.T) {
  1057  	th := Setup()
  1058  	defer th.TearDown()
  1059  
  1060  	recipient := &model.User{}
  1061  	post := &model.Post{
  1062  		Message: "This is the message",
  1063  	}
  1064  	channel := &model.Channel{
  1065  		DisplayName: "ChannelName",
  1066  		Type:        model.CHANNEL_GROUP,
  1067  	}
  1068  	senderName := "sender"
  1069  	teamName := "team"
  1070  	teamURL := "http://localhost:8065/" + teamName
  1071  	emailNotificationContentsType := model.EMAIL_NOTIFICATION_CONTENTS_FULL
  1072  	translateFunc := utils.GetUserTranslations("en")
  1073  
  1074  	body := th.App.getNotificationEmailBody(recipient, post, channel, senderName, teamName, teamURL, emailNotificationContentsType, translateFunc)
  1075  	if !strings.Contains(body, "You have a new notification.") {
  1076  		t.Fatal("Expected email text 'You have a new notification. Got " + body)
  1077  	}
  1078  	if !strings.Contains(body, "CHANNEL: Group Message") {
  1079  		t.Fatal("Expected email text 'CHANNEL: Group Message'. Got " + body)
  1080  	}
  1081  	if !strings.Contains(body, senderName+" - ") {
  1082  		t.Fatal("Expected email text '" + senderName + " - '. Got " + body)
  1083  	}
  1084  	if !strings.Contains(body, post.Message) {
  1085  		t.Fatal("Expected email text '" + post.Message + "'. Got " + body)
  1086  	}
  1087  	if !strings.Contains(body, teamURL) {
  1088  		t.Fatal("Expected email text '" + teamURL + "'. Got " + body)
  1089  	}
  1090  }
  1091  
  1092  func TestGetNotificationEmailBodyFullNotificationPrivateChannel(t *testing.T) {
  1093  	th := Setup()
  1094  	defer th.TearDown()
  1095  
  1096  	recipient := &model.User{}
  1097  	post := &model.Post{
  1098  		Message: "This is the message",
  1099  	}
  1100  	channel := &model.Channel{
  1101  		DisplayName: "ChannelName",
  1102  		Type:        model.CHANNEL_PRIVATE,
  1103  	}
  1104  	senderName := "sender"
  1105  	teamName := "team"
  1106  	teamURL := "http://localhost:8065/" + teamName
  1107  	emailNotificationContentsType := model.EMAIL_NOTIFICATION_CONTENTS_FULL
  1108  	translateFunc := utils.GetUserTranslations("en")
  1109  
  1110  	body := th.App.getNotificationEmailBody(recipient, post, channel, senderName, teamName, teamURL, emailNotificationContentsType, translateFunc)
  1111  	if !strings.Contains(body, "You have a new notification.") {
  1112  		t.Fatal("Expected email text 'You have a new notification. Got " + body)
  1113  	}
  1114  	if !strings.Contains(body, "CHANNEL: "+channel.DisplayName) {
  1115  		t.Fatal("Expected email text 'CHANNEL: " + channel.DisplayName + "'. Got " + body)
  1116  	}
  1117  	if !strings.Contains(body, senderName+" - ") {
  1118  		t.Fatal("Expected email text '" + senderName + " - '. Got " + body)
  1119  	}
  1120  	if !strings.Contains(body, post.Message) {
  1121  		t.Fatal("Expected email text '" + post.Message + "'. Got " + body)
  1122  	}
  1123  	if !strings.Contains(body, teamURL) {
  1124  		t.Fatal("Expected email text '" + teamURL + "'. Got " + body)
  1125  	}
  1126  }
  1127  
  1128  func TestGetNotificationEmailBodyFullNotificationDirectChannel(t *testing.T) {
  1129  	th := Setup()
  1130  	defer th.TearDown()
  1131  
  1132  	recipient := &model.User{}
  1133  	post := &model.Post{
  1134  		Message: "This is the message",
  1135  	}
  1136  	channel := &model.Channel{
  1137  		DisplayName: "ChannelName",
  1138  		Type:        model.CHANNEL_DIRECT,
  1139  	}
  1140  	senderName := "sender"
  1141  	teamName := "team"
  1142  	teamURL := "http://localhost:8065/" + teamName
  1143  	emailNotificationContentsType := model.EMAIL_NOTIFICATION_CONTENTS_FULL
  1144  	translateFunc := utils.GetUserTranslations("en")
  1145  
  1146  	body := th.App.getNotificationEmailBody(recipient, post, channel, senderName, teamName, teamURL, emailNotificationContentsType, translateFunc)
  1147  	if !strings.Contains(body, "You have a new direct message.") {
  1148  		t.Fatal("Expected email text 'You have a new direct message. Got " + body)
  1149  	}
  1150  	if !strings.Contains(body, senderName+" - ") {
  1151  		t.Fatal("Expected email text '" + senderName + " - '. Got " + body)
  1152  	}
  1153  	if !strings.Contains(body, post.Message) {
  1154  		t.Fatal("Expected email text '" + post.Message + "'. Got " + body)
  1155  	}
  1156  	if !strings.Contains(body, teamURL) {
  1157  		t.Fatal("Expected email text '" + teamURL + "'. Got " + body)
  1158  	}
  1159  }
  1160  
  1161  // from here
  1162  func TestGetNotificationEmailBodyGenericNotificationPublicChannel(t *testing.T) {
  1163  	th := Setup()
  1164  	defer th.TearDown()
  1165  
  1166  	recipient := &model.User{}
  1167  	post := &model.Post{
  1168  		Message: "This is the message",
  1169  	}
  1170  	channel := &model.Channel{
  1171  		DisplayName: "ChannelName",
  1172  		Type:        model.CHANNEL_OPEN,
  1173  	}
  1174  	senderName := "sender"
  1175  	teamName := "team"
  1176  	teamURL := "http://localhost:8065/" + teamName
  1177  	emailNotificationContentsType := model.EMAIL_NOTIFICATION_CONTENTS_GENERIC
  1178  	translateFunc := utils.GetUserTranslations("en")
  1179  
  1180  	body := th.App.getNotificationEmailBody(recipient, post, channel, senderName, teamName, teamURL, emailNotificationContentsType, translateFunc)
  1181  	if !strings.Contains(body, "You have a new notification from "+senderName) {
  1182  		t.Fatal("Expected email text 'You have a new notification from " + senderName + "'. Got " + body)
  1183  	}
  1184  	if strings.Contains(body, "CHANNEL: "+channel.DisplayName) {
  1185  		t.Fatal("Did not expect email text 'CHANNEL: " + channel.DisplayName + "'. Got " + body)
  1186  	}
  1187  	if strings.Contains(body, post.Message) {
  1188  		t.Fatal("Did not expect email text '" + post.Message + "'. Got " + body)
  1189  	}
  1190  	if !strings.Contains(body, teamURL) {
  1191  		t.Fatal("Expected email text '" + teamURL + "'. Got " + body)
  1192  	}
  1193  }
  1194  
  1195  func TestGetNotificationEmailBodyGenericNotificationGroupChannel(t *testing.T) {
  1196  	th := Setup()
  1197  	defer th.TearDown()
  1198  
  1199  	recipient := &model.User{}
  1200  	post := &model.Post{
  1201  		Message: "This is the message",
  1202  	}
  1203  	channel := &model.Channel{
  1204  		DisplayName: "ChannelName",
  1205  		Type:        model.CHANNEL_GROUP,
  1206  	}
  1207  	senderName := "sender"
  1208  	teamName := "team"
  1209  	teamURL := "http://localhost:8065/" + teamName
  1210  	emailNotificationContentsType := model.EMAIL_NOTIFICATION_CONTENTS_GENERIC
  1211  	translateFunc := utils.GetUserTranslations("en")
  1212  
  1213  	body := th.App.getNotificationEmailBody(recipient, post, channel, senderName, teamName, teamURL, emailNotificationContentsType, translateFunc)
  1214  	if !strings.Contains(body, "You have a new notification from "+senderName) {
  1215  		t.Fatal("Expected email text 'You have a new notification from " + senderName + "'. Got " + body)
  1216  	}
  1217  	if strings.Contains(body, "CHANNEL: "+channel.DisplayName) {
  1218  		t.Fatal("Did not expect email text 'CHANNEL: " + channel.DisplayName + "'. Got " + body)
  1219  	}
  1220  	if strings.Contains(body, post.Message) {
  1221  		t.Fatal("Did not expect email text '" + post.Message + "'. Got " + body)
  1222  	}
  1223  	if !strings.Contains(body, teamURL) {
  1224  		t.Fatal("Expected email text '" + teamURL + "'. Got " + body)
  1225  	}
  1226  }
  1227  
  1228  func TestGetNotificationEmailBodyGenericNotificationPrivateChannel(t *testing.T) {
  1229  	th := Setup()
  1230  	defer th.TearDown()
  1231  
  1232  	recipient := &model.User{}
  1233  	post := &model.Post{
  1234  		Message: "This is the message",
  1235  	}
  1236  	channel := &model.Channel{
  1237  		DisplayName: "ChannelName",
  1238  		Type:        model.CHANNEL_PRIVATE,
  1239  	}
  1240  	senderName := "sender"
  1241  	teamName := "team"
  1242  	teamURL := "http://localhost:8065/" + teamName
  1243  	emailNotificationContentsType := model.EMAIL_NOTIFICATION_CONTENTS_GENERIC
  1244  	translateFunc := utils.GetUserTranslations("en")
  1245  
  1246  	body := th.App.getNotificationEmailBody(recipient, post, channel, senderName, teamName, teamURL, emailNotificationContentsType, translateFunc)
  1247  	if !strings.Contains(body, "You have a new notification from "+senderName) {
  1248  		t.Fatal("Expected email text 'You have a new notification from " + senderName + "'. Got " + body)
  1249  	}
  1250  	if strings.Contains(body, "CHANNEL: "+channel.DisplayName) {
  1251  		t.Fatal("Did not expect email text 'CHANNEL: " + channel.DisplayName + "'. Got " + body)
  1252  	}
  1253  	if strings.Contains(body, post.Message) {
  1254  		t.Fatal("Did not expect email text '" + post.Message + "'. Got " + body)
  1255  	}
  1256  	if !strings.Contains(body, teamURL) {
  1257  		t.Fatal("Expected email text '" + teamURL + "'. Got " + body)
  1258  	}
  1259  }
  1260  
  1261  func TestGetNotificationEmailBodyGenericNotificationDirectChannel(t *testing.T) {
  1262  	th := Setup()
  1263  	defer th.TearDown()
  1264  
  1265  	recipient := &model.User{}
  1266  	post := &model.Post{
  1267  		Message: "This is the message",
  1268  	}
  1269  	channel := &model.Channel{
  1270  		DisplayName: "ChannelName",
  1271  		Type:        model.CHANNEL_DIRECT,
  1272  	}
  1273  	senderName := "sender"
  1274  	teamName := "team"
  1275  	teamURL := "http://localhost:8065/" + teamName
  1276  	emailNotificationContentsType := model.EMAIL_NOTIFICATION_CONTENTS_GENERIC
  1277  	translateFunc := utils.GetUserTranslations("en")
  1278  
  1279  	body := th.App.getNotificationEmailBody(recipient, post, channel, senderName, teamName, teamURL, emailNotificationContentsType, translateFunc)
  1280  	if !strings.Contains(body, "You have a new direct message from "+senderName) {
  1281  		t.Fatal("Expected email text 'You have a new direct message from " + senderName + "'. Got " + body)
  1282  	}
  1283  	if strings.Contains(body, "CHANNEL: "+channel.DisplayName) {
  1284  		t.Fatal("Did not expect email text 'CHANNEL: " + channel.DisplayName + "'. Got " + body)
  1285  	}
  1286  	if strings.Contains(body, post.Message) {
  1287  		t.Fatal("Did not expect email text '" + post.Message + "'. Got " + body)
  1288  	}
  1289  	if !strings.Contains(body, teamURL) {
  1290  		t.Fatal("Expected email text '" + teamURL + "'. Got " + body)
  1291  	}
  1292  }
  1293  
  1294  func TestGetPushNotificationMessage(t *testing.T) {
  1295  	th := Setup()
  1296  	defer th.TearDown()
  1297  
  1298  	for name, tc := range map[string]struct {
  1299  		Message                  string
  1300  		WasMentioned             bool
  1301  		HasFiles                 bool
  1302  		Locale                   string
  1303  		PushNotificationContents string
  1304  		ChannelType              string
  1305  
  1306  		ExpectedMessage  string
  1307  		ExpectedCategory string
  1308  	}{
  1309  		"full message, public channel, no mention": {
  1310  			Message:          "this is a message",
  1311  			ChannelType:      model.CHANNEL_OPEN,
  1312  			ExpectedMessage:  "user in channel: this is a message",
  1313  			ExpectedCategory: model.CATEGORY_CAN_REPLY,
  1314  		},
  1315  		"full message, public channel, mention": {
  1316  			Message:          "this is a message",
  1317  			WasMentioned:     true,
  1318  			ChannelType:      model.CHANNEL_OPEN,
  1319  			ExpectedMessage:  "user in channel: this is a message",
  1320  			ExpectedCategory: model.CATEGORY_CAN_REPLY,
  1321  		},
  1322  		"full message, private channel, no mention": {
  1323  			Message:          "this is a message",
  1324  			ChannelType:      model.CHANNEL_PRIVATE,
  1325  			ExpectedMessage:  "user in channel: this is a message",
  1326  			ExpectedCategory: model.CATEGORY_CAN_REPLY,
  1327  		},
  1328  		"full message, private channel, mention": {
  1329  			Message:          "this is a message",
  1330  			WasMentioned:     true,
  1331  			ChannelType:      model.CHANNEL_PRIVATE,
  1332  			ExpectedMessage:  "user in channel: this is a message",
  1333  			ExpectedCategory: model.CATEGORY_CAN_REPLY,
  1334  		},
  1335  		"full message, group message channel, no mention": {
  1336  			Message:          "this is a message",
  1337  			ChannelType:      model.CHANNEL_GROUP,
  1338  			ExpectedMessage:  "user in channel: this is a message",
  1339  			ExpectedCategory: model.CATEGORY_CAN_REPLY,
  1340  		},
  1341  		"full message, group message channel, mention": {
  1342  			Message:          "this is a message",
  1343  			WasMentioned:     true,
  1344  			ChannelType:      model.CHANNEL_GROUP,
  1345  			ExpectedMessage:  "user in channel: this is a message",
  1346  			ExpectedCategory: model.CATEGORY_CAN_REPLY,
  1347  		},
  1348  		"full message, direct message channel, no mention": {
  1349  			Message:          "this is a message",
  1350  			ChannelType:      model.CHANNEL_DIRECT,
  1351  			ExpectedMessage:  "user: this is a message",
  1352  			ExpectedCategory: model.CATEGORY_CAN_REPLY,
  1353  		},
  1354  		"full message, direct message channel, mention": {
  1355  			Message:          "this is a message",
  1356  			WasMentioned:     true,
  1357  			ChannelType:      model.CHANNEL_DIRECT,
  1358  			ExpectedMessage:  "user: this is a message",
  1359  			ExpectedCategory: model.CATEGORY_CAN_REPLY,
  1360  		},
  1361  		"generic message with channel, public channel, no mention": {
  1362  			Message:                  "this is a message",
  1363  			PushNotificationContents: model.GENERIC_NOTIFICATION,
  1364  			ChannelType:              model.CHANNEL_OPEN,
  1365  			ExpectedMessage:          "user posted in channel",
  1366  		},
  1367  		"generic message with channel, public channel, mention": {
  1368  			Message:                  "this is a message",
  1369  			WasMentioned:             true,
  1370  			PushNotificationContents: model.GENERIC_NOTIFICATION,
  1371  			ChannelType:              model.CHANNEL_OPEN,
  1372  			ExpectedMessage:          "user mentioned you in channel",
  1373  			ExpectedCategory:         model.CATEGORY_CAN_REPLY,
  1374  		},
  1375  		"generic message with channel, private channel, no mention": {
  1376  			Message:                  "this is a message",
  1377  			PushNotificationContents: model.GENERIC_NOTIFICATION,
  1378  			ChannelType:              model.CHANNEL_PRIVATE,
  1379  			ExpectedMessage:          "user posted in channel",
  1380  		},
  1381  		"generic message with channel, private channel, mention": {
  1382  			Message:                  "this is a message",
  1383  			WasMentioned:             true,
  1384  			PushNotificationContents: model.GENERIC_NOTIFICATION,
  1385  			ChannelType:              model.CHANNEL_PRIVATE,
  1386  			ExpectedMessage:          "user mentioned you in channel",
  1387  			ExpectedCategory:         model.CATEGORY_CAN_REPLY,
  1388  		},
  1389  		"generic message with channel, group message channel, no mention": {
  1390  			Message:                  "this is a message",
  1391  			PushNotificationContents: model.GENERIC_NOTIFICATION,
  1392  			ChannelType:              model.CHANNEL_GROUP,
  1393  			ExpectedMessage:          "user posted in channel",
  1394  		},
  1395  		"generic message with channel, group message channel, mention": {
  1396  			Message:                  "this is a message",
  1397  			WasMentioned:             true,
  1398  			PushNotificationContents: model.GENERIC_NOTIFICATION,
  1399  			ChannelType:              model.CHANNEL_GROUP,
  1400  			ExpectedMessage:          "user mentioned you in channel",
  1401  			ExpectedCategory:         model.CATEGORY_CAN_REPLY,
  1402  		},
  1403  		"generic message with channel, direct message channel, no mention": {
  1404  			Message:                  "this is a message",
  1405  			PushNotificationContents: model.GENERIC_NOTIFICATION,
  1406  			ChannelType:              model.CHANNEL_DIRECT,
  1407  			ExpectedMessage:          "user sent you a direct message",
  1408  			ExpectedCategory:         model.CATEGORY_CAN_REPLY,
  1409  		},
  1410  		"generic message with channel, direct message channel, mention": {
  1411  			Message:                  "this is a message",
  1412  			WasMentioned:             true,
  1413  			PushNotificationContents: model.GENERIC_NOTIFICATION,
  1414  			ChannelType:              model.CHANNEL_DIRECT,
  1415  			ExpectedMessage:          "user sent you a direct message",
  1416  			ExpectedCategory:         model.CATEGORY_CAN_REPLY,
  1417  		},
  1418  		"generic message without channel, public channel, no mention": {
  1419  			Message:                  "this is a message",
  1420  			PushNotificationContents: model.GENERIC_NO_CHANNEL_NOTIFICATION,
  1421  			ChannelType:              model.CHANNEL_OPEN,
  1422  			ExpectedMessage:          "user posted a message",
  1423  		},
  1424  		"generic message without channel, public channel, mention": {
  1425  			Message:                  "this is a message",
  1426  			WasMentioned:             true,
  1427  			PushNotificationContents: model.GENERIC_NO_CHANNEL_NOTIFICATION,
  1428  			ChannelType:              model.CHANNEL_OPEN,
  1429  			ExpectedMessage:          "user mentioned you",
  1430  		},
  1431  		"generic message without channel, private channel, no mention": {
  1432  			Message:                  "this is a message",
  1433  			PushNotificationContents: model.GENERIC_NO_CHANNEL_NOTIFICATION,
  1434  			ChannelType:              model.CHANNEL_PRIVATE,
  1435  			ExpectedMessage:          "user posted a message",
  1436  		},
  1437  		"generic message without channel, private channel, mention": {
  1438  			Message:                  "this is a message",
  1439  			WasMentioned:             true,
  1440  			PushNotificationContents: model.GENERIC_NO_CHANNEL_NOTIFICATION,
  1441  			ChannelType:              model.CHANNEL_PRIVATE,
  1442  			ExpectedMessage:          "user mentioned you",
  1443  		},
  1444  		"generic message without channel, group message channel, no mention": {
  1445  			Message:                  "this is a message",
  1446  			PushNotificationContents: model.GENERIC_NO_CHANNEL_NOTIFICATION,
  1447  			ChannelType:              model.CHANNEL_GROUP,
  1448  			ExpectedMessage:          "user posted a message",
  1449  		},
  1450  		"generic message without channel, group message channel, mention": {
  1451  			Message:                  "this is a message",
  1452  			WasMentioned:             true,
  1453  			PushNotificationContents: model.GENERIC_NO_CHANNEL_NOTIFICATION,
  1454  			ChannelType:              model.CHANNEL_GROUP,
  1455  			ExpectedMessage:          "user mentioned you",
  1456  		},
  1457  		"generic message without channel, direct message channel, no mention": {
  1458  			Message:                  "this is a message",
  1459  			PushNotificationContents: model.GENERIC_NO_CHANNEL_NOTIFICATION,
  1460  			ChannelType:              model.CHANNEL_DIRECT,
  1461  			ExpectedMessage:          "user sent you a direct message",
  1462  			ExpectedCategory:         model.CATEGORY_CAN_REPLY,
  1463  		},
  1464  		"generic message without channel, direct message channel, mention": {
  1465  			Message:                  "this is a message",
  1466  			WasMentioned:             true,
  1467  			PushNotificationContents: model.GENERIC_NO_CHANNEL_NOTIFICATION,
  1468  			ChannelType:              model.CHANNEL_DIRECT,
  1469  			ExpectedMessage:          "user sent you a direct message",
  1470  			ExpectedCategory:         model.CATEGORY_CAN_REPLY,
  1471  		},
  1472  		"only files, public channel": {
  1473  			HasFiles:         true,
  1474  			ChannelType:      model.CHANNEL_OPEN,
  1475  			ExpectedMessage:  "user uploaded one or more files in channel",
  1476  			ExpectedCategory: model.CATEGORY_CAN_REPLY,
  1477  		},
  1478  		"only files, private channel": {
  1479  			HasFiles:         true,
  1480  			ChannelType:      model.CHANNEL_PRIVATE,
  1481  			ExpectedMessage:  "user uploaded one or more files in channel",
  1482  			ExpectedCategory: model.CATEGORY_CAN_REPLY,
  1483  		},
  1484  		"only files, group message channel": {
  1485  			HasFiles:         true,
  1486  			ChannelType:      model.CHANNEL_GROUP,
  1487  			ExpectedMessage:  "user uploaded one or more files in channel",
  1488  			ExpectedCategory: model.CATEGORY_CAN_REPLY,
  1489  		},
  1490  		"only files, direct message channel": {
  1491  			HasFiles:         true,
  1492  			ChannelType:      model.CHANNEL_DIRECT,
  1493  			ExpectedMessage:  "user uploaded one or more files in a direct message",
  1494  			ExpectedCategory: model.CATEGORY_CAN_REPLY,
  1495  		},
  1496  		"only files without channel, public channel": {
  1497  			HasFiles:                 true,
  1498  			PushNotificationContents: model.GENERIC_NO_CHANNEL_NOTIFICATION,
  1499  			ChannelType:              model.CHANNEL_OPEN,
  1500  			ExpectedMessage:          "user uploaded one or more files",
  1501  		},
  1502  	} {
  1503  		t.Run(name, func(t *testing.T) {
  1504  			locale := tc.Locale
  1505  			if locale == "" {
  1506  				locale = "en"
  1507  			}
  1508  
  1509  			pushNotificationContents := tc.PushNotificationContents
  1510  			if pushNotificationContents == "" {
  1511  				pushNotificationContents = model.FULL_NOTIFICATION
  1512  			}
  1513  
  1514  			th.App.UpdateConfig(func(cfg *model.Config) {
  1515  				*cfg.EmailSettings.PushNotificationContents = pushNotificationContents
  1516  			})
  1517  
  1518  			if actualMessage, actualCategory := th.App.getPushNotificationMessage(
  1519  				tc.Message,
  1520  				tc.WasMentioned,
  1521  				tc.HasFiles,
  1522  				"user",
  1523  				"channel",
  1524  				tc.ChannelType,
  1525  				utils.GetUserTranslations(locale),
  1526  			); actualMessage != tc.ExpectedMessage {
  1527  				t.Fatalf("Received incorrect push notification message `%v`, expected `%v`", actualMessage, tc.ExpectedMessage)
  1528  			} else if actualCategory != tc.ExpectedCategory {
  1529  				t.Fatalf("Received incorrect push notification category `%v`, expected `%v`", actualCategory, tc.ExpectedCategory)
  1530  			}
  1531  		})
  1532  	}
  1533  }