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
@@ -303,6 +303,7 @@ type ServiceSettings struct {
|
||||
GoogleDeveloperKey *string `access:"site_posts,write_restrictable,cloud_restrictable"`
|
||||
DEPRECATED_DO_NOT_USE_EnableOnlyAdminIntegrations *bool `json:"EnableOnlyAdminIntegrations" mapstructure:"EnableOnlyAdminIntegrations"` // Deprecated: do not use
|
||||
EnableLinkPreviews *bool `access:"site_posts"`
|
||||
EnablePermalinkPreviews *bool `access:"site_posts"`
|
||||
RestrictLinkPreviews *string `access:"site_posts"`
|
||||
EnableTesting *bool `access:"environment_developer,write_restrictable,cloud_restrictable"`
|
||||
EnableDeveloper *bool `access:"environment_developer,write_restrictable,cloud_restrictable"`
|
||||
@@ -413,6 +414,10 @@ func (s *ServiceSettings) SetDefaults(isUpdate bool) {
|
||||
s.EnableLinkPreviews = NewBool(true)
|
||||
}
|
||||
|
||||
if s.EnablePermalinkPreviews == nil {
|
||||
s.EnablePermalinkPreviews = NewBool(true)
|
||||
}
|
||||
|
||||
if s.RestrictLinkPreviews == nil {
|
||||
s.RestrictLinkPreviews = NewString("")
|
||||
}
|
||||
|
||||
@@ -36,6 +36,8 @@ type FeatureFlags struct {
|
||||
// Enable timed dnd support for user status
|
||||
TimedDND bool
|
||||
|
||||
PermalinkPreviews bool
|
||||
|
||||
// Enable the Global Header
|
||||
GlobalHeader bool
|
||||
|
||||
@@ -54,6 +56,7 @@ func (f *FeatureFlags) SetDefaults() {
|
||||
f.PluginApps = ""
|
||||
f.PluginFocalboard = ""
|
||||
f.TimedDND = false
|
||||
f.PermalinkPreviews = true
|
||||
f.GlobalHeader = false
|
||||
f.InviteMembersButton = "none"
|
||||
}
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
|
||||
package model
|
||||
|
||||
import "encoding/json"
|
||||
|
||||
type MessageExport struct {
|
||||
TeamId *string
|
||||
TeamName *string
|
||||
@@ -34,3 +36,15 @@ type MessageExportCursor struct {
|
||||
LastPostUpdateAt int64
|
||||
LastPostId string
|
||||
}
|
||||
|
||||
// PreviewID returns the value of the post's previewed_post prop, if present, or an empty string.
|
||||
func (m *MessageExport) PreviewID() string {
|
||||
var previewID string
|
||||
props := map[string]interface{}{}
|
||||
if m.PostProps != nil && json.Unmarshal([]byte(*m.PostProps), &props) == nil {
|
||||
if val, ok := props[PostPropsPreviewedPost]; ok {
|
||||
previewID = val.(string)
|
||||
}
|
||||
}
|
||||
return previewID
|
||||
}
|
||||
|
||||
34
model/permalink.go
Обычный файл
34
model/permalink.go
Обычный файл
@@ -0,0 +1,34 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package model
|
||||
|
||||
import "encoding/json"
|
||||
|
||||
type Permalink struct {
|
||||
PreviewPost *PreviewPost `json:"preview_post"`
|
||||
}
|
||||
|
||||
type PreviewPost struct {
|
||||
PostID string `json:"post_id"`
|
||||
Post *Post `json:"post"`
|
||||
TeamName string `json:"team_name"`
|
||||
ChannelDisplayName string `json:"channel_display_name"`
|
||||
}
|
||||
|
||||
func NewPreviewPost(post *Post, team *Team, channel *Channel) *PreviewPost {
|
||||
if post == nil {
|
||||
return nil
|
||||
}
|
||||
return &PreviewPost{
|
||||
PostID: post.Id,
|
||||
Post: post,
|
||||
TeamName: team.Name,
|
||||
ChannelDisplayName: channel.DisplayName,
|
||||
}
|
||||
}
|
||||
|
||||
func (o *Permalink) ToJson() string {
|
||||
b, _ := json.Marshal(o)
|
||||
return string(b)
|
||||
}
|
||||
@@ -67,6 +67,8 @@ const (
|
||||
|
||||
PostPropsMentionHighlightDisabled = "mentionHighlightDisabled"
|
||||
PostPropsGroupHighlightDisabled = "disable_group_highlight"
|
||||
|
||||
PostPropsPreviewedPost = "previewed_post"
|
||||
)
|
||||
|
||||
type Post struct {
|
||||
@@ -749,3 +751,14 @@ func (o *Post) ToNilIfInvalid() *Post {
|
||||
}
|
||||
return o
|
||||
}
|
||||
|
||||
func (o *Post) GetPreviewPost() *PreviewPost {
|
||||
for _, embed := range o.Metadata.Embeds {
|
||||
if embed.Type == PostEmbedPermalink {
|
||||
if previewPost, ok := embed.Data.(*PreviewPost); ok {
|
||||
return previewPost
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ const (
|
||||
PostEmbedMessageAttachment PostEmbedType = "message_attachment"
|
||||
PostEmbedOpengraph PostEmbedType = "opengraph"
|
||||
PostEmbedLink PostEmbedType = "link"
|
||||
PostEmbedPermalink PostEmbedType = "permalink"
|
||||
)
|
||||
|
||||
type PostEmbedType string
|
||||
|
||||
@@ -25,6 +25,23 @@ func NewPostList() *PostList {
|
||||
}
|
||||
}
|
||||
|
||||
func (o *PostList) Clone() *PostList {
|
||||
orderCopy := make([]string, len(o.Order))
|
||||
postsCopy := make(map[string]*Post)
|
||||
for i, v := range o.Order {
|
||||
orderCopy[i] = v
|
||||
}
|
||||
for k, v := range o.Posts {
|
||||
postsCopy[k] = v.Clone()
|
||||
}
|
||||
return &PostList{
|
||||
Order: orderCopy,
|
||||
Posts: postsCopy,
|
||||
NextPostId: o.NextPostId,
|
||||
PrevPostId: o.PrevPostId,
|
||||
}
|
||||
}
|
||||
|
||||
func (o *PostList) ToSlice() []*Post {
|
||||
var posts []*Post
|
||||
|
||||
|
||||
Ссылка в новой задаче
Block a user