MM-11272 Added initial post metadata (#9175)

* MM-11272 Added app.PreparePostForClient

* MM-11272 Added app.PreparePostListForClient

* MM-11272 Added EmojiStore.GetMultipleByName

* MM-11272 Added emojis to PreparePostForClient

* MM-11272 Added unit tests for getting reaction counts

* MM-11272 Added unit tests for TestPreparePostForClient

* MM-11272 Added emojis from reactions to Post.Emojis

* MM-11272 Always update post.UpdateAt when reactions change to bust cache

* Fixed merge conflicts

* Moved post metadata-related code into its own file

* Update store mocks

* Fixed typo

* Add missing license headers

* Updated post metadata tests when custom emojis are disabled

* Fix unreliable unit tests

* Fix inconsistent casing in SQL statements

* Fix blank line

* Invalidate store cache after making changes

* Clear post cache synchronously with reactions
Этот коммит содержится в:
Harrison Healey
2018-08-07 16:24:56 -04:00
родитель 2e945e287d
Коммит 48f16b6401
27 изменённых файлов: 902 добавлений и 87 удалений

Просмотреть файл

@@ -7,6 +7,7 @@ import (
"encoding/json"
"io"
"net/http"
"regexp"
)
const (
@@ -14,6 +15,8 @@ const (
EMOJI_SORT_BY_NAME = "name"
)
var EMOJI_PATTERN = regexp.MustCompile(`:[a-zA-Z0-9_-]+:`)
type Emoji struct {
Id string `json:"id"`
CreateAt int64 `json:"create_at"`

Просмотреть файл

@@ -11,6 +11,7 @@ import (
"strings"
"unicode/utf8"
"github.com/dyatlov/go-opengraph/opengraph"
"github.com/mattermost/mattermost-server/utils/markdown"
)
@@ -78,9 +79,22 @@ type Post struct {
Props StringInterface `json:"props"`
Hashtags string `json:"hashtags"`
Filenames StringArray `json:"filenames,omitempty"` // Deprecated, do not use this field any more
FileIds StringArray `json:"file_ids,omitempty"`
FileIds StringArray `json:"file_ids,omitempty"` // Deprecated, do not use this field any more
PendingPostId string `json:"pending_post_id" db:"-"`
HasReactions bool `json:"has_reactions,omitempty"`
HasReactions bool `json:"has_reactions,omitempty"` // Deprecated, do not use this field any more
// Transient fields populated before sending posts to the client
ReactionCounts ReactionCounts `json:"reaction_counts" db:"-"`
FileInfos []*FileInfo `json:"file_infos" db:"-"`
ImageDimensions []*PostImageDimensions `json:"image_dimensions" db:"-"`
OpenGraphData []*opengraph.OpenGraph `json:"opengraph_data" db:"-"`
Emojis []*Emoji `json:"emojis" db:"-"`
}
type PostImageDimensions struct {
URL string `json:"url"`
Width int64 `json:"width"`
Height int64 `json:"height"`
}
type PostEphemeral struct {
@@ -170,10 +184,16 @@ type PostActionIntegrationResponse struct {
EphemeralText string `json:"ephemeral_text"`
}
func (o *Post) ToJson() string {
// Shallowly clone the a post
func (o *Post) Clone() *Post {
copy := *o
return &copy
}
func (o *Post) ToJson() string {
copy := o.Clone()
copy.StripActionIntegrations()
b, _ := json.Marshal(&copy)
b, _ := json.Marshal(copy)
return string(b)
}
@@ -502,12 +522,12 @@ var markdownDestinationEscaper = strings.NewReplacer(
// WithRewrittenImageURLs returns a new shallow copy of the post where the message has been
// rewritten via RewriteImageURLs.
func (o *Post) WithRewrittenImageURLs(f func(string) string) *Post {
copy := *o
copy := o.Clone()
copy.Message = RewriteImageURLs(o.Message, f)
if copy.MessageSource == "" && copy.Message != o.Message {
copy.MessageSource = o.Message
}
return &copy
return copy
}
func (o *PostEphemeral) ToUnsanitizedJson() string {

Просмотреть файл

@@ -17,6 +17,8 @@ type Reaction struct {
CreateAt int64 `json:"create_at"`
}
type ReactionCounts map[string]int
func (o *Reaction) ToJson() string {
b, _ := json.Marshal(o)
return string(b)
@@ -74,3 +76,13 @@ func (o *Reaction) PreSave() {
o.CreateAt = GetMillis()
}
}
func CountReactions(reactions []*Reaction) ReactionCounts {
reactionCounts := ReactionCounts{}
for _, reaction := range reactions {
reactionCounts[reaction.EmojiName] += 1
}
return reactionCounts
}

Просмотреть файл

@@ -82,3 +82,38 @@ func TestReactionIsValid(t *testing.T) {
t.Fatal("create at should be invalid")
}
}
func TestCountReactions(t *testing.T) {
userId := NewId()
userId2 := NewId()
reactions := []*Reaction{
{
UserId: userId,
EmojiName: "smile",
},
{
UserId: userId,
EmojiName: "frowning",
},
{
UserId: userId2,
EmojiName: "smile",
},
{
UserId: userId2,
EmojiName: "neutral_face",
},
}
reactionCounts := CountReactions(reactions)
if len(reactionCounts) != 3 {
t.Fatal("should've received counts for 3 reactions")
} else if reactionCounts["smile"] != 2 {
t.Fatal("should've received 2 smile reactions")
} else if reactionCounts["frowning"] != 1 {
t.Fatal("should've received 1 frowning reaction")
} else if reactionCounts["neutral_face"] != 1 {
t.Fatal("should've received 2 neutral_face reaction")
}
}