Merge branch 'master' of github.com:mattermost/mattermost-server into top-dms-clean

Этот коммит содержится в:
Shivashis Padhi
2022-07-27 17:03:34 +05:30
родитель db192aff1b eba08cbb11
Коммит 849aea452c
79 изменённых файлов: 1724 добавлений и 381 удалений

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

@@ -18,30 +18,30 @@ import (
)
const (
HeaderRequestId = "X-Request-ID"
HeaderVersionId = "X-Version-ID"
HeaderClusterId = "X-Cluster-ID"
HeaderEtagServer = "ETag"
HeaderEtagClient = "If-None-Match"
HeaderForwarded = "X-Forwarded-For"
HeaderRealIP = "X-Real-IP"
HeaderForwardedProto = "X-Forwarded-Proto"
HeaderToken = "token"
HeaderCsrfToken = "X-CSRF-Token"
HeaderBearer = "BEARER"
HeaderAuth = "Authorization"
HeaderCloudToken = "X-Cloud-Token"
HeaderRemoteclusterToken = "X-RemoteCluster-Token"
HeaderRemoteclusterId = "X-RemoteCluster-Id"
HeaderRequestedWith = "X-Requested-With"
HeaderRequestedWithXML = "XMLHttpRequest"
HeaderHasInaccessiblePosts = "Has-Inaccessible-Posts"
HeaderRange = "Range"
STATUS = "status"
StatusOk = "OK"
StatusFail = "FAIL"
StatusUnhealthy = "UNHEALTHY"
StatusRemove = "REMOVE"
HeaderRequestId = "X-Request-ID"
HeaderVersionId = "X-Version-ID"
HeaderClusterId = "X-Cluster-ID"
HeaderEtagServer = "ETag"
HeaderEtagClient = "If-None-Match"
HeaderForwarded = "X-Forwarded-For"
HeaderRealIP = "X-Real-IP"
HeaderForwardedProto = "X-Forwarded-Proto"
HeaderToken = "token"
HeaderCsrfToken = "X-CSRF-Token"
HeaderBearer = "BEARER"
HeaderAuth = "Authorization"
HeaderCloudToken = "X-Cloud-Token"
HeaderRemoteclusterToken = "X-RemoteCluster-Token"
HeaderRemoteclusterId = "X-RemoteCluster-Id"
HeaderRequestedWith = "X-Requested-With"
HeaderRequestedWithXML = "XMLHttpRequest"
HeaderFirstInaccessiblePostTime = "First-Inaccessible-Post-Time"
HeaderRange = "Range"
STATUS = "status"
StatusOk = "OK"
StatusFail = "FAIL"
StatusUnhealthy = "UNHEALTHY"
StatusRemove = "REMOVE"
ClientDir = "client"
@@ -103,7 +103,7 @@ func (c *Client4) boolString(value bool) string {
func closeBody(r *http.Response) {
if r.Body != nil {
_, _ = io.Copy(ioutil.Discard, r.Body)
_, _ = io.Copy(io.Discard, r.Body)
_ = r.Body.Close()
}
}
@@ -3743,6 +3743,23 @@ func (c *Client4) SetPostUnread(userId string, postId string, collapsedThreadsSu
return BuildResponse(r), nil
}
// SetPostReminder creates a post reminder for a given post at a specified time.
// The time needs to be in UTC epoch in seconds. It is always truncated to a
// 5 minute resolution minimum.
func (c *Client4) SetPostReminder(reminder *PostReminder) (*Response, error) {
b, err := json.Marshal(reminder)
if err != nil {
return nil, NewAppError("SetPostReminder", "api.marshal_error", nil, err.Error(), http.StatusInternalServerError)
}
r, err := c.DoAPIPostBytes(c.userRoute(reminder.UserId)+c.postRoute(reminder.PostId)+"/reminder", b)
if err != nil {
return BuildResponse(r), err
}
defer closeBody(r)
return BuildResponse(r), nil
}
// PinPost pin a post based on provided post id string.
func (c *Client4) PinPost(postId string) (*Response, error) {
r, err := c.DoAPIPost(c.postRoute(postId)+"/pin", "")
@@ -4419,6 +4436,24 @@ func (c *Client4) GetFileInfosForPost(postId string, etag string) ([]*FileInfo,
return list, BuildResponse(r), nil
}
// GetFileInfosForPost gets all the file info objects attached to a post, including deleted
func (c *Client4) GetFileInfosForPostIncludeDeleted(postId string, etag string) ([]*FileInfo, *Response, error) {
r, err := c.DoAPIGet(c.postRoute(postId)+"/files/info"+"?include_deleted="+c.boolString(true), etag)
if err != nil {
return nil, BuildResponse(r), err
}
defer closeBody(r)
var list []*FileInfo
if r.StatusCode == http.StatusNotModified {
return list, BuildResponse(r), nil
}
if jsonErr := json.NewDecoder(r.Body).Decode(&list); jsonErr != nil {
return nil, nil, NewAppError("GetFileInfosForPostIncludeDeleted", "api.unmarshal_error", nil, jsonErr.Error(), http.StatusInternalServerError)
}
return list, BuildResponse(r), nil
}
// General/System Section
// GenerateSupportPacket downloads the generated support packet

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

@@ -67,10 +67,14 @@ type FeatureFlags struct {
CommandPalette bool
PostForwarding bool
AdvancedTextEditor bool
// Enable Boards as a product (multi-product architecture)
BoardsProduct bool
PlanUpgradeButtonText string
}
func (f *FeatureFlags) SetDefaults() {
@@ -94,9 +98,11 @@ func (f *FeatureFlags) SetDefaults() {
f.GraphQL = false
f.InsightsEnabled = true
f.CommandPalette = false
f.PostForwarding = false
f.AdvancedTextEditor = true
f.CallsEnabled = true
f.BoardsProduct = false
f.PlanUpgradeButtonText = "Upgrade"
}
func (f *FeatureFlags) Plugins() map[string]string {

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

@@ -141,7 +141,7 @@ func GetInfoForBytes(name string, data io.ReadSeeker, size int) (*FileInfo, *App
extension := strings.ToLower(filepath.Ext(name))
info.MimeType = mime.TypeByExtension(extension)
if extension != "" && extension[0] == '.' {
if extension != "" {
// The client expects a file extension without the leading period
info.Extension = extension[1:]
} else {

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

@@ -13,6 +13,7 @@ import (
"unicode/utf8"
"github.com/dyatlov/go-opengraph/opengraph"
"github.com/dyatlov/go-opengraph/opengraph/types/image"
)
const (
@@ -50,7 +51,7 @@ func truncateText(original string) string {
return original
}
func firstNImages(images []*opengraph.Image, maxImages int) []*opengraph.Image {
func firstNImages(images []*image.Image, maxImages int) []*image.Image {
if maxImages < 0 { // don't break stuff, if it's weird, go for sane defaults
maxImages = LinkMetadataMaxImages
}

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

@@ -11,14 +11,20 @@ import (
"unicode/utf8"
"github.com/dyatlov/go-opengraph/opengraph"
"github.com/dyatlov/go-opengraph/opengraph/types/article"
"github.com/dyatlov/go-opengraph/opengraph/types/audio"
"github.com/dyatlov/go-opengraph/opengraph/types/book"
"github.com/dyatlov/go-opengraph/opengraph/types/image"
"github.com/dyatlov/go-opengraph/opengraph/types/profile"
"github.com/dyatlov/go-opengraph/opengraph/types/video"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
const BigText = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus maximus faucibus ex, vitae placerat neque feugiat ac. Nam tempus libero quis pellentesque feugiat. Cras tristique diam vel condimentum viverra. Proin molestie posuere leo. Nam pulvinar, ex quis tristique cursus, turpis ante commodo elit, a dapibus est ipsum id eros. Mauris tortor dolor, posuere ac velit vitae, faucibus viverra fusce."
func sampleImage(imageName string) *opengraph.Image {
return &opengraph.Image{
func sampleImage(imageName string) *image.Image {
return &image.Image{
URL: fmt.Sprintf("http://example.com/%s", imageName),
SecureURL: fmt.Sprintf("https://example.com/%s", imageName),
Type: "png",
@@ -180,7 +186,7 @@ func TestLinkMetadataDeserializeDataToConcreteType(t *testing.T) {
og := &opengraph.OpenGraph{
URL: "http://example.com",
Description: "Hello, world!",
Images: []*opengraph.Image{
Images: []*image.Image{
{
URL: "http://example.com/image.png",
},
@@ -260,24 +266,24 @@ func TestTruncateText(t *testing.T) {
func TestFirstNImages(t *testing.T) {
t.Run("when empty, return an empty one", func(t *testing.T) {
empty := make([]*opengraph.Image, 0)
empty := make([]*image.Image, 0)
assert.Exactly(t, firstNImages(empty, 1), empty, "Should be the same element")
})
t.Run("when it contains one element, return the same array", func(t *testing.T) {
one := []*opengraph.Image{sampleImage("image.png")}
one := []*image.Image{sampleImage("image.png")}
assert.Exactly(t, firstNImages(one, 1), one, "Should be the same element")
})
t.Run("when it contains more than one element and asking for only one, return the first one", func(t *testing.T) {
two := []*opengraph.Image{sampleImage("image.png"), sampleImage("notme.png")}
two := []*image.Image{sampleImage("image.png"), sampleImage("notme.png")}
assert.True(t, strings.HasSuffix(firstNImages(two, 1)[0].URL, "image.png"), "Should be the image element")
})
t.Run("when it contains less than asked, return the original", func(t *testing.T) {
two := []*opengraph.Image{sampleImage("image.png"), sampleImage("notme.png")}
two := []*image.Image{sampleImage("image.png"), sampleImage("notme.png")}
assert.Equal(t, two, firstNImages(two, 10), "should be the same pointer")
})
t.Run("asking for negative images", func(t *testing.T) {
six := []*opengraph.Image{
six := []*image.Image{
sampleImage("image.png"),
sampleImage("another.png"),
sampleImage("yetanother.jpg"),
@@ -300,18 +306,18 @@ func TestTruncateOpenGraph(t *testing.T) {
SiteName: BigText,
Locale: "[EN-en]",
LocalesAlternate: []string{"[EN-ca]", "[ES-es]"},
Images: []*opengraph.Image{
Images: []*image.Image{
sampleImage("image.png"),
sampleImage("another.png"),
sampleImage("yetanother.jpg"),
sampleImage("metoo.gif"),
sampleImage("fifth.ico"),
sampleImage("notme.tiff")},
Audios: []*opengraph.Audio{{}},
Videos: []*opengraph.Video{{}},
Article: &opengraph.Article{},
Book: &opengraph.Book{},
Profile: &opengraph.Profile{},
Audios: []*audio.Audio{{}},
Videos: []*video.Video{{}},
Article: &article.Article{},
Book: &book.Book{},
Profile: &profile.Profile{},
}
result := TruncateOpenGraph(&og)
assert.Nil(t, result.Article, "No article stored")

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

@@ -84,6 +84,11 @@ type PluginSetting struct {
// For "radio" or "dropdown" settings, this is the list of pre-defined options that the user can choose
// from.
Options []*PluginOption `json:"options,omitempty" yaml:"options,omitempty"`
// The intended hosting environment for this plugin setting. Can be "cloud" or "on-prem". When this field is set,
// and the opposite environment is running the plugin, the setting will be hidden in the admin console UI.
// Note that this functionality is entirely client-side, so the plugin needs to handle the case of invalid submissions.
Hosting string `json:"hosting"`
}
type PluginSettingsSchema struct {

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

@@ -18,6 +18,7 @@ type PluginStatus struct {
ClusterId string `json:"cluster_id"`
PluginPath string `json:"plugin_path"`
State int `json:"state"`
Error string `json:"error"`
Name string `json:"name"`
Description string `json:"description"`
Version string `json:"version"`

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

@@ -48,6 +48,7 @@ const (
PostTypeSystemWarnMetricStatus = "warn_metric_status"
PostTypeMe = "me"
PostCustomTypePrefix = "custom_"
PostTypeReminder = "reminder"
PostFileidsMaxRunes = 300
PostFilenamesMaxRunes = 4000
@@ -149,6 +150,13 @@ type PostPatch struct {
HasReactions *bool `json:"has_reactions"`
}
type PostReminder struct {
TargetTime int64 `json:"target_time"`
// These fields are only used internally for interacting with DB.
PostId string `json:",omitempty"`
UserId string `json:",omitempty"`
}
type SearchParameter struct {
Terms *string `json:"terms"`
IsOrSearch *bool `json:"is_or_search"`
@@ -736,18 +744,10 @@ func (o *Post) ToNilIfInvalid() *Post {
return o
}
func (o *Post) RemovePreviewPost() {
if o.Metadata == nil || o.Metadata.Embeds == nil {
return
}
n := 0
for _, embed := range o.Metadata.Embeds {
if embed.Type != PostEmbedPermalink {
o.Metadata.Embeds[n] = embed
n++
}
}
o.Metadata.Embeds = o.Metadata.Embeds[:n]
func (o *Post) ForPlugin() *Post {
p := o.Clone()
p.Metadata = nil
return p
}
func (o *Post) GetPreviewPost() *PreviewPost {

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

@@ -16,8 +16,8 @@ type PostList struct {
PrevPostId string `json:"prev_post_id"`
// HasNext indicates whether there are more items to be fetched or not.
HasNext bool `json:"has_next"`
// HasInaccessiblePosts tells if there are inaccessible posts, past the cloud limit.
HasInaccessiblePosts bool `json:"has_inaccessible_posts"`
// If there are inaccessible posts, FirstInaccessiblePostTime is the time of the latest inaccessible post
FirstInaccessiblePostTime int64 `json:"first_inaccessible_post_time"`
}
func NewPostList() *PostList {
@@ -37,15 +37,23 @@ func (o *PostList) Clone() *PostList {
postsCopy[k] = v.Clone()
}
return &PostList{
Order: orderCopy,
Posts: postsCopy,
NextPostId: o.NextPostId,
PrevPostId: o.PrevPostId,
HasNext: o.HasNext,
HasInaccessiblePosts: o.HasInaccessiblePosts,
Order: orderCopy,
Posts: postsCopy,
NextPostId: o.NextPostId,
PrevPostId: o.PrevPostId,
HasNext: o.HasNext,
FirstInaccessiblePostTime: o.FirstInaccessiblePostTime,
}
}
func (o *PostList) ForPlugin() *PostList {
copy := o.Clone()
for k, p := range copy.Posts {
copy.Posts[k] = p.ForPlugin()
}
return copy
}
func (o *PostList) ToSlice() []*Post {
var posts []*Post

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

@@ -33,3 +33,9 @@ func (o *PostSearchResults) EncodeJSON(w io.Writer) error {
o.PostList.StripActionIntegrations()
return json.NewEncoder(w).Encode(o)
}
func (o *PostSearchResults) ForPlugin() *PostSearchResults {
copy := *o
copy.PostList = copy.PostList.ForPlugin()
return &copy
}