MM-22845: Added support for permalink previews. (#17796)

* MM-22845: Added support for permalink previews.

* MM-22845: Adds license to new file.

* MM-22845: Adds endpoint to retrieve multiple posts by id.

* MM-22845: Fix for deleted post.

* MM-22845: Adds config setting for permalink previews.

* MM-22845: Adds API test for new endpoint.

* MM-22845: Fix typo.

* MM-22845: Tests that post create or updated via App get the previewed_post prop.

* MM-22845: Tests for matching permalinks.

* MM-22845: Adds PreparePostForClient test for permalink previews.

* MM-22845: Embeds entire post in permalink metadata.

* MM-22845: Filter WS message payload of created and edited post based on permissions.

* MM-22845: Runs app layer generator.

* MM-22845: Lint check fix.

* MM-22845: Adds feature flag.

* MM-22845: Clones WS message.

* MM-22845: Removes knowledge of permalink from LinkMetadata table. Removes knowledge of user id from post embedding methods in favour of a 'sanitize' method/step.

* MM-22845: Handle nil post metadata.

* MM-22845: Switch to cloning post.

* MM-22845: Removes unused code.

* MM-22845: Refactor.

* MM-22845: Reverts whitespace change.

* MM-22845: Removes unnecessary code.

* MM-22845: Removes unnecessary function.

* MM-22845: Warn but don't error if permalinked referenced post or channel is not found.

* MM-22845: Fix for clone method.

* MM-22845: Fix for clone method.

* MM-22845: Updates translations.

Co-authored-by: Mattermod <mattermod@users.noreply.github.com>
Этот коммит содержится в:
Martin Kraft
2021-08-09 11:33:21 -04:00
коммит произвёл GitHub
родитель 56be6b539c
Коммит 21639f9c87
28 изменённых файлов: 645 добавлений и 115 удалений

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

@@ -359,6 +359,11 @@ func (a *App) CreatePost(c *request.Context, post *model.Post, channel *model.Ch
// to be done when we send the post over the websocket in handlePostEvents
rpost = a.PreparePostForClient(rpost, true, false)
rpost, nErr = a.addPostPreviewProp(rpost)
if nErr != nil {
return nil, model.NewAppError("CreatePost", "app.post.save.app_error", nil, nErr.Error(), http.StatusInternalServerError)
}
// Make sure poster is following the thread
if *a.Config().ServiceSettings.ThreadAutoFollow && rpost.RootId != "" {
_, err := a.Srv().Store.Thread().MaintainMembership(user.Id, rpost.RootId, store.ThreadMembershipOpts{
@@ -379,9 +384,25 @@ func (a *App) CreatePost(c *request.Context, post *model.Post, channel *model.Ch
a.SendEphemeralPost(post.UserId, ephemeralPost)
}
rpost, err = a.SanitizePostMetadataForUser(rpost, c.Session().UserId)
if err != nil {
return nil, err
}
return rpost, nil
}
func (a *App) addPostPreviewProp(post *model.Post) (*model.Post, error) {
previewPost := post.GetPreviewPost()
if previewPost != nil {
updatedPost := post.Clone()
updatedPost.AddProp(model.PostPropsPreviewedPost, previewPost.PostID)
updatedPost, err := a.Srv().Store.Post().Update(updatedPost, post)
return updatedPost, err
}
return post, nil
}
func (a *App) attachFilesToPost(post *model.Post) *model.AppError {
var attachedIds []string
for _, fileID := range post.FileIds {
@@ -671,15 +692,79 @@ func (a *App) UpdatePost(c *request.Context, post *model.Post, safeUpdate bool)
// individually.
rpost.IsFollowing = nil
rpost, nErr = a.addPostPreviewProp(rpost)
if nErr != nil {
return nil, model.NewAppError("UpdatePost", "app.post.update.app_error", nil, nErr.Error(), http.StatusInternalServerError)
}
message := model.NewWebSocketEvent(model.WebsocketEventPostEdited, "", rpost.ChannelId, "", nil)
message.Add("post", rpost.ToJson())
a.Publish(message)
published, err := a.publishWebsocketEventForPermalinkPost(rpost, message)
if err != nil {
return nil, err
}
if !published {
a.Publish(message)
}
a.invalidateCacheForChannelPosts(rpost.ChannelId)
return rpost, nil
}
func (a *App) publishWebsocketEventForPermalinkPost(post *model.Post, message *model.WebSocketEvent) (published bool, err *model.AppError) {
var previewedPostID string
if val, ok := post.GetProp(model.PostPropsPreviewedPost).(string); ok {
previewedPostID = val
} else {
return false, nil
}
if !model.IsValidId(previewedPostID) {
mlog.Warn("invalid post prop value", mlog.String("prop_key", model.PostPropsPreviewedPost), mlog.String("prop_value", previewedPostID))
return false, nil
}
previewedPost, err := a.GetSinglePost(previewedPostID)
if err != nil {
if err.StatusCode == http.StatusNotFound {
mlog.Warn("permalinked post not found", mlog.String("referenced_post_id", previewedPostID))
return false, nil
}
return false, err
}
previewedChannel, err := a.GetChannel(previewedPost.ChannelId)
if err != nil {
if err.StatusCode == http.StatusNotFound {
mlog.Warn("channel containing permalinked post not found", mlog.String("referenced_channel_id", previewedPost.ChannelId))
return false, nil
}
return false, err
}
channelMembers, err := a.GetChannelMembersPage(post.ChannelId, 0, 10000000)
if err != nil {
return false, err
}
for _, cm := range *channelMembers {
postForUser := post.Clone()
if !a.HasPermissionToReadChannel(cm.UserId, previewedChannel) {
postForUser.Metadata.Embeds[0].Data = nil
}
messageCopy := message.Copy()
broadcastCopy := messageCopy.GetBroadcast()
broadcastCopy.UserId = cm.UserId
messageCopy.SetBroadcast(broadcastCopy)
messageCopy.Add("post", postForUser.ToJson())
a.Publish(messageCopy)
}
return true, nil
}
func (a *App) PatchPost(c *request.Context, postID string, patch *model.PostPatch) (*model.Post, *model.AppError) {
post, err := a.GetSinglePost(postID)
if err != nil {
@@ -1063,15 +1148,13 @@ func (a *App) DeletePost(postID, deleteByID string) (*model.Post, *model.AppErro
}
}
postData := a.PreparePostForClient(post, false, false).ToJson()
userMessage := model.NewWebSocketEvent(model.WebsocketEventPostDeleted, "", post.ChannelId, "", nil)
userMessage.Add("post", postData)
userMessage.Add("post", post)
userMessage.GetBroadcast().ContainsSanitizedData = true
a.Publish(userMessage)
adminMessage := model.NewWebSocketEvent(model.WebsocketEventPostDeleted, "", post.ChannelId, "", nil)
adminMessage.Add("post", postData)
adminMessage.Add("post", post)
adminMessage.Add("delete_by", deleteByID)
adminMessage.GetBroadcast().ContainsSensitiveData = true
a.Publish(adminMessage)