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>
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
56be6b539c
Коммит
21639f9c87
93
app/post.go
93
app/post.go
@@ -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)
|
||||
|
||||
Ссылка в новой задаче
Block a user