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 удалений

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

@@ -259,7 +259,7 @@ func (a *App) CreatePost(c request.CTX, post *model.Post, channel *model.Channel
var rejectionError *model.AppError
pluginContext := pluginContext(c)
pluginsEnvironment.RunMultiPluginHook(func(hooks plugin.Hooks) bool {
replacementPost, rejectionReason := hooks.MessageWillBePosted(pluginContext, post)
replacementPost, rejectionReason := hooks.MessageWillBePosted(pluginContext, post.ForPlugin())
if rejectionReason != "" {
id := "Post rejected by plugin. " + rejectionReason
if rejectionReason == plugin.DismissPostError {
@@ -269,6 +269,7 @@ func (a *App) CreatePost(c request.CTX, post *model.Post, channel *model.Channel
return false
}
if replacementPost != nil {
// the original post's metadata (if there ever was any) is lost, and will be rebuilt.
post = replacementPost
}
@@ -309,21 +310,14 @@ func (a *App) CreatePost(c request.CTX, post *model.Post, channel *model.Channel
// might be duplicating requests.
a.Srv().seenPendingPostIdsCache.SetWithExpiry(post.PendingPostId, rpost.Id, PendingPostIDsCacheTTL)
// We make a copy of the post for the plugin hook to avoid a race condition.
rPostCopy := rpost.Clone()
// FIXME: Removes PreviewPost from the post payload sent to the MessageHasBeenPosted hook so that plugins compiled with older versions of
// Mattermost—without the gob registration of the PreviewPost struct—won't crash.
if rPostCopy.Metadata != nil {
rPostCopy.Metadata = rPostCopy.Metadata.Copy()
}
rPostCopy.RemovePreviewPost()
// We make a copy of the post for the plugin hook to avoid a race condition,
// and to remove the non-GOB-encodable Metadata from it.
if pluginsEnvironment := a.GetPluginsEnvironment(); pluginsEnvironment != nil {
pluginPost := rpost.ForPlugin()
a.Srv().Go(func() {
pluginContext := pluginContext(c)
pluginsEnvironment.RunMultiPluginHook(func(hooks plugin.Hooks) bool {
hooks.MessageHasBeenPosted(pluginContext, rPostCopy)
hooks.MessageHasBeenPosted(pluginContext, pluginPost)
return true
}, plugin.MessageHasBeenPostedID)
})
@@ -650,12 +644,15 @@ func (a *App) UpdatePost(c *request.Context, post *model.Post, safeUpdate bool)
var rejectionReason string
pluginContext := pluginContext(c)
pluginsEnvironment.RunMultiPluginHook(func(hooks plugin.Hooks) bool {
newPost, rejectionReason = hooks.MessageWillBeUpdated(pluginContext, newPost, oldPost)
newPost, rejectionReason = hooks.MessageWillBeUpdated(pluginContext, newPost.ForPlugin(), oldPost.ForPlugin())
return post != nil
}, plugin.MessageWillBeUpdatedID)
if newPost == nil {
return nil, model.NewAppError("UpdatePost", "Post rejected by plugin. "+rejectionReason, nil, "", http.StatusBadRequest)
}
// Restore the post metadata that was stripped by the plugin. Set it to
// the last known good.
newPost.Metadata = oldPost.Metadata
}
rpost, nErr := a.Srv().Store.Post().Update(newPost, oldPost)
@@ -670,10 +667,12 @@ func (a *App) UpdatePost(c *request.Context, post *model.Post, safeUpdate bool)
}
if pluginsEnvironment := a.GetPluginsEnvironment(); pluginsEnvironment != nil {
pluginOldPost := oldPost.ForPlugin()
pluginNewPost := newPost.ForPlugin()
a.Srv().Go(func() {
pluginContext := pluginContext(c)
pluginsEnvironment.RunMultiPluginHook(func(hooks plugin.Hooks) bool {
hooks.MessageHasBeenUpdated(pluginContext, newPost, oldPost)
hooks.MessageHasBeenUpdated(pluginContext, pluginNewPost, pluginOldPost)
return true
}, plugin.MessageHasBeenUpdatedID)
})
@@ -871,11 +870,11 @@ func (a *App) GetSinglePost(postID string, includeDeleted bool) (*model.Post, *m
}
}
isInaccessible, appErr := a.isInaccessiblePost(post)
firstInaccessiblePostTime, appErr := a.isInaccessiblePost(post)
if appErr != nil {
return nil, appErr
}
if isInaccessible {
if firstInaccessiblePostTime != 0 {
return nil, model.NewAppError("GetSinglePost", "app.post.cloud.get.app_error", nil, "", http.StatusForbidden)
}
@@ -1270,6 +1269,8 @@ func (a *App) DeletePost(c request.CTX, postID, deleteByID string) (*model.Post,
a.Srv().Go(func() {
a.deletePostFiles(post.Id)
})
a.Srv().Store.FileInfo().InvalidateFileInfosForPostCache(postID, true)
a.Srv().Store.FileInfo().InvalidateFileInfosForPostCache(postID, false)
}
a.Srv().Go(func() {
a.deleteFlaggedPosts(post.Id)
@@ -1542,16 +1543,16 @@ func (a *App) GetRecentSearchesForUser(userID string) ([]*model.SearchParams, *m
return searchParams, nil
}
func (a *App) GetFileInfosForPostWithMigration(postID string) ([]*model.FileInfo, *model.AppError) {
func (a *App) GetFileInfosForPostWithMigration(postID string, includeDeleted bool) ([]*model.FileInfo, *model.AppError) {
pchan := make(chan store.StoreResult, 1)
go func() {
post, err := a.Srv().Store.Post().GetSingle(postID, false)
post, err := a.Srv().Store.Post().GetSingle(postID, includeDeleted)
pchan <- store.StoreResult{Data: post, NErr: err}
close(pchan)
}()
infos, err := a.GetFileInfosForPost(postID, false)
infos, err := a.GetFileInfosForPost(postID, false, includeDeleted)
if err != nil {
return nil, err
}
@@ -1581,8 +1582,8 @@ func (a *App) GetFileInfosForPostWithMigration(postID string) ([]*model.FileInfo
return infos, nil
}
func (a *App) GetFileInfosForPost(postID string, fromMaster bool) ([]*model.FileInfo, *model.AppError) {
fileInfos, err := a.Srv().Store.FileInfo().GetForPost(postID, fromMaster, false, true)
func (a *App) GetFileInfosForPost(postID string, fromMaster bool, includeDeleted bool) ([]*model.FileInfo, *model.AppError) {
fileInfos, err := a.Srv().Store.FileInfo().GetForPost(postID, fromMaster, includeDeleted, true)
if err != nil {
return nil, model.NewAppError("GetFileInfosForPost", "app.file_info.get_for_post.app_error", nil, err.Error(), http.StatusInternalServerError)
}
@@ -1880,24 +1881,24 @@ func (a *App) GetPostIfAuthorized(c request.CTX, postID string, session *model.S
}
// GetPostsByIds response bool value indicates, if the post is inaccessible due to cloud plan's limit.
func (a *App) GetPostsByIds(postIDs []string) ([]*model.Post, bool, *model.AppError) {
func (a *App) GetPostsByIds(postIDs []string) ([]*model.Post, int64, *model.AppError) {
posts, err := a.Srv().Store.Post().GetPostsByIds(postIDs)
if err != nil {
var nfErr *store.ErrNotFound
switch {
case errors.As(err, &nfErr):
return nil, false, model.NewAppError("GetPostsByIds", "app.post.get.app_error", nil, nfErr.Error(), http.StatusNotFound)
return nil, 0, model.NewAppError("GetPostsByIds", "app.post.get.app_error", nil, nfErr.Error(), http.StatusNotFound)
default:
return nil, false, model.NewAppError("GetPostsByIds", "app.post.get.app_error", nil, err.Error(), http.StatusInternalServerError)
return nil, 0, model.NewAppError("GetPostsByIds", "app.post.get.app_error", nil, err.Error(), http.StatusInternalServerError)
}
}
posts, hasInaccessiblePosts, appErr := a.getFilteredAccessiblePosts(posts, filterPostOptions{assumeSortedCreatedAt: true})
posts, firstInaccessiblePostTime, appErr := a.getFilteredAccessiblePosts(posts, filterPostOptions{assumeSortedCreatedAt: true})
if appErr != nil {
return nil, false, appErr
return nil, 0, appErr
}
return posts, hasInaccessiblePosts, nil
return posts, firstInaccessiblePostTime, nil
}
func (a *App) GetTopThreadsForTeamSince(c request.CTX, teamID, userID string, opts *model.InsightsOpts) (*model.TopThreadList, *model.AppError) {
@@ -1943,6 +1944,126 @@ func (a *App) GetTopDMsForUserSince(userID string, opts *model.InsightsOpts) (*m
return topDMs, nil
}
func (a *App) SetPostReminder(postID, userID string, targetTime int64) *model.AppError {
// Store the reminder in the DB
reminder := &model.PostReminder{
PostId: postID,
UserId: userID,
TargetTime: targetTime,
}
err := a.Srv().Store.Post().SetPostReminder(reminder)
if err != nil {
return model.NewAppError("SetPostReminder", "app.post_reminder.app_error", nil, err.Error(), http.StatusInternalServerError)
}
metadata, err := a.Srv().Store.Post().GetPostReminderMetadata(postID)
if err != nil {
return model.NewAppError("SetPostReminder", "app.post_reminder.app_error", nil, err.Error(), http.StatusInternalServerError)
}
parsed := time.Unix(targetTime, 0).UTC().Format(time.RFC822)
siteURL := *a.Config().ServiceSettings.SiteURL
// Send an ack message.
ephemeralPost := &model.Post{
Type: model.PostTypeEphemeral,
Id: model.NewId(),
CreateAt: model.GetMillis(),
UserId: userID,
RootId: postID,
ChannelId: metadata.ChannelId,
// It's okay to keep this non-translated. This is just a fallback.
// The webapp will parse the timestamp and show that in user's local timezone.
Message: fmt.Sprintf("You will be reminded about %s/%s/pl/%s by @%s at %s", siteURL, metadata.TeamName, postID, metadata.Username, parsed),
Props: model.StringInterface{
"target_time": targetTime,
"team_name": metadata.TeamName,
"post_id": postID,
"username": metadata.Username,
"type": model.PostTypeReminder,
},
}
message := model.NewWebSocketEvent(model.WebsocketEventEphemeralMessage, "", ephemeralPost.ChannelId, userID, nil)
ephemeralPost = a.PreparePostForClientWithEmbedsAndImages(request.EmptyContext(a.Log()), ephemeralPost, true, false)
ephemeralPost = model.AddPostActionCookies(ephemeralPost, a.PostActionCookieSecret())
postJSON, jsonErr := ephemeralPost.ToJSON()
if jsonErr != nil {
mlog.Warn("Failed to encode post to JSON", mlog.Err(jsonErr))
}
message.Add("post", postJSON)
a.Publish(message)
return nil
}
func (a *App) CheckPostReminders() {
systemBot, appErr := a.GetSystemBot()
if appErr != nil {
mlog.Error("Failed to get system bot", mlog.Err(appErr))
return
}
// This will return the reminders and also delete them from the DB.
// In case, any of the next steps fail, those reminders would be lost.
// Alternatively, if we delete those reminders _after_ it has been sent,
// then in case of any temporary failure, they would get sent in the next batch.
// MM-45595.
reminders, err := a.Srv().Store.Post().GetPostReminders(time.Now().UTC().Unix())
if err != nil {
mlog.Error("Failed to get post reminders", mlog.Err(err))
return
}
// We group multiple reminders for a single user.
groupedReminders := make(map[string][]string)
for _, r := range reminders {
if groupedReminders[r.UserId] == nil {
groupedReminders[r.UserId] = []string{r.PostId}
} else {
groupedReminders[r.UserId] = append(groupedReminders[r.UserId], r.PostId)
}
}
siteURL := *a.Config().ServiceSettings.SiteURL
for userID, postIDs := range groupedReminders {
ch, appErr := a.GetOrCreateDirectChannel(request.EmptyContext(a.Log()), userID, systemBot.UserId)
if appErr != nil {
mlog.Error("Failed to get direct channel", mlog.Err(appErr))
return
}
for _, postID := range postIDs {
metadata, err := a.Srv().Store.Post().GetPostReminderMetadata(postID)
if err != nil {
mlog.Error("Failed to get post reminder metadata", mlog.Err(err))
continue
}
T := i18n.GetUserTranslations(metadata.UserLocale)
dm := &model.Post{
ChannelId: ch.Id,
Message: T("app.post_reminder_dm", model.StringInterface{
"SiteURL": siteURL,
"TeamName": metadata.TeamName,
"PostId": postID,
"Username": metadata.Username,
}),
Type: model.PostTypeDefault,
UserId: systemBot.UserId,
Props: model.StringInterface{
"username": systemBot.Username,
},
}
if _, err := a.CreatePost(request.EmptyContext(a.Log()), dm, ch, false, true); err != nil {
mlog.Error("Failed to post reminder message", mlog.Err(err))
}
}
}
}
func includeEmbedsAndImages(a *App, c request.CTX, topThreadList *model.TopThreadList, userID string) (*model.TopThreadList, error) {
for _, topThread := range topThreadList.Items {
topThread.Post = a.PreparePostForClientWithEmbedsAndImages(c, topThread.Post, false, false)