MM-21552: Adding SaveMultiple to posts (#13766)
* Adding SaveMultiple to posts * Improving tests * fixing i18n * Fixing tests * Improving testing on top of Save and SaveMultiple * Fixing shadow variables * Addressing some PR comments * More clear update post test * Addressing some PR comments * Addressing some PR comments and simplifying the code * Improting replies in bulk too * Fixing reply count and processing last imported replies * Adding OverwriteMultiple to posts aggregating everything in the same transaction * Adding 2 pending tests to implement * Adding tests for overwrite multiple posts * Adding tests for TeamStore.GetByNames method * Fixing shadow variables * Addressing PR comments * Extracting i18n strings * Fixing tests * Fixing tests * Adding more test cases * Using a variable instead of a fake timestamp
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
2bec92a404
Коммит
27d536b212
@@ -16,7 +16,10 @@ import (
|
|||||||
"github.com/mattermost/mattermost-server/v5/model"
|
"github.com/mattermost/mattermost-server/v5/model"
|
||||||
)
|
)
|
||||||
|
|
||||||
const maxScanTokenSize = 16 * 1024 * 1024 // Need to set a higher limit than default because some customers cross the limit. See MM-22314
|
const (
|
||||||
|
importMultiplePostsThreshold = 1000
|
||||||
|
maxScanTokenSize = 16 * 1024 * 1024 // Need to set a higher limit than default because some customers cross the limit. See MM-22314
|
||||||
|
)
|
||||||
|
|
||||||
func stopOnError(err LineImportWorkerError) bool {
|
func stopOnError(err LineImportWorkerError) bool {
|
||||||
if err.Error.Id == "api.file.upload_file.large_image.app_error" {
|
if err.Error.Id == "api.file.upload_file.large_image.app_error" {
|
||||||
@@ -27,11 +30,41 @@ func stopOnError(err LineImportWorkerError) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (a *App) bulkImportWorker(dryRun bool, wg *sync.WaitGroup, lines <-chan LineImportWorkerData, errors chan<- LineImportWorkerError) {
|
func (a *App) bulkImportWorker(dryRun bool, wg *sync.WaitGroup, lines <-chan LineImportWorkerData, errors chan<- LineImportWorkerError) {
|
||||||
|
posts := []*PostImportData{}
|
||||||
|
directPosts := []*DirectPostImportData{}
|
||||||
for line := range lines {
|
for line := range lines {
|
||||||
if err := a.importLine(line.LineImportData, dryRun); err != nil {
|
switch {
|
||||||
errors <- LineImportWorkerError{err, line.LineNumber}
|
case line.LineImportData.Type == "post":
|
||||||
|
posts = append(posts, line.Post)
|
||||||
|
if line.Post == nil {
|
||||||
|
errors <- LineImportWorkerError{model.NewAppError("BulkImport", "app.import.import_line.null_post.error", nil, "", http.StatusBadRequest), line.LineNumber}
|
||||||
|
}
|
||||||
|
if len(posts) >= importMultiplePostsThreshold {
|
||||||
|
a.importMultiplePosts(posts, dryRun)
|
||||||
|
posts = []*PostImportData{}
|
||||||
|
}
|
||||||
|
case line.LineImportData.Type == "direct_post":
|
||||||
|
directPosts = append(directPosts, line.DirectPost)
|
||||||
|
if line.DirectPost == nil {
|
||||||
|
errors <- LineImportWorkerError{model.NewAppError("BulkImport", "app.import.import_line.null_direct_post.error", nil, "", http.StatusBadRequest), line.LineNumber}
|
||||||
|
}
|
||||||
|
if len(directPosts) >= importMultiplePostsThreshold {
|
||||||
|
a.importMultipleDirectPosts(directPosts, dryRun)
|
||||||
|
directPosts = []*DirectPostImportData{}
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
if err := a.importLine(line.LineImportData, dryRun); err != nil {
|
||||||
|
errors <- LineImportWorkerError{err, line.LineNumber}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(posts) > 0 {
|
||||||
|
a.importMultiplePosts(posts, dryRun)
|
||||||
|
}
|
||||||
|
if len(directPosts) > 0 {
|
||||||
|
a.importMultipleDirectPosts(directPosts, dryRun)
|
||||||
|
}
|
||||||
wg.Done()
|
wg.Done()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -159,21 +192,11 @@ func (a *App) importLine(line LineImportData, dryRun bool) *model.AppError {
|
|||||||
return model.NewAppError("BulkImport", "app.import.import_line.null_user.error", nil, "", http.StatusBadRequest)
|
return model.NewAppError("BulkImport", "app.import.import_line.null_user.error", nil, "", http.StatusBadRequest)
|
||||||
}
|
}
|
||||||
return a.importUser(line.User, dryRun)
|
return a.importUser(line.User, dryRun)
|
||||||
case line.Type == "post":
|
|
||||||
if line.Post == nil {
|
|
||||||
return model.NewAppError("BulkImport", "app.import.import_line.null_post.error", nil, "", http.StatusBadRequest)
|
|
||||||
}
|
|
||||||
return a.importPost(line.Post, dryRun)
|
|
||||||
case line.Type == "direct_channel":
|
case line.Type == "direct_channel":
|
||||||
if line.DirectChannel == nil {
|
if line.DirectChannel == nil {
|
||||||
return model.NewAppError("BulkImport", "app.import.import_line.null_direct_channel.error", nil, "", http.StatusBadRequest)
|
return model.NewAppError("BulkImport", "app.import.import_line.null_direct_channel.error", nil, "", http.StatusBadRequest)
|
||||||
}
|
}
|
||||||
return a.importDirectChannel(line.DirectChannel, dryRun)
|
return a.importDirectChannel(line.DirectChannel, dryRun)
|
||||||
case line.Type == "direct_post":
|
|
||||||
if line.DirectPost == nil {
|
|
||||||
return model.NewAppError("BulkImport", "app.import.import_line.null_direct_post.error", nil, "", http.StatusBadRequest)
|
|
||||||
}
|
|
||||||
return a.importDirectPost(line.DirectPost, dryRun)
|
|
||||||
case line.Type == "emoji":
|
case line.Type == "emoji":
|
||||||
if line.Emoji == nil {
|
if line.Emoji == nil {
|
||||||
return model.NewAppError("BulkImport", "app.import.import_line.null_emoji.error", nil, "", http.StatusBadRequest)
|
return model.NewAppError("BulkImport", "app.import.import_line.null_emoji.error", nil, "", http.StatusBadRequest)
|
||||||
|
|||||||
@@ -851,67 +851,87 @@ func (a *App) importReaction(data *ReactionImportData, post *model.Post, dryRun
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *App) importReply(data *ReplyImportData, post *model.Post, teamId string, dryRun bool) *model.AppError {
|
func (a *App) importReplies(data []ReplyImportData, post *model.Post, teamId string, dryRun bool) *model.AppError {
|
||||||
var err *model.AppError
|
var err *model.AppError
|
||||||
if err = validateReplyImportData(data, post.CreateAt, a.MaxPostSize()); err != nil {
|
usernames := []string{}
|
||||||
return err
|
for _, replyData := range data {
|
||||||
}
|
if err = validateReplyImportData(&replyData, post.CreateAt, a.MaxPostSize()); err != nil {
|
||||||
|
|
||||||
var user *model.User
|
|
||||||
user, err = a.Srv().Store.User().GetByUsername(*data.User)
|
|
||||||
if err != nil {
|
|
||||||
return model.NewAppError("BulkImport", "app.import.import_post.user_not_found.error", map[string]interface{}{"Username": data.User}, err.Error(), http.StatusBadRequest)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if this post already exists.
|
|
||||||
replies, err := a.Srv().Store.Post().GetPostsCreatedAt(post.ChannelId, *data.CreateAt)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
var reply *model.Post
|
|
||||||
for _, r := range replies {
|
|
||||||
if r.Message == *data.Message && r.RootId == post.Id {
|
|
||||||
reply = r
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if reply == nil {
|
|
||||||
reply = &model.Post{}
|
|
||||||
}
|
|
||||||
reply.UserId = user.Id
|
|
||||||
reply.ChannelId = post.ChannelId
|
|
||||||
reply.ParentId = post.Id
|
|
||||||
reply.RootId = post.Id
|
|
||||||
reply.Message = *data.Message
|
|
||||||
reply.CreateAt = *data.CreateAt
|
|
||||||
|
|
||||||
fileIds, err := a.uploadAttachments(data.Attachments, reply, teamId, dryRun)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
for _, fileID := range reply.FileIds {
|
|
||||||
if _, ok := fileIds[fileID]; !ok {
|
|
||||||
a.Srv().Store.FileInfo().PermanentDelete(fileID)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
reply.FileIds = make([]string, 0)
|
|
||||||
for fileID := range fileIds {
|
|
||||||
reply.FileIds = append(reply.FileIds, fileID)
|
|
||||||
}
|
|
||||||
|
|
||||||
if reply.Id == "" {
|
|
||||||
if _, err := a.Srv().Store.Post().Save(reply); err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
} else {
|
usernames = append(usernames, *replyData.User)
|
||||||
if _, err := a.Srv().Store.Post().Overwrite(reply); err != nil {
|
}
|
||||||
|
|
||||||
|
users, err := a.getUsersByUsernames(usernames)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
postsWithData := []postAndData{}
|
||||||
|
postsForCreateList := []*model.Post{}
|
||||||
|
postsForOverwriteList := []*model.Post{}
|
||||||
|
|
||||||
|
for _, replyData := range data {
|
||||||
|
user := users[*replyData.User]
|
||||||
|
|
||||||
|
// Check if this post already exists.
|
||||||
|
replies, err := a.Srv().Store.Post().GetPostsCreatedAt(post.ChannelId, *replyData.CreateAt)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var reply *model.Post
|
||||||
|
for _, r := range replies {
|
||||||
|
if r.Message == *replyData.Message && r.RootId == post.Id {
|
||||||
|
reply = r
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if reply == nil {
|
||||||
|
reply = &model.Post{}
|
||||||
|
}
|
||||||
|
reply.UserId = user.Id
|
||||||
|
reply.ChannelId = post.ChannelId
|
||||||
|
reply.ParentId = post.Id
|
||||||
|
reply.RootId = post.Id
|
||||||
|
reply.Message = *replyData.Message
|
||||||
|
reply.CreateAt = *replyData.CreateAt
|
||||||
|
|
||||||
|
fileIds, err := a.uploadAttachments(replyData.Attachments, reply, teamId, dryRun)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for _, fileID := range reply.FileIds {
|
||||||
|
if _, ok := fileIds[fileID]; !ok {
|
||||||
|
a.Srv().Store.FileInfo().PermanentDelete(fileID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
reply.FileIds = make([]string, 0)
|
||||||
|
for fileID := range fileIds {
|
||||||
|
reply.FileIds = append(reply.FileIds, fileID)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(reply.Id) == 0 {
|
||||||
|
postsForCreateList = append(postsForCreateList, reply)
|
||||||
|
} else {
|
||||||
|
postsForOverwriteList = append(postsForOverwriteList, reply)
|
||||||
|
}
|
||||||
|
postsWithData = append(postsWithData, postAndData{post: reply, replyData: &replyData})
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(postsForCreateList) > 0 {
|
||||||
|
if _, err := a.Srv().Store.Post().SaveMultiple(postsForCreateList); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
a.updateFileInfoWithPostId(reply)
|
if _, err := a.Srv().Store.Post().OverwriteMultiple(postsForOverwriteList); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, postWithData := range postsWithData {
|
||||||
|
a.updateFileInfoWithPostId(postWithData.post)
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -961,9 +981,70 @@ func (a *App) importAttachment(data *AttachmentImportData, post *model.Post, tea
|
|||||||
return fileInfo, nil
|
return fileInfo, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *App) importPost(data *PostImportData, dryRun bool) *model.AppError {
|
type postAndData struct {
|
||||||
if err := validatePostImportData(data, a.MaxPostSize()); err != nil {
|
post *model.Post
|
||||||
return err
|
postData *PostImportData
|
||||||
|
directPostData *DirectPostImportData
|
||||||
|
replyData *ReplyImportData
|
||||||
|
team *model.Team
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *App) getUsersByUsernames(usernames []string) (map[string]*model.User, *model.AppError) {
|
||||||
|
uniqueUsernames := utils.RemoveDuplicatesFromStringArray(usernames)
|
||||||
|
allUsers, err := a.Srv().Store.User().GetProfilesByUsernames(uniqueUsernames, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, model.NewAppError("BulkImport", "app.import.get_users_by_username.some_users_not_found.error", nil, err.Error(), http.StatusBadRequest)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(allUsers) != len(uniqueUsernames) {
|
||||||
|
return nil, model.NewAppError("BulkImport", "app.import.get_users_by_username.some_users_not_found.error", nil, "", http.StatusBadRequest)
|
||||||
|
}
|
||||||
|
|
||||||
|
users := make(map[string]*model.User)
|
||||||
|
for _, user := range allUsers {
|
||||||
|
users[user.Username] = user
|
||||||
|
}
|
||||||
|
return users, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *App) getTeamsByNames(names []string) (map[string]*model.Team, *model.AppError) {
|
||||||
|
allTeams, err := a.Srv().Store.Team().GetByNames(names)
|
||||||
|
if err != nil {
|
||||||
|
return nil, model.NewAppError("BulkImport", "app.import.get_teams_by_names.some_teams_not_found.error", nil, err.Error(), http.StatusBadRequest)
|
||||||
|
}
|
||||||
|
|
||||||
|
teams := make(map[string]*model.Team)
|
||||||
|
for _, team := range allTeams {
|
||||||
|
teams[team.Name] = team
|
||||||
|
}
|
||||||
|
return teams, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *App) getChannelsForPosts(teams map[string]*model.Team, data []*PostImportData) (map[string]*model.Channel, *model.AppError) {
|
||||||
|
channels := make(map[string]*model.Channel)
|
||||||
|
for _, postData := range data {
|
||||||
|
team := teams[*postData.Team]
|
||||||
|
if channel, ok := channels[*postData.Channel]; !ok || channel == nil {
|
||||||
|
var err *model.AppError
|
||||||
|
channel, err = a.Srv().Store.Channel().GetByName(team.Id, *postData.Channel, true)
|
||||||
|
if err != nil {
|
||||||
|
return nil, model.NewAppError("BulkImport", "app.import.import_post.channel_not_found.error", map[string]interface{}{"ChannelName": *postData.Channel}, err.Error(), http.StatusBadRequest)
|
||||||
|
}
|
||||||
|
channels[*postData.Channel] = channel
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return channels, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *App) importMultiplePosts(data []*PostImportData, dryRun bool) *model.AppError {
|
||||||
|
if len(data) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, postData := range data {
|
||||||
|
if err := validatePostImportData(postData, a.MaxPostSize()); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If this is a Dry Run, do not continue any further.
|
// If this is a Dry Run, do not continue any further.
|
||||||
@@ -971,113 +1052,148 @@ func (a *App) importPost(data *PostImportData, dryRun bool) *model.AppError {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
team, err := a.Srv().Store.Team().GetByName(*data.Team)
|
usernames := []string{}
|
||||||
if err != nil {
|
teamNames := []string{}
|
||||||
return model.NewAppError("BulkImport", "app.import.import_post.team_not_found.error", map[string]interface{}{"TeamName": *data.Team}, err.Error(), http.StatusBadRequest)
|
for _, postData := range data {
|
||||||
|
usernames = append(usernames, *postData.User)
|
||||||
|
if postData.FlaggedBy != nil {
|
||||||
|
usernames = append(usernames, *postData.FlaggedBy...)
|
||||||
|
}
|
||||||
|
teamNames = append(teamNames, *postData.Team)
|
||||||
}
|
}
|
||||||
|
|
||||||
channel, err := a.Srv().Store.Channel().GetByName(team.Id, *data.Channel, false)
|
users, err := a.getUsersByUsernames(usernames)
|
||||||
if err != nil {
|
|
||||||
return model.NewAppError("BulkImport", "app.import.import_post.channel_not_found.error", map[string]interface{}{"ChannelName": *data.Channel}, err.Error(), http.StatusBadRequest)
|
|
||||||
}
|
|
||||||
|
|
||||||
var user *model.User
|
|
||||||
user, err = a.Srv().Store.User().GetByUsername(*data.User)
|
|
||||||
if err != nil {
|
|
||||||
return model.NewAppError("BulkImport", "app.import.import_post.user_not_found.error", map[string]interface{}{"Username": *data.User}, err.Error(), http.StatusBadRequest)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if this post already exists.
|
|
||||||
posts, err := a.Srv().Store.Post().GetPostsCreatedAt(channel.Id, *data.CreateAt)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
var post *model.Post
|
teams, err := a.getTeamsByNames(teamNames)
|
||||||
for _, p := range posts {
|
|
||||||
if p.Message == *data.Message {
|
|
||||||
post = p
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if post == nil {
|
|
||||||
post = &model.Post{}
|
|
||||||
}
|
|
||||||
|
|
||||||
post.ChannelId = channel.Id
|
|
||||||
post.Message = *data.Message
|
|
||||||
post.UserId = user.Id
|
|
||||||
post.CreateAt = *data.CreateAt
|
|
||||||
|
|
||||||
post.Hashtags, _ = model.ParseHashtags(post.Message)
|
|
||||||
|
|
||||||
fileIds, err := a.uploadAttachments(data.Attachments, post, team.Id, dryRun)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
for _, fileID := range post.FileIds {
|
|
||||||
if _, ok := fileIds[fileID]; !ok {
|
|
||||||
a.Srv().Store.FileInfo().PermanentDelete(fileID)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
post.FileIds = make([]string, 0)
|
|
||||||
for fileID := range fileIds {
|
|
||||||
post.FileIds = append(post.FileIds, fileID)
|
|
||||||
}
|
|
||||||
|
|
||||||
if post.Id == "" {
|
channels, err := a.getChannelsForPosts(teams, data)
|
||||||
if _, err = a.Srv().Store.Post().Save(post); err != nil {
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
postsWithData := []postAndData{}
|
||||||
|
postsForCreateList := []*model.Post{}
|
||||||
|
postsForOverwriteList := []*model.Post{}
|
||||||
|
|
||||||
|
for _, postData := range data {
|
||||||
|
team := teams[*postData.Team]
|
||||||
|
channel := channels[*postData.Channel]
|
||||||
|
user := users[*postData.User]
|
||||||
|
|
||||||
|
// Check if this post already exists.
|
||||||
|
posts, err := a.Srv().Store.Post().GetPostsCreatedAt(channel.Id, *postData.CreateAt)
|
||||||
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
if _, err = a.Srv().Store.Post().Overwrite(post); err != nil {
|
var post *model.Post
|
||||||
|
for _, p := range posts {
|
||||||
|
if p.Message == *postData.Message {
|
||||||
|
post = p
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if post == nil {
|
||||||
|
post = &model.Post{}
|
||||||
|
}
|
||||||
|
|
||||||
|
post.ChannelId = channel.Id
|
||||||
|
post.Message = *postData.Message
|
||||||
|
post.UserId = user.Id
|
||||||
|
post.CreateAt = *postData.CreateAt
|
||||||
|
post.Hashtags, _ = model.ParseHashtags(post.Message)
|
||||||
|
|
||||||
|
fileIds, err := a.uploadAttachments(postData.Attachments, post, team.Id, dryRun)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for _, fileID := range post.FileIds {
|
||||||
|
if _, ok := fileIds[fileID]; !ok {
|
||||||
|
a.Srv().Store.FileInfo().PermanentDelete(fileID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
post.FileIds = make([]string, 0)
|
||||||
|
for fileID := range fileIds {
|
||||||
|
post.FileIds = append(post.FileIds, fileID)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(post.Id) == 0 {
|
||||||
|
postsForCreateList = append(postsForCreateList, post)
|
||||||
|
} else {
|
||||||
|
postsForOverwriteList = append(postsForOverwriteList, post)
|
||||||
|
}
|
||||||
|
postsWithData = append(postsWithData, postAndData{post: post, postData: postData, team: team})
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(postsForCreateList) > 0 {
|
||||||
|
if _, err := a.Srv().Store.Post().SaveMultiple(postsForCreateList); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if data.FlaggedBy != nil {
|
if _, err := a.Srv().Store.Post().OverwriteMultiple(postsForOverwriteList); err != nil {
|
||||||
var preferences model.Preferences
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
for _, username := range *data.FlaggedBy {
|
var lastPostWithData *postAndData
|
||||||
var user *model.User
|
repliesBulk := []ReplyImportData{}
|
||||||
user, err = a.Srv().Store.User().GetByUsername(username)
|
for _, postWithData := range postsWithData {
|
||||||
if err != nil {
|
if postWithData.postData.FlaggedBy != nil {
|
||||||
return model.NewAppError("BulkImport", "app.import.import_post.user_not_found.error", map[string]interface{}{"Username": username}, err.Error(), http.StatusBadRequest)
|
var preferences model.Preferences
|
||||||
|
|
||||||
|
for _, username := range *postWithData.postData.FlaggedBy {
|
||||||
|
user := users[username]
|
||||||
|
|
||||||
|
preferences = append(preferences, model.Preference{
|
||||||
|
UserId: user.Id,
|
||||||
|
Category: model.PREFERENCE_CATEGORY_FLAGGED_POST,
|
||||||
|
Name: postWithData.post.Id,
|
||||||
|
Value: "true",
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
preferences = append(preferences, model.Preference{
|
if len(preferences) > 0 {
|
||||||
UserId: user.Id,
|
if err := a.Srv().Store.Preference().Save(&preferences); err != nil {
|
||||||
Category: model.PREFERENCE_CATEGORY_FLAGGED_POST,
|
return model.NewAppError("BulkImport", "app.import.import_post.save_preferences.error", nil, err.Error(), http.StatusInternalServerError)
|
||||||
Name: post.Id,
|
}
|
||||||
Value: "true",
|
}
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(preferences) > 0 {
|
if postWithData.postData.Reactions != nil {
|
||||||
if err := a.Srv().Store.Preference().Save(&preferences); err != nil {
|
for _, reaction := range *postWithData.postData.Reactions {
|
||||||
return model.NewAppError("BulkImport", "app.import.import_post.save_preferences.error", nil, err.Error(), http.StatusInternalServerError)
|
if err := a.importReaction(&reaction, postWithData.post, dryRun); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if postWithData.postData.Replies != nil {
|
||||||
|
repliesBulk = append(repliesBulk, *postWithData.postData.Replies...)
|
||||||
|
if len(repliesBulk) >= importMultiplePostsThreshold {
|
||||||
|
err := a.importReplies(repliesBulk, postWithData.post, postWithData.team.Id, dryRun)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
repliesBulk = []ReplyImportData{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
a.updateFileInfoWithPostId(postWithData.post)
|
||||||
|
lastPostWithData = &postWithData
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(repliesBulk) >= 0 && lastPostWithData != nil {
|
||||||
|
err := a.importReplies(repliesBulk, lastPostWithData.post, lastPostWithData.team.Id, dryRun)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if data.Reactions != nil {
|
|
||||||
for _, reaction := range *data.Reactions {
|
|
||||||
if err := a.importReaction(&reaction, post, dryRun); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if data.Replies != nil {
|
|
||||||
for _, reply := range *data.Replies {
|
|
||||||
if err := a.importReply(&reply, post, team.Id, dryRun); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
a.updateFileInfoWithPostId(post)
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1116,15 +1232,12 @@ func (a *App) importDirectChannel(data *DirectChannelImportData, dryRun bool) *m
|
|||||||
}
|
}
|
||||||
|
|
||||||
var userIds []string
|
var userIds []string
|
||||||
userMap := make(map[string]string)
|
userMap, err := a.getUsersByUsernames(*data.Members)
|
||||||
for _, username := range *data.Members {
|
if err != nil {
|
||||||
var user *model.User
|
return err
|
||||||
user, err = a.Srv().Store.User().GetByUsername(username)
|
}
|
||||||
if err != nil {
|
for _, user := range *data.Members {
|
||||||
return model.NewAppError("BulkImport", "app.import.import_direct_channel.member_not_found.error", nil, err.Error(), http.StatusBadRequest)
|
userIds = append(userIds, userMap[user].Id)
|
||||||
}
|
|
||||||
userIds = append(userIds, user.Id)
|
|
||||||
userMap[username] = user.Id
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var channel *model.Channel
|
var channel *model.Channel
|
||||||
@@ -1157,7 +1270,7 @@ func (a *App) importDirectChannel(data *DirectChannelImportData, dryRun bool) *m
|
|||||||
if data.FavoritedBy != nil {
|
if data.FavoritedBy != nil {
|
||||||
for _, favoriter := range *data.FavoritedBy {
|
for _, favoriter := range *data.FavoritedBy {
|
||||||
preferences = append(preferences, model.Preference{
|
preferences = append(preferences, model.Preference{
|
||||||
UserId: userMap[favoriter],
|
UserId: userMap[favoriter].Id,
|
||||||
Category: model.PREFERENCE_CATEGORY_FAVORITE_CHANNEL,
|
Category: model.PREFERENCE_CATEGORY_FAVORITE_CHANNEL,
|
||||||
Name: channel.Id,
|
Name: channel.Id,
|
||||||
Value: "true",
|
Value: "true",
|
||||||
@@ -1180,10 +1293,15 @@ func (a *App) importDirectChannel(data *DirectChannelImportData, dryRun bool) *m
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *App) importDirectPost(data *DirectPostImportData, dryRun bool) *model.AppError {
|
func (a *App) importMultipleDirectPosts(data []*DirectPostImportData, dryRun bool) *model.AppError {
|
||||||
var err *model.AppError
|
if len(data) == 0 {
|
||||||
if err = validateDirectPostImportData(data, a.MaxPostSize()); err != nil {
|
return nil
|
||||||
return err
|
}
|
||||||
|
|
||||||
|
for _, postData := range data {
|
||||||
|
if err := validateDirectPostImportData(postData, a.MaxPostSize()); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If this is a Dry Run, do not continue any further.
|
// If this is a Dry Run, do not continue any further.
|
||||||
@@ -1191,129 +1309,143 @@ func (a *App) importDirectPost(data *DirectPostImportData, dryRun bool) *model.A
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var userIds []string
|
usernames := []string{}
|
||||||
for _, username := range *data.ChannelMembers {
|
for _, postData := range data {
|
||||||
var user *model.User
|
usernames = append(usernames, *postData.User)
|
||||||
user, err = a.Srv().Store.User().GetByUsername(username)
|
if postData.FlaggedBy != nil {
|
||||||
|
usernames = append(usernames, *postData.FlaggedBy...)
|
||||||
|
}
|
||||||
|
usernames = append(usernames, *postData.ChannelMembers...)
|
||||||
|
}
|
||||||
|
|
||||||
|
users, err := a.getUsersByUsernames(usernames)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
postsWithData := []postAndData{}
|
||||||
|
postsForCreateList := []*model.Post{}
|
||||||
|
postsForOverwriteList := []*model.Post{}
|
||||||
|
|
||||||
|
for _, postData := range data {
|
||||||
|
var userIds []string
|
||||||
|
var err *model.AppError
|
||||||
|
for _, username := range *postData.ChannelMembers {
|
||||||
|
user := users[username]
|
||||||
|
userIds = append(userIds, user.Id)
|
||||||
|
}
|
||||||
|
|
||||||
|
var channel *model.Channel
|
||||||
|
var ch *model.Channel
|
||||||
|
if len(userIds) == 2 {
|
||||||
|
ch, err = a.GetOrCreateDirectChannel(userIds[0], userIds[1])
|
||||||
|
if err != nil && err.Id != store.CHANNEL_EXISTS_ERROR {
|
||||||
|
return model.NewAppError("BulkImport", "app.import.import_direct_post.create_direct_channel.error", nil, err.Error(), http.StatusBadRequest)
|
||||||
|
}
|
||||||
|
channel = ch
|
||||||
|
} else {
|
||||||
|
ch, err = a.createGroupChannel(userIds, userIds[0])
|
||||||
|
if err != nil && err.Id != store.CHANNEL_EXISTS_ERROR {
|
||||||
|
return model.NewAppError("BulkImport", "app.import.import_direct_post.create_group_channel.error", nil, err.Error(), http.StatusBadRequest)
|
||||||
|
}
|
||||||
|
channel = ch
|
||||||
|
}
|
||||||
|
|
||||||
|
user := users[*postData.User]
|
||||||
|
|
||||||
|
// Check if this post already exists.
|
||||||
|
posts, err := a.Srv().Store.Post().GetPostsCreatedAt(channel.Id, *postData.CreateAt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return model.NewAppError("BulkImport", "app.import.import_direct_post.channel_member_not_found.error", nil, err.Error(), http.StatusBadRequest)
|
|
||||||
}
|
|
||||||
userIds = append(userIds, user.Id)
|
|
||||||
}
|
|
||||||
|
|
||||||
var channel *model.Channel
|
|
||||||
var ch *model.Channel
|
|
||||||
if len(userIds) == 2 {
|
|
||||||
ch, err = a.createDirectChannel(userIds[0], userIds[1])
|
|
||||||
if err != nil && err.Id != store.CHANNEL_EXISTS_ERROR {
|
|
||||||
return model.NewAppError("BulkImport", "app.import.import_direct_post.create_direct_channel.error", nil, err.Error(), http.StatusBadRequest)
|
|
||||||
}
|
|
||||||
channel = ch
|
|
||||||
} else {
|
|
||||||
ch, err = a.createGroupChannel(userIds, userIds[0])
|
|
||||||
if err != nil && err.Id != store.CHANNEL_EXISTS_ERROR {
|
|
||||||
return model.NewAppError("BulkImport", "app.import.import_direct_post.create_group_channel.error", nil, err.Error(), http.StatusBadRequest)
|
|
||||||
}
|
|
||||||
channel = ch
|
|
||||||
}
|
|
||||||
|
|
||||||
var user *model.User
|
|
||||||
user, err = a.Srv().Store.User().GetByUsername(*data.User)
|
|
||||||
if err != nil {
|
|
||||||
return model.NewAppError("BulkImport", "app.import.import_direct_post.user_not_found.error", map[string]interface{}{"Username": *data.User}, "", http.StatusBadRequest)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if this post already exists.
|
|
||||||
posts, err := a.Srv().Store.Post().GetPostsCreatedAt(channel.Id, *data.CreateAt)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
var post *model.Post
|
|
||||||
for _, p := range posts {
|
|
||||||
if p.Message == *data.Message {
|
|
||||||
post = p
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if post == nil {
|
|
||||||
post = &model.Post{}
|
|
||||||
}
|
|
||||||
|
|
||||||
post.ChannelId = channel.Id
|
|
||||||
post.Message = *data.Message
|
|
||||||
post.UserId = user.Id
|
|
||||||
post.CreateAt = *data.CreateAt
|
|
||||||
|
|
||||||
post.Hashtags, _ = model.ParseHashtags(post.Message)
|
|
||||||
|
|
||||||
fileIds, err := a.uploadAttachments(data.Attachments, post, "noteam", dryRun)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
for _, fileID := range post.FileIds {
|
|
||||||
if _, ok := fileIds[fileID]; !ok {
|
|
||||||
a.Srv().Store.FileInfo().PermanentDelete(fileID)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
post.FileIds = make([]string, 0)
|
|
||||||
for fileID := range fileIds {
|
|
||||||
post.FileIds = append(post.FileIds, fileID)
|
|
||||||
}
|
|
||||||
|
|
||||||
if post.Id == "" {
|
|
||||||
if _, err = a.Srv().Store.Post().Save(post); err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
if _, err = a.Srv().Store.Post().Overwrite(post); err != nil {
|
var post *model.Post
|
||||||
|
for _, p := range posts {
|
||||||
|
if p.Message == *postData.Message {
|
||||||
|
post = p
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if post == nil {
|
||||||
|
post = &model.Post{}
|
||||||
|
}
|
||||||
|
|
||||||
|
post.ChannelId = channel.Id
|
||||||
|
post.Message = *postData.Message
|
||||||
|
post.UserId = user.Id
|
||||||
|
post.CreateAt = *postData.CreateAt
|
||||||
|
post.Hashtags, _ = model.ParseHashtags(post.Message)
|
||||||
|
|
||||||
|
fileIds, err := a.uploadAttachments(postData.Attachments, post, "noteam", dryRun)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for _, fileID := range post.FileIds {
|
||||||
|
if _, ok := fileIds[fileID]; !ok {
|
||||||
|
a.Srv().Store.FileInfo().PermanentDelete(fileID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
post.FileIds = make([]string, 0)
|
||||||
|
for fileID := range fileIds {
|
||||||
|
post.FileIds = append(post.FileIds, fileID)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(post.Id) == 0 {
|
||||||
|
postsForCreateList = append(postsForCreateList, post)
|
||||||
|
} else {
|
||||||
|
postsForOverwriteList = append(postsForOverwriteList, post)
|
||||||
|
}
|
||||||
|
postsWithData = append(postsWithData, postAndData{post: post, directPostData: postData})
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(postsForCreateList) > 0 {
|
||||||
|
if _, err := a.Srv().Store.Post().SaveMultiple(postsForCreateList); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if _, err := a.Srv().Store.Post().OverwriteMultiple(postsForOverwriteList); err != nil {
|
||||||
if data.FlaggedBy != nil {
|
return err
|
||||||
var preferences model.Preferences
|
|
||||||
|
|
||||||
for _, username := range *data.FlaggedBy {
|
|
||||||
var user *model.User
|
|
||||||
user, err = a.Srv().Store.User().GetByUsername(username)
|
|
||||||
if err != nil {
|
|
||||||
return model.NewAppError("BulkImport", "app.import.import_direct_post.user_not_found.error", map[string]interface{}{"Username": username}, "", http.StatusBadRequest)
|
|
||||||
}
|
|
||||||
|
|
||||||
preferences = append(preferences, model.Preference{
|
|
||||||
UserId: user.Id,
|
|
||||||
Category: model.PREFERENCE_CATEGORY_FLAGGED_POST,
|
|
||||||
Name: post.Id,
|
|
||||||
Value: "true",
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(preferences) > 0 {
|
|
||||||
if err := a.Srv().Store.Preference().Save(&preferences); err != nil {
|
|
||||||
return model.NewAppError("BulkImport", "app.import.import_direct_post.save_preferences.error", nil, err.Error(), http.StatusInternalServerError)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if data.Reactions != nil {
|
for _, postWithData := range postsWithData {
|
||||||
for _, reaction := range *data.Reactions {
|
if postWithData.directPostData.FlaggedBy != nil {
|
||||||
if err := a.importReaction(&reaction, post, dryRun); err != nil {
|
var preferences model.Preferences
|
||||||
|
|
||||||
|
for _, username := range *postWithData.directPostData.FlaggedBy {
|
||||||
|
user := users[username]
|
||||||
|
|
||||||
|
preferences = append(preferences, model.Preference{
|
||||||
|
UserId: user.Id,
|
||||||
|
Category: model.PREFERENCE_CATEGORY_FLAGGED_POST,
|
||||||
|
Name: postWithData.post.Id,
|
||||||
|
Value: "true",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(preferences) > 0 {
|
||||||
|
if err := a.Srv().Store.Preference().Save(&preferences); err != nil {
|
||||||
|
return model.NewAppError("BulkImport", "app.import.import_post.save_preferences.error", nil, err.Error(), http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if postWithData.directPostData.Reactions != nil {
|
||||||
|
for _, reaction := range *postWithData.directPostData.Reactions {
|
||||||
|
if err := a.importReaction(&reaction, postWithData.post, dryRun); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if postWithData.directPostData.Replies != nil {
|
||||||
|
if err := a.importReplies(*postWithData.directPostData.Replies, postWithData.post, "noteam", dryRun); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if data.Replies != nil {
|
a.updateFileInfoWithPostId(postWithData.post)
|
||||||
for _, reply := range *data.Replies {
|
|
||||||
if err := a.importReply(&reply, post, "noteam", dryRun); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
a.updateFileInfoWithPostId(post)
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
@@ -239,12 +239,12 @@ func GetAttachments(userId string, th *TestHelper, t *testing.T) []*model.FileIn
|
|||||||
|
|
||||||
func AssertFileIdsInPost(files []*model.FileInfo, th *TestHelper, t *testing.T) {
|
func AssertFileIdsInPost(files []*model.FileInfo, th *TestHelper, t *testing.T) {
|
||||||
postId := files[0].PostId
|
postId := files[0].PostId
|
||||||
assert.NotNil(t, postId)
|
require.NotNil(t, postId)
|
||||||
|
|
||||||
posts, err := th.App.Srv().Store.Post().GetPostsByIds([]string{postId})
|
posts, err := th.App.Srv().Store.Post().GetPostsByIds([]string{postId})
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
|
|
||||||
assert.Equal(t, len(posts), 1)
|
require.Len(t, posts, 1)
|
||||||
for _, file := range files {
|
for _, file := range files {
|
||||||
assert.Contains(t, posts[0].FileIds, file.Id)
|
assert.Contains(t, posts[0].FileIds, file.Id)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -325,6 +325,11 @@ func sampleDataCmdF(command *cobra.Command, args []string) error {
|
|||||||
user2 := allUsers[rand.Intn(len(allUsers))]
|
user2 := allUsers[rand.Intn(len(allUsers))]
|
||||||
channelLine := createDirectChannel([]string{user1, user2})
|
channelLine := createDirectChannel([]string{user1, user2})
|
||||||
encoder.Encode(channelLine)
|
encoder.Encode(channelLine)
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < directChannels; i++ {
|
||||||
|
user1 := allUsers[rand.Intn(len(allUsers))]
|
||||||
|
user2 := allUsers[rand.Intn(len(allUsers))]
|
||||||
|
|
||||||
dates := sortedRandomDates(postsPerDirectChannel)
|
dates := sortedRandomDates(postsPerDirectChannel)
|
||||||
for j := 0; j < postsPerDirectChannel; j++ {
|
for j := 0; j < postsPerDirectChannel; j++ {
|
||||||
@@ -344,6 +349,17 @@ func sampleDataCmdF(command *cobra.Command, args []string) error {
|
|||||||
}
|
}
|
||||||
channelLine := createDirectChannel(users)
|
channelLine := createDirectChannel(users)
|
||||||
encoder.Encode(channelLine)
|
encoder.Encode(channelLine)
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < groupChannels; i++ {
|
||||||
|
users := []string{}
|
||||||
|
totalUsers := 3 + rand.Intn(3)
|
||||||
|
for len(users) < totalUsers {
|
||||||
|
user := allUsers[rand.Intn(len(allUsers))]
|
||||||
|
if !sliceIncludes(users, user) {
|
||||||
|
users = append(users, user)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
dates := sortedRandomDates(postsPerGroupChannel)
|
dates := sortedRandomDates(postsPerGroupChannel)
|
||||||
for j := 0; j < postsPerGroupChannel; j++ {
|
for j := 0; j < postsPerGroupChannel; j++ {
|
||||||
|
|||||||
36
i18n/en.json
36
i18n/en.json
@@ -2958,6 +2958,14 @@
|
|||||||
"id": "app.import.emoji.bad_file.error",
|
"id": "app.import.emoji.bad_file.error",
|
||||||
"translation": "Error reading import emoji image file. Emoji with name: \"{{.EmojiName}}\""
|
"translation": "Error reading import emoji image file. Emoji with name: \"{{.EmojiName}}\""
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"id": "app.import.get_teams_by_names.some_teams_not_found.error",
|
||||||
|
"translation": "Some teams not found"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "app.import.get_users_by_username.some_users_not_found.error",
|
||||||
|
"translation": "Some users not found"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"id": "app.import.import_channel.scheme_deleted.error",
|
"id": "app.import.import_channel.scheme_deleted.error",
|
||||||
"translation": "Unable to set a channel to use a deleted scheme."
|
"translation": "Unable to set a channel to use a deleted scheme."
|
||||||
@@ -2978,18 +2986,10 @@
|
|||||||
"id": "app.import.import_direct_channel.create_group_channel.error",
|
"id": "app.import.import_direct_channel.create_group_channel.error",
|
||||||
"translation": "Failed to create group channel"
|
"translation": "Failed to create group channel"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"id": "app.import.import_direct_channel.member_not_found.error",
|
|
||||||
"translation": "Could not find channel member when importing direct channel"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"id": "app.import.import_direct_channel.update_header_failed.error",
|
"id": "app.import.import_direct_channel.update_header_failed.error",
|
||||||
"translation": "Failed to update direct channel header"
|
"translation": "Failed to update direct channel header"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"id": "app.import.import_direct_post.channel_member_not_found.error",
|
|
||||||
"translation": "Could not find channel member when importing direct channel post"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"id": "app.import.import_direct_post.create_direct_channel.error",
|
"id": "app.import.import_direct_post.create_direct_channel.error",
|
||||||
"translation": "Failed to get direct channel"
|
"translation": "Failed to get direct channel"
|
||||||
@@ -2998,14 +2998,6 @@
|
|||||||
"id": "app.import.import_direct_post.create_group_channel.error",
|
"id": "app.import.import_direct_post.create_group_channel.error",
|
||||||
"translation": "Failed to get group channel"
|
"translation": "Failed to get group channel"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"id": "app.import.import_direct_post.save_preferences.error",
|
|
||||||
"translation": "Error importing direct post. Failed to save preferences."
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "app.import.import_direct_post.user_not_found.error",
|
|
||||||
"translation": "Post user does not exist"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"id": "app.import.import_line.null_channel.error",
|
"id": "app.import.import_line.null_channel.error",
|
||||||
"translation": "Import data line has type \"channel\" but the channel object is null."
|
"translation": "Import data line has type \"channel\" but the channel object is null."
|
||||||
@@ -3050,10 +3042,6 @@
|
|||||||
"id": "app.import.import_post.save_preferences.error",
|
"id": "app.import.import_post.save_preferences.error",
|
||||||
"translation": "Error importing post. Failed to save preferences."
|
"translation": "Error importing post. Failed to save preferences."
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"id": "app.import.import_post.team_not_found.error",
|
|
||||||
"translation": "Error importing post. Team with name \"{{.TeamName}}\" could not be found."
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"id": "app.import.import_post.user_not_found.error",
|
"id": "app.import.import_post.user_not_found.error",
|
||||||
"translation": "Error importing post. User with username \"{{.Username}}\" could not be found."
|
"translation": "Error importing post. User with username \"{{.Username}}\" could not be found."
|
||||||
@@ -6982,6 +6970,14 @@
|
|||||||
"id": "store.sql_team.get_by_name.missing.app_error",
|
"id": "store.sql_team.get_by_name.missing.app_error",
|
||||||
"translation": "Unable to find the existing team."
|
"translation": "Unable to find the existing team."
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"id": "store.sql_team.get_by_names.app_error",
|
||||||
|
"translation": "Unable to get the teams by names"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "store.sql_team.get_by_names.missing.app_error",
|
||||||
|
"translation": "Unable to find some of the requested teams"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"id": "store.sql_team.get_by_scheme.app_error",
|
"id": "store.sql_team.get_by_scheme.app_error",
|
||||||
"translation": "Unable to get the channels for the provided scheme."
|
"translation": "Unable to get the channels for the provided scheme."
|
||||||
|
|||||||
@@ -30,6 +30,33 @@ type SqlPostStore struct {
|
|||||||
func (s *SqlPostStore) ClearCaches() {
|
func (s *SqlPostStore) ClearCaches() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func postSliceColumns() []string {
|
||||||
|
return []string{"Id", "CreateAt", "UpdateAt", "EditAt", "DeleteAt", "IsPinned", "UserId", "ChannelId", "RootId", "ParentId", "OriginalId", "Message", "Type", "Props", "Hashtags", "Filenames", "FileIds", "HasReactions"}
|
||||||
|
}
|
||||||
|
|
||||||
|
func postToSlice(post *model.Post) []interface{} {
|
||||||
|
return []interface{}{
|
||||||
|
post.Id,
|
||||||
|
post.CreateAt,
|
||||||
|
post.UpdateAt,
|
||||||
|
post.EditAt,
|
||||||
|
post.DeleteAt,
|
||||||
|
post.IsPinned,
|
||||||
|
post.UserId,
|
||||||
|
post.ChannelId,
|
||||||
|
post.RootId,
|
||||||
|
post.ParentId,
|
||||||
|
post.OriginalId,
|
||||||
|
post.Message,
|
||||||
|
post.Type,
|
||||||
|
model.StringInterfaceToJson(post.Props),
|
||||||
|
post.Hashtags,
|
||||||
|
model.ArrayToJson(post.Filenames),
|
||||||
|
model.ArrayToJson(post.FileIds),
|
||||||
|
post.HasReactions,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func newSqlPostStore(sqlStore SqlStore, metrics einterfaces.MetricsInterface) store.PostStore {
|
func newSqlPostStore(sqlStore SqlStore, metrics einterfaces.MetricsInterface) store.PostStore {
|
||||||
s := &SqlPostStore{
|
s := &SqlPostStore{
|
||||||
SqlStore: sqlStore,
|
SqlStore: sqlStore,
|
||||||
@@ -72,48 +99,97 @@ func (s *SqlPostStore) createIndexesIfNotExists() {
|
|||||||
s.CreateFullTextIndexIfNotExists("idx_posts_hashtags_txt", "Posts", "Hashtags")
|
s.CreateFullTextIndexIfNotExists("idx_posts_hashtags_txt", "Posts", "Hashtags")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *SqlPostStore) Save(post *model.Post) (*model.Post, *model.AppError) {
|
func (s *SqlPostStore) SaveMultiple(posts []*model.Post) ([]*model.Post, *model.AppError) {
|
||||||
if len(post.Id) > 0 {
|
channelNewPosts := make(map[string]int)
|
||||||
return nil, model.NewAppError("SqlPostStore.Save", "store.sql_post.save.existing.app_error", nil, "id="+post.Id, http.StatusBadRequest)
|
maxDateNewPosts := make(map[string]int64)
|
||||||
}
|
rootIds := make(map[string]int)
|
||||||
|
maxDateRootIds := make(map[string]int64)
|
||||||
maxPostSize := s.GetMaxPostSize()
|
for _, post := range posts {
|
||||||
|
if len(post.Id) > 0 {
|
||||||
post.PreSave()
|
return nil, model.NewAppError("SqlPostStore.Save", "store.sql_post.save.existing.app_error", nil, "id="+post.Id, http.StatusBadRequest)
|
||||||
if err := post.IsValid(maxPostSize); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := s.GetMaster().Insert(post); err != nil {
|
|
||||||
return nil, model.NewAppError("SqlPostStore.Save", "store.sql_post.save.app_error", nil, "id="+post.Id+", "+err.Error(), http.StatusInternalServerError)
|
|
||||||
}
|
|
||||||
|
|
||||||
time := post.UpdateAt
|
|
||||||
|
|
||||||
if !post.IsJoinLeaveMessage() {
|
|
||||||
if _, err := s.GetMaster().Exec("UPDATE Channels SET LastPostAt = GREATEST(:LastPostAt, LastPostAt), TotalMsgCount = TotalMsgCount + 1 WHERE Id = :ChannelId", map[string]interface{}{"LastPostAt": time, "ChannelId": post.ChannelId}); err != nil {
|
|
||||||
mlog.Error("Error updating Channel LastPostAt.", mlog.Err(err))
|
|
||||||
}
|
}
|
||||||
} else {
|
post.PreSave()
|
||||||
// don't update TotalMsgCount for unimportant messages so that the channel isn't marked as unread
|
maxPostSize := s.GetMaxPostSize()
|
||||||
if _, err := s.GetMaster().Exec("UPDATE Channels SET LastPostAt = :LastPostAt WHERE Id = :ChannelId AND LastPostAt < :LastPostAt", map[string]interface{}{"LastPostAt": time, "ChannelId": post.ChannelId}); err != nil {
|
if err := post.IsValid(maxPostSize); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
currentChannelCount, ok := channelNewPosts[post.ChannelId]
|
||||||
|
if !ok {
|
||||||
|
if post.IsJoinLeaveMessage() {
|
||||||
|
channelNewPosts[post.ChannelId] = 0
|
||||||
|
} else {
|
||||||
|
channelNewPosts[post.ChannelId] = 1
|
||||||
|
}
|
||||||
|
maxDateNewPosts[post.ChannelId] = post.CreateAt
|
||||||
|
} else {
|
||||||
|
if !post.IsJoinLeaveMessage() {
|
||||||
|
channelNewPosts[post.ChannelId] = currentChannelCount + 1
|
||||||
|
}
|
||||||
|
if post.CreateAt > maxDateNewPosts[post.ChannelId] {
|
||||||
|
maxDateNewPosts[post.ChannelId] = post.CreateAt
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(post.RootId) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
currentRootCount, ok := rootIds[post.RootId]
|
||||||
|
if !ok {
|
||||||
|
rootIds[post.RootId] = 1
|
||||||
|
maxDateRootIds[post.RootId] = post.CreateAt
|
||||||
|
} else {
|
||||||
|
rootIds[post.RootId] = currentRootCount + 1
|
||||||
|
if post.CreateAt > maxDateRootIds[post.RootId] {
|
||||||
|
maxDateRootIds[post.RootId] = post.CreateAt
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
query := s.getQueryBuilder().Insert("Posts").Columns(postSliceColumns()...)
|
||||||
|
for _, post := range posts {
|
||||||
|
query = query.Values(postToSlice(post)...)
|
||||||
|
}
|
||||||
|
sql, args, err := query.ToSql()
|
||||||
|
if err != nil {
|
||||||
|
return nil, model.NewAppError("SqlPostStore.Save", "store.sql_post.save.app_error", nil, err.Error(), http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := s.GetMaster().Exec(sql, args...); err != nil {
|
||||||
|
return nil, model.NewAppError("SqlPostStore.Save", "store.sql_post.save.app_error", nil, err.Error(), http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
|
||||||
|
for channelId, count := range channelNewPosts {
|
||||||
|
if _, err := s.GetMaster().Exec("UPDATE Channels SET LastPostAt = GREATEST(:LastPostAt, LastPostAt), TotalMsgCount = TotalMsgCount + :Count WHERE Id = :ChannelId", map[string]interface{}{"LastPostAt": maxDateNewPosts[channelId], "ChannelId": channelId, "Count": count}); err != nil {
|
||||||
mlog.Error("Error updating Channel LastPostAt.", mlog.Err(err))
|
mlog.Error("Error updating Channel LastPostAt.", mlog.Err(err))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(post.RootId) > 0 {
|
for rootId := range rootIds {
|
||||||
if _, err := s.GetMaster().Exec("UPDATE Posts SET UpdateAt = :UpdateAt WHERE Id = :RootId", map[string]interface{}{"UpdateAt": time, "RootId": post.RootId}); err != nil {
|
if _, err := s.GetMaster().Exec("UPDATE Posts SET UpdateAt = :UpdateAt WHERE Id = :RootId", map[string]interface{}{"UpdateAt": maxDateRootIds[rootId], "RootId": rootId}); err != nil {
|
||||||
mlog.Error("Error updating Post UpdateAt.", mlog.Err(err))
|
mlog.Error("Error updating Post UpdateAt.", mlog.Err(err))
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
if count, err := s.GetMaster().SelectInt("SELECT COUNT(*) FROM Posts WHERE RootId = :Id", map[string]interface{}{"Id": post.Id}); err != nil {
|
|
||||||
mlog.Error("Error fetching post's thread.", mlog.Err(err))
|
for _, post := range posts {
|
||||||
} else {
|
if len(post.RootId) == 0 {
|
||||||
post.ReplyCount = count
|
count, ok := rootIds[post.Id]
|
||||||
|
if ok {
|
||||||
|
post.ReplyCount += int64(count)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return post, nil
|
return posts, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *SqlPostStore) Save(post *model.Post) (*model.Post, *model.AppError) {
|
||||||
|
posts, err := s.SaveMultiple([]*model.Post{post})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return posts[0], nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *SqlPostStore) Update(newPost *model.Post, oldPost *model.Post) (*model.Post, *model.AppError) {
|
func (s *SqlPostStore) Update(newPost *model.Post, oldPost *model.Post) (*model.Post, *model.AppError) {
|
||||||
@@ -149,19 +225,45 @@ func (s *SqlPostStore) Update(newPost *model.Post, oldPost *model.Post) (*model.
|
|||||||
return newPost, nil
|
return newPost, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *SqlPostStore) Overwrite(post *model.Post) (*model.Post, *model.AppError) {
|
func (s *SqlPostStore) OverwriteMultiple(posts []*model.Post) ([]*model.Post, *model.AppError) {
|
||||||
post.UpdateAt = model.GetMillis()
|
updateAt := model.GetMillis()
|
||||||
|
|
||||||
maxPostSize := s.GetMaxPostSize()
|
maxPostSize := s.GetMaxPostSize()
|
||||||
if appErr := post.IsValid(maxPostSize); appErr != nil {
|
for _, post := range posts {
|
||||||
return nil, appErr
|
post.UpdateAt = updateAt
|
||||||
|
if appErr := post.IsValid(maxPostSize); appErr != nil {
|
||||||
|
return nil, appErr
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := s.GetMaster().Update(post); err != nil {
|
tx, err := s.GetMaster().Begin()
|
||||||
return nil, model.NewAppError("SqlPostStore.Overwrite", "store.sql_post.overwrite.app_error", nil, "id="+post.Id+", "+err.Error(), http.StatusInternalServerError)
|
if err != nil {
|
||||||
|
return nil, model.NewAppError("SqlPostStore.Overwrite", "store.sql_post.overwrite.app_error", nil, err.Error(), http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
for _, post := range posts {
|
||||||
|
if _, err = tx.Update(post); err != nil {
|
||||||
|
txErr := tx.Rollback()
|
||||||
|
if txErr != nil {
|
||||||
|
return nil, model.NewAppError("SqlPostStore.Overwrite", "store.sql_post.overwrite.app_error", nil, txErr.Error(), http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, model.NewAppError("SqlPostStore.Overwrite", "store.sql_post.overwrite.app_error", nil, "id="+post.Id+", "+err.Error(), http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
err = tx.Commit()
|
||||||
|
if err != nil {
|
||||||
|
return nil, model.NewAppError("SqlPostStore.Overwrite", "store.sql_post.overwrite.app_error", nil, err.Error(), http.StatusInternalServerError)
|
||||||
}
|
}
|
||||||
|
|
||||||
return post, nil
|
return posts, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *SqlPostStore) Overwrite(post *model.Post) (*model.Post, *model.AppError) {
|
||||||
|
posts, err := s.OverwriteMultiple([]*model.Post{post})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return posts[0], nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *SqlPostStore) GetFlaggedPosts(userId string, offset int, limit int) (*model.PostList, *model.AppError) {
|
func (s *SqlPostStore) GetFlaggedPosts(userId string, offset int, limit int) (*model.PostList, *model.AppError) {
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import (
|
|||||||
"github.com/mattermost/gorp"
|
"github.com/mattermost/gorp"
|
||||||
"github.com/mattermost/mattermost-server/v5/model"
|
"github.com/mattermost/mattermost-server/v5/model"
|
||||||
"github.com/mattermost/mattermost-server/v5/store"
|
"github.com/mattermost/mattermost-server/v5/store"
|
||||||
|
"github.com/mattermost/mattermost-server/v5/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -287,6 +288,33 @@ func (s SqlTeamStore) GetByName(name string) (*model.Team, *model.AppError) {
|
|||||||
return &team, nil
|
return &team, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s SqlTeamStore) GetByNames(names []string) ([]*model.Team, *model.AppError) {
|
||||||
|
uniqueNames := utils.RemoveDuplicatesFromStringArray(names)
|
||||||
|
|
||||||
|
query := s.getQueryBuilder().
|
||||||
|
Select("*").
|
||||||
|
From("Teams").
|
||||||
|
Where(sq.Eq{"Name": uniqueNames})
|
||||||
|
|
||||||
|
queryString, args, err := query.ToSql()
|
||||||
|
if err != nil {
|
||||||
|
return nil, model.NewAppError("SqlTeamStore.GetByNames", "store.sql_team.get_by_names.app_error", nil, err.Error(), http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
|
||||||
|
teams := []*model.Team{}
|
||||||
|
_, err = s.GetReplica().Select(&teams, queryString, args...)
|
||||||
|
if err != nil {
|
||||||
|
if err == sql.ErrNoRows {
|
||||||
|
return nil, model.NewAppError("SqlTeamStore.GetByNames", "store.sql_team.get_by_names.missing.app_error", nil, err.Error(), http.StatusNotFound)
|
||||||
|
}
|
||||||
|
return nil, model.NewAppError("SqlTeamStore.GetByNames", "store.sql_team.get_by_names.app_error", nil, err.Error(), http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
if len(teams) != len(uniqueNames) {
|
||||||
|
return nil, model.NewAppError("SqlTeamStore.GetByNames", "store.sql_team.get_by_names.missing.app_error", nil, "", http.StatusNotFound)
|
||||||
|
}
|
||||||
|
return teams, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (s SqlTeamStore) SearchAll(term string) ([]*model.Team, *model.AppError) {
|
func (s SqlTeamStore) SearchAll(term string) ([]*model.Team, *model.AppError) {
|
||||||
var teams []*model.Team
|
var teams []*model.Team
|
||||||
|
|
||||||
|
|||||||
@@ -67,6 +67,7 @@ type TeamStore interface {
|
|||||||
Update(team *model.Team) (*model.Team, *model.AppError)
|
Update(team *model.Team) (*model.Team, *model.AppError)
|
||||||
Get(id string) (*model.Team, *model.AppError)
|
Get(id string) (*model.Team, *model.AppError)
|
||||||
GetByName(name string) (*model.Team, *model.AppError)
|
GetByName(name string) (*model.Team, *model.AppError)
|
||||||
|
GetByNames(name []string) ([]*model.Team, *model.AppError)
|
||||||
SearchAll(term string) ([]*model.Team, *model.AppError)
|
SearchAll(term string) ([]*model.Team, *model.AppError)
|
||||||
SearchAllPaged(term string, page int, perPage int) ([]*model.Team, int64, *model.AppError)
|
SearchAllPaged(term string, page int, perPage int) ([]*model.Team, int64, *model.AppError)
|
||||||
SearchOpen(term string) ([]*model.Team, *model.AppError)
|
SearchOpen(term string) ([]*model.Team, *model.AppError)
|
||||||
@@ -218,6 +219,7 @@ type ChannelMemberHistoryStore interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type PostStore interface {
|
type PostStore interface {
|
||||||
|
SaveMultiple(posts []*model.Post) ([]*model.Post, *model.AppError)
|
||||||
Save(post *model.Post) (*model.Post, *model.AppError)
|
Save(post *model.Post) (*model.Post, *model.AppError)
|
||||||
Update(newPost *model.Post, oldPost *model.Post) (*model.Post, *model.AppError)
|
Update(newPost *model.Post, oldPost *model.Post) (*model.Post, *model.AppError)
|
||||||
Get(id string, skipFetchThreads bool) (*model.PostList, *model.AppError)
|
Get(id string, skipFetchThreads bool) (*model.PostList, *model.AppError)
|
||||||
@@ -245,6 +247,7 @@ type PostStore interface {
|
|||||||
InvalidateLastPostTimeCache(channelId string)
|
InvalidateLastPostTimeCache(channelId string)
|
||||||
GetPostsCreatedAt(channelId string, time int64) ([]*model.Post, *model.AppError)
|
GetPostsCreatedAt(channelId string, time int64) ([]*model.Post, *model.AppError)
|
||||||
Overwrite(post *model.Post) (*model.Post, *model.AppError)
|
Overwrite(post *model.Post) (*model.Post, *model.AppError)
|
||||||
|
OverwriteMultiple(posts []*model.Post) ([]*model.Post, *model.AppError)
|
||||||
GetPostsByIds(postIds []string) ([]*model.Post, *model.AppError)
|
GetPostsByIds(postIds []string) ([]*model.Post, *model.AppError)
|
||||||
GetPostsBatchForIndexing(startTime int64, endTime int64, limit int) ([]*model.PostForIndexing, *model.AppError)
|
GetPostsBatchForIndexing(startTime int64, endTime int64, limit int) ([]*model.PostForIndexing, *model.AppError)
|
||||||
PermanentDeleteBatch(endTime int64, limit int64) (int64, *model.AppError)
|
PermanentDeleteBatch(endTime int64, limit int64) (int64, *model.AppError)
|
||||||
|
|||||||
@@ -637,6 +637,31 @@ func (_m *PostStore) Overwrite(post *model.Post) (*model.Post, *model.AppError)
|
|||||||
return r0, r1
|
return r0, r1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// OverwriteMultiple provides a mock function with given fields: posts
|
||||||
|
func (_m *PostStore) OverwriteMultiple(posts []*model.Post) ([]*model.Post, *model.AppError) {
|
||||||
|
ret := _m.Called(posts)
|
||||||
|
|
||||||
|
var r0 []*model.Post
|
||||||
|
if rf, ok := ret.Get(0).(func([]*model.Post) []*model.Post); ok {
|
||||||
|
r0 = rf(posts)
|
||||||
|
} else {
|
||||||
|
if ret.Get(0) != nil {
|
||||||
|
r0 = ret.Get(0).([]*model.Post)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var r1 *model.AppError
|
||||||
|
if rf, ok := ret.Get(1).(func([]*model.Post) *model.AppError); ok {
|
||||||
|
r1 = rf(posts)
|
||||||
|
} else {
|
||||||
|
if ret.Get(1) != nil {
|
||||||
|
r1 = ret.Get(1).(*model.AppError)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return r0, r1
|
||||||
|
}
|
||||||
|
|
||||||
// PermanentDeleteBatch provides a mock function with given fields: endTime, limit
|
// PermanentDeleteBatch provides a mock function with given fields: endTime, limit
|
||||||
func (_m *PostStore) PermanentDeleteBatch(endTime int64, limit int64) (int64, *model.AppError) {
|
func (_m *PostStore) PermanentDeleteBatch(endTime int64, limit int64) (int64, *model.AppError) {
|
||||||
ret := _m.Called(endTime, limit)
|
ret := _m.Called(endTime, limit)
|
||||||
@@ -717,6 +742,31 @@ func (_m *PostStore) Save(post *model.Post) (*model.Post, *model.AppError) {
|
|||||||
return r0, r1
|
return r0, r1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SaveMultiple provides a mock function with given fields: posts
|
||||||
|
func (_m *PostStore) SaveMultiple(posts []*model.Post) ([]*model.Post, *model.AppError) {
|
||||||
|
ret := _m.Called(posts)
|
||||||
|
|
||||||
|
var r0 []*model.Post
|
||||||
|
if rf, ok := ret.Get(0).(func([]*model.Post) []*model.Post); ok {
|
||||||
|
r0 = rf(posts)
|
||||||
|
} else {
|
||||||
|
if ret.Get(0) != nil {
|
||||||
|
r0 = ret.Get(0).([]*model.Post)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var r1 *model.AppError
|
||||||
|
if rf, ok := ret.Get(1).(func([]*model.Post) *model.AppError); ok {
|
||||||
|
r1 = rf(posts)
|
||||||
|
} else {
|
||||||
|
if ret.Get(1) != nil {
|
||||||
|
r1 = ret.Get(1).(*model.AppError)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return r0, r1
|
||||||
|
}
|
||||||
|
|
||||||
// Search provides a mock function with given fields: teamId, userId, params
|
// Search provides a mock function with given fields: teamId, userId, params
|
||||||
func (_m *PostStore) Search(teamId string, userId string, params *model.SearchParams) (*model.PostList, *model.AppError) {
|
func (_m *PostStore) Search(teamId string, userId string, params *model.SearchParams) (*model.PostList, *model.AppError) {
|
||||||
ret := _m.Called(teamId, userId, params)
|
ret := _m.Called(teamId, userId, params)
|
||||||
|
|||||||
@@ -425,6 +425,31 @@ func (_m *TeamStore) GetByName(name string) (*model.Team, *model.AppError) {
|
|||||||
return r0, r1
|
return r0, r1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetByNames provides a mock function with given fields: name
|
||||||
|
func (_m *TeamStore) GetByNames(name []string) ([]*model.Team, *model.AppError) {
|
||||||
|
ret := _m.Called(name)
|
||||||
|
|
||||||
|
var r0 []*model.Team
|
||||||
|
if rf, ok := ret.Get(0).(func([]string) []*model.Team); ok {
|
||||||
|
r0 = rf(name)
|
||||||
|
} else {
|
||||||
|
if ret.Get(0) != nil {
|
||||||
|
r0 = ret.Get(0).([]*model.Team)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var r1 *model.AppError
|
||||||
|
if rf, ok := ret.Get(1).(func([]string) *model.AppError); ok {
|
||||||
|
r1 = rf(name)
|
||||||
|
} else {
|
||||||
|
if ret.Get(1) != nil {
|
||||||
|
r1 = ret.Get(1).(*model.AppError)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return r0, r1
|
||||||
|
}
|
||||||
|
|
||||||
// GetChannelUnreadsForAllTeams provides a mock function with given fields: excludeTeamId, userId
|
// GetChannelUnreadsForAllTeams provides a mock function with given fields: excludeTeamId, userId
|
||||||
func (_m *TeamStore) GetChannelUnreadsForAllTeams(excludeTeamId string, userId string) ([]*model.ChannelUnread, *model.AppError) {
|
func (_m *TeamStore) GetChannelUnreadsForAllTeams(excludeTeamId string, userId string) ([]*model.ChannelUnread, *model.AppError) {
|
||||||
ret := _m.Called(excludeTeamId, userId)
|
ret := _m.Called(excludeTeamId, userId)
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestPostStore(t *testing.T, ss store.Store, s SqlSupplier) {
|
func TestPostStore(t *testing.T, ss store.Store, s SqlSupplier) {
|
||||||
|
t.Run("SaveMultiple", func(t *testing.T) { testPostStoreSaveMultiple(t, ss) })
|
||||||
t.Run("Save", func(t *testing.T) { testPostStoreSave(t, ss) })
|
t.Run("Save", func(t *testing.T) { testPostStoreSave(t, ss) })
|
||||||
t.Run("SaveAndUpdateChannelMsgCounts", func(t *testing.T) { testPostStoreSaveChannelMsgCounts(t, ss) })
|
t.Run("SaveAndUpdateChannelMsgCounts", func(t *testing.T) { testPostStoreSaveChannelMsgCounts(t, ss) })
|
||||||
t.Run("Get", func(t *testing.T) { testPostStoreGet(t, ss) })
|
t.Run("Get", func(t *testing.T) { testPostStoreGet(t, ss) })
|
||||||
@@ -41,6 +42,7 @@ func TestPostStore(t *testing.T, ss store.Store, s SqlSupplier) {
|
|||||||
t.Run("GetFlaggedPostsForChannel", func(t *testing.T) { testPostStoreGetFlaggedPostsForChannel(t, ss) })
|
t.Run("GetFlaggedPostsForChannel", func(t *testing.T) { testPostStoreGetFlaggedPostsForChannel(t, ss) })
|
||||||
t.Run("GetPostsCreatedAt", func(t *testing.T) { testPostStoreGetPostsCreatedAt(t, ss) })
|
t.Run("GetPostsCreatedAt", func(t *testing.T) { testPostStoreGetPostsCreatedAt(t, ss) })
|
||||||
t.Run("Overwrite", func(t *testing.T) { testPostStoreOverwrite(t, ss) })
|
t.Run("Overwrite", func(t *testing.T) { testPostStoreOverwrite(t, ss) })
|
||||||
|
t.Run("OverwriteMultiple", func(t *testing.T) { testPostStoreOverwriteMultiple(t, ss) })
|
||||||
t.Run("GetPostsByIds", func(t *testing.T) { testPostStoreGetPostsByIds(t, ss) })
|
t.Run("GetPostsByIds", func(t *testing.T) { testPostStoreGetPostsByIds(t, ss) })
|
||||||
t.Run("GetPostsBatchForIndexing", func(t *testing.T) { testPostStoreGetPostsBatchForIndexing(t, ss) })
|
t.Run("GetPostsBatchForIndexing", func(t *testing.T) { testPostStoreGetPostsBatchForIndexing(t, ss) })
|
||||||
t.Run("PermanentDeleteBatch", func(t *testing.T) { testPostStorePermanentDeleteBatch(t, ss) })
|
t.Run("PermanentDeleteBatch", func(t *testing.T) { testPostStorePermanentDeleteBatch(t, ss) })
|
||||||
@@ -54,16 +56,223 @@ func TestPostStore(t *testing.T, ss store.Store, s SqlSupplier) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func testPostStoreSave(t *testing.T, ss store.Store) {
|
func testPostStoreSave(t *testing.T, ss store.Store) {
|
||||||
o1 := model.Post{}
|
t.Run("Save post", func(t *testing.T) {
|
||||||
o1.ChannelId = model.NewId()
|
o1 := model.Post{}
|
||||||
o1.UserId = model.NewId()
|
o1.ChannelId = model.NewId()
|
||||||
o1.Message = "zz" + model.NewId() + "b"
|
o1.UserId = model.NewId()
|
||||||
|
o1.Message = "zz" + model.NewId() + "b"
|
||||||
|
|
||||||
_, err := ss.Post().Save(&o1)
|
_, err := ss.Post().Save(&o1)
|
||||||
require.Nil(t, err, "couldn't save item")
|
require.Nil(t, err, "couldn't save item")
|
||||||
|
})
|
||||||
|
|
||||||
_, err = ss.Post().Save(&o1)
|
t.Run("Try to save existing post", func(t *testing.T) {
|
||||||
require.NotNil(t, err, "shouldn't be able to update from save")
|
o1 := model.Post{}
|
||||||
|
o1.ChannelId = model.NewId()
|
||||||
|
o1.UserId = model.NewId()
|
||||||
|
o1.Message = "zz" + model.NewId() + "b"
|
||||||
|
|
||||||
|
_, err := ss.Post().Save(&o1)
|
||||||
|
require.Nil(t, err, "couldn't save item")
|
||||||
|
|
||||||
|
_, err = ss.Post().Save(&o1)
|
||||||
|
require.NotNil(t, err, "shouldn't be able to update from save")
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Update reply should update the UpdateAt of the root post", func(t *testing.T) {
|
||||||
|
rootPost := model.Post{}
|
||||||
|
rootPost.ChannelId = model.NewId()
|
||||||
|
rootPost.UserId = model.NewId()
|
||||||
|
rootPost.Message = "zz" + model.NewId() + "b"
|
||||||
|
|
||||||
|
_, err := ss.Post().Save(&rootPost)
|
||||||
|
require.Nil(t, err)
|
||||||
|
|
||||||
|
replyPost := model.Post{}
|
||||||
|
replyPost.ChannelId = rootPost.ChannelId
|
||||||
|
replyPost.UserId = model.NewId()
|
||||||
|
replyPost.Message = "zz" + model.NewId() + "b"
|
||||||
|
replyPost.RootId = rootPost.Id
|
||||||
|
|
||||||
|
_, err = ss.Post().Save(&replyPost)
|
||||||
|
require.Nil(t, err)
|
||||||
|
|
||||||
|
rrootPost, err := ss.Post().GetSingle(rootPost.Id)
|
||||||
|
require.Nil(t, err)
|
||||||
|
assert.Greater(t, rrootPost.UpdateAt, rootPost.UpdateAt)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Create a post should update the channel LastPostAt and the total messages count by one", func(t *testing.T) {
|
||||||
|
channel := model.Channel{}
|
||||||
|
channel.Name = "zz" + model.NewId() + "b"
|
||||||
|
channel.DisplayName = "zz" + model.NewId() + "b"
|
||||||
|
channel.Type = model.CHANNEL_OPEN
|
||||||
|
|
||||||
|
_, err := ss.Channel().Save(&channel, 100)
|
||||||
|
require.Nil(t, err)
|
||||||
|
|
||||||
|
post := model.Post{}
|
||||||
|
post.ChannelId = channel.Id
|
||||||
|
post.UserId = model.NewId()
|
||||||
|
post.Message = "zz" + model.NewId() + "b"
|
||||||
|
|
||||||
|
_, err = ss.Post().Save(&post)
|
||||||
|
require.Nil(t, err)
|
||||||
|
|
||||||
|
rchannel, err := ss.Channel().Get(channel.Id, false)
|
||||||
|
require.Nil(t, err)
|
||||||
|
assert.Greater(t, rchannel.LastPostAt, channel.LastPostAt)
|
||||||
|
assert.Equal(t, int64(1), rchannel.TotalMsgCount)
|
||||||
|
|
||||||
|
post = model.Post{}
|
||||||
|
post.ChannelId = channel.Id
|
||||||
|
post.UserId = model.NewId()
|
||||||
|
post.Message = "zz" + model.NewId() + "b"
|
||||||
|
post.CreateAt = 5
|
||||||
|
|
||||||
|
_, err = ss.Post().Save(&post)
|
||||||
|
require.Nil(t, err)
|
||||||
|
|
||||||
|
rchannel2, err := ss.Channel().Get(channel.Id, false)
|
||||||
|
require.Nil(t, err)
|
||||||
|
assert.Equal(t, rchannel.LastPostAt, rchannel2.LastPostAt)
|
||||||
|
assert.Equal(t, int64(2), rchannel2.TotalMsgCount)
|
||||||
|
|
||||||
|
post = model.Post{}
|
||||||
|
post.ChannelId = channel.Id
|
||||||
|
post.UserId = model.NewId()
|
||||||
|
post.Message = "zz" + model.NewId() + "b"
|
||||||
|
|
||||||
|
_, err = ss.Post().Save(&post)
|
||||||
|
require.Nil(t, err)
|
||||||
|
|
||||||
|
rchannel3, err := ss.Channel().Get(channel.Id, false)
|
||||||
|
require.Nil(t, err)
|
||||||
|
assert.Greater(t, rchannel3.LastPostAt, rchannel2.LastPostAt)
|
||||||
|
assert.Equal(t, int64(3), rchannel3.TotalMsgCount)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func testPostStoreSaveMultiple(t *testing.T, ss store.Store) {
|
||||||
|
p1 := model.Post{}
|
||||||
|
p1.ChannelId = model.NewId()
|
||||||
|
p1.UserId = model.NewId()
|
||||||
|
p1.Message = "zz" + model.NewId() + "b"
|
||||||
|
|
||||||
|
p2 := model.Post{}
|
||||||
|
p2.ChannelId = model.NewId()
|
||||||
|
p2.UserId = model.NewId()
|
||||||
|
p2.Message = "zz" + model.NewId() + "b"
|
||||||
|
|
||||||
|
p3 := model.Post{}
|
||||||
|
p3.ChannelId = model.NewId()
|
||||||
|
p3.UserId = model.NewId()
|
||||||
|
p3.Message = "zz" + model.NewId() + "b"
|
||||||
|
|
||||||
|
p4 := model.Post{}
|
||||||
|
p4.ChannelId = model.NewId()
|
||||||
|
p4.UserId = model.NewId()
|
||||||
|
p4.Message = "zz" + model.NewId() + "b"
|
||||||
|
|
||||||
|
t.Run("Save correctly a new set of posts", func(t *testing.T) {
|
||||||
|
newPosts, err := ss.Post().SaveMultiple([]*model.Post{&p1, &p2, &p3})
|
||||||
|
require.Nil(t, err)
|
||||||
|
for _, post := range newPosts {
|
||||||
|
storedPost, err := ss.Post().GetSingle(post.Id)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Equal(t, post.ChannelId, storedPost.ChannelId)
|
||||||
|
assert.Equal(t, post.Message, storedPost.Message)
|
||||||
|
assert.Equal(t, post.UserId, storedPost.UserId)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Try to save mixed, already saved and not saved posts", func(t *testing.T) {
|
||||||
|
newPosts, err := ss.Post().SaveMultiple([]*model.Post{&p4, &p3})
|
||||||
|
require.NotNil(t, err)
|
||||||
|
require.Nil(t, newPosts)
|
||||||
|
storedPost, err := ss.Post().GetSingle(p3.Id)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Equal(t, p3.ChannelId, storedPost.ChannelId)
|
||||||
|
assert.Equal(t, p3.Message, storedPost.Message)
|
||||||
|
assert.Equal(t, p3.UserId, storedPost.UserId)
|
||||||
|
|
||||||
|
storedPost, err = ss.Post().GetSingle(p4.Id)
|
||||||
|
assert.NotNil(t, err)
|
||||||
|
assert.Nil(t, storedPost)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Update reply should update the UpdateAt of the root post", func(t *testing.T) {
|
||||||
|
rootPost := model.Post{}
|
||||||
|
rootPost.ChannelId = model.NewId()
|
||||||
|
rootPost.UserId = model.NewId()
|
||||||
|
rootPost.Message = "zz" + model.NewId() + "b"
|
||||||
|
|
||||||
|
replyPost := model.Post{}
|
||||||
|
replyPost.ChannelId = rootPost.ChannelId
|
||||||
|
replyPost.UserId = model.NewId()
|
||||||
|
replyPost.Message = "zz" + model.NewId() + "b"
|
||||||
|
replyPost.RootId = rootPost.Id
|
||||||
|
|
||||||
|
_, err := ss.Post().SaveMultiple([]*model.Post{&rootPost, &replyPost})
|
||||||
|
require.Nil(t, err)
|
||||||
|
|
||||||
|
rrootPost, err := ss.Post().GetSingle(rootPost.Id)
|
||||||
|
require.Nil(t, err)
|
||||||
|
assert.Equal(t, rrootPost.UpdateAt, rootPost.UpdateAt)
|
||||||
|
|
||||||
|
replyPost2 := model.Post{}
|
||||||
|
replyPost2.ChannelId = rootPost.ChannelId
|
||||||
|
replyPost2.UserId = model.NewId()
|
||||||
|
replyPost2.Message = "zz" + model.NewId() + "b"
|
||||||
|
replyPost2.RootId = rootPost.Id
|
||||||
|
|
||||||
|
replyPost3 := model.Post{}
|
||||||
|
replyPost3.ChannelId = rootPost.ChannelId
|
||||||
|
replyPost3.UserId = model.NewId()
|
||||||
|
replyPost3.Message = "zz" + model.NewId() + "b"
|
||||||
|
replyPost3.RootId = rootPost.Id
|
||||||
|
|
||||||
|
_, err = ss.Post().SaveMultiple([]*model.Post{&replyPost2, &replyPost3})
|
||||||
|
require.Nil(t, err)
|
||||||
|
|
||||||
|
rrootPost2, err := ss.Post().GetSingle(rootPost.Id)
|
||||||
|
require.Nil(t, err)
|
||||||
|
assert.Greater(t, rrootPost2.UpdateAt, rrootPost.UpdateAt)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Create a post should update the channel LastPostAt and the total messages count by one", func(t *testing.T) {
|
||||||
|
channel := model.Channel{}
|
||||||
|
channel.Name = "zz" + model.NewId() + "b"
|
||||||
|
channel.DisplayName = "zz" + model.NewId() + "b"
|
||||||
|
channel.Type = model.CHANNEL_OPEN
|
||||||
|
|
||||||
|
_, err := ss.Channel().Save(&channel, 100)
|
||||||
|
require.Nil(t, err)
|
||||||
|
|
||||||
|
post1 := model.Post{}
|
||||||
|
post1.ChannelId = channel.Id
|
||||||
|
post1.UserId = model.NewId()
|
||||||
|
post1.Message = "zz" + model.NewId() + "b"
|
||||||
|
|
||||||
|
post2 := model.Post{}
|
||||||
|
post2.ChannelId = channel.Id
|
||||||
|
post2.UserId = model.NewId()
|
||||||
|
post2.Message = "zz" + model.NewId() + "b"
|
||||||
|
post2.CreateAt = 5
|
||||||
|
|
||||||
|
post3 := model.Post{}
|
||||||
|
post3.ChannelId = channel.Id
|
||||||
|
post3.UserId = model.NewId()
|
||||||
|
post3.Message = "zz" + model.NewId() + "b"
|
||||||
|
|
||||||
|
_, err = ss.Post().SaveMultiple([]*model.Post{&post1, &post2, &post3})
|
||||||
|
require.Nil(t, err)
|
||||||
|
|
||||||
|
rchannel, err := ss.Channel().Get(channel.Id, false)
|
||||||
|
require.Nil(t, err)
|
||||||
|
assert.Greater(t, rchannel.LastPostAt, channel.LastPostAt)
|
||||||
|
assert.Equal(t, int64(3), rchannel.TotalMsgCount)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func testPostStoreSaveChannelMsgCounts(t *testing.T, ss store.Store) {
|
func testPostStoreSaveChannelMsgCounts(t *testing.T, ss store.Store) {
|
||||||
@@ -2005,6 +2214,136 @@ func testPostStoreGetPostsCreatedAt(t *testing.T, ss store.Store) {
|
|||||||
assert.Equal(t, 2, len(r1))
|
assert.Equal(t, 2, len(r1))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func testPostStoreOverwriteMultiple(t *testing.T, ss store.Store) {
|
||||||
|
o1 := &model.Post{}
|
||||||
|
o1.ChannelId = model.NewId()
|
||||||
|
o1.UserId = model.NewId()
|
||||||
|
o1.Message = "zz" + model.NewId() + "AAAAAAAAAAA"
|
||||||
|
o1, err := ss.Post().Save(o1)
|
||||||
|
require.Nil(t, err)
|
||||||
|
|
||||||
|
o2 := &model.Post{}
|
||||||
|
o2.ChannelId = o1.ChannelId
|
||||||
|
o2.UserId = model.NewId()
|
||||||
|
o2.Message = "zz" + model.NewId() + "CCCCCCCCC"
|
||||||
|
o2.ParentId = o1.Id
|
||||||
|
o2.RootId = o1.Id
|
||||||
|
o2, err = ss.Post().Save(o2)
|
||||||
|
require.Nil(t, err)
|
||||||
|
|
||||||
|
o3 := &model.Post{}
|
||||||
|
o3.ChannelId = o1.ChannelId
|
||||||
|
o3.UserId = model.NewId()
|
||||||
|
o3.Message = "zz" + model.NewId() + "QQQQQQQQQQ"
|
||||||
|
o3, err = ss.Post().Save(o3)
|
||||||
|
require.Nil(t, err)
|
||||||
|
|
||||||
|
o4, err := ss.Post().Save(&model.Post{
|
||||||
|
ChannelId: model.NewId(),
|
||||||
|
UserId: model.NewId(),
|
||||||
|
Message: model.NewId(),
|
||||||
|
Filenames: []string{"test"},
|
||||||
|
})
|
||||||
|
require.Nil(t, err)
|
||||||
|
|
||||||
|
o5, err := ss.Post().Save(&model.Post{
|
||||||
|
ChannelId: model.NewId(),
|
||||||
|
UserId: model.NewId(),
|
||||||
|
Message: model.NewId(),
|
||||||
|
Filenames: []string{"test2", "test3"},
|
||||||
|
})
|
||||||
|
require.Nil(t, err)
|
||||||
|
|
||||||
|
r1, err := ss.Post().Get(o1.Id, false)
|
||||||
|
require.Nil(t, err)
|
||||||
|
ro1 := r1.Posts[o1.Id]
|
||||||
|
|
||||||
|
r2, err := ss.Post().Get(o2.Id, false)
|
||||||
|
require.Nil(t, err)
|
||||||
|
ro2 := r2.Posts[o2.Id]
|
||||||
|
|
||||||
|
r3, err := ss.Post().Get(o3.Id, false)
|
||||||
|
require.Nil(t, err)
|
||||||
|
ro3 := r3.Posts[o3.Id]
|
||||||
|
|
||||||
|
r4, err := ss.Post().Get(o4.Id, false)
|
||||||
|
require.Nil(t, err)
|
||||||
|
ro4 := r4.Posts[o4.Id]
|
||||||
|
|
||||||
|
r5, err := ss.Post().Get(o5.Id, false)
|
||||||
|
require.Nil(t, err)
|
||||||
|
ro5 := r5.Posts[o5.Id]
|
||||||
|
|
||||||
|
require.Equal(t, ro1.Message, o1.Message, "Failed to save/get")
|
||||||
|
require.Equal(t, ro2.Message, o2.Message, "Failed to save/get")
|
||||||
|
require.Equal(t, ro3.Message, o3.Message, "Failed to save/get")
|
||||||
|
require.Equal(t, ro4.Message, o4.Message, "Failed to save/get")
|
||||||
|
require.Equal(t, ro4.Filenames, o4.Filenames, "Failed to save/get")
|
||||||
|
require.Equal(t, ro5.Message, o5.Message, "Failed to save/get")
|
||||||
|
require.Equal(t, ro5.Filenames, o5.Filenames, "Failed to save/get")
|
||||||
|
|
||||||
|
t.Run("overwrite changing message", func(t *testing.T) {
|
||||||
|
o1a := &model.Post{}
|
||||||
|
*o1a = *ro1
|
||||||
|
o1a.Message = ro1.Message + "BBBBBBBBBB"
|
||||||
|
|
||||||
|
o2a := &model.Post{}
|
||||||
|
*o2a = *ro2
|
||||||
|
o2a.Message = ro2.Message + "DDDDDDD"
|
||||||
|
|
||||||
|
o3a := &model.Post{}
|
||||||
|
*o3a = *ro3
|
||||||
|
o3a.Message = ro3.Message + "WWWWWWW"
|
||||||
|
|
||||||
|
_, err = ss.Post().OverwriteMultiple([]*model.Post{o1a, o2a, o3a})
|
||||||
|
require.Nil(t, err)
|
||||||
|
|
||||||
|
r1, err = ss.Post().Get(o1.Id, false)
|
||||||
|
require.Nil(t, err)
|
||||||
|
ro1a := r1.Posts[o1.Id]
|
||||||
|
|
||||||
|
r2, err = ss.Post().Get(o1.Id, false)
|
||||||
|
require.Nil(t, err)
|
||||||
|
ro2a := r2.Posts[o2.Id]
|
||||||
|
|
||||||
|
r3, err = ss.Post().Get(o3.Id, false)
|
||||||
|
require.Nil(t, err)
|
||||||
|
ro3a := r3.Posts[o3.Id]
|
||||||
|
|
||||||
|
assert.Equal(t, ro1a.Message, o1a.Message, "Failed to overwrite/get")
|
||||||
|
assert.Equal(t, ro2a.Message, o2a.Message, "Failed to overwrite/get")
|
||||||
|
assert.Equal(t, ro3a.Message, o3a.Message, "Failed to overwrite/get")
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("overwrite clearing filenames", func(t *testing.T) {
|
||||||
|
o4a := &model.Post{}
|
||||||
|
*o4a = *ro4
|
||||||
|
o4a.Filenames = []string{}
|
||||||
|
o4a.FileIds = []string{model.NewId()}
|
||||||
|
|
||||||
|
o5a := &model.Post{}
|
||||||
|
*o5a = *ro5
|
||||||
|
o5a.Filenames = []string{}
|
||||||
|
o5a.FileIds = []string{}
|
||||||
|
|
||||||
|
_, err = ss.Post().OverwriteMultiple([]*model.Post{o4a, o5a})
|
||||||
|
require.Nil(t, err)
|
||||||
|
|
||||||
|
r4, err = ss.Post().Get(o4.Id, false)
|
||||||
|
require.Nil(t, err)
|
||||||
|
ro4a := r4.Posts[o4.Id]
|
||||||
|
|
||||||
|
r5, err = ss.Post().Get(o5.Id, false)
|
||||||
|
require.Nil(t, err)
|
||||||
|
ro5a := r5.Posts[o5.Id]
|
||||||
|
|
||||||
|
require.Empty(t, ro4a.Filenames, "Failed to clear Filenames")
|
||||||
|
require.Len(t, ro4a.FileIds, 1, "Failed to set FileIds")
|
||||||
|
require.Empty(t, ro5a.Filenames, "Failed to clear Filenames")
|
||||||
|
require.Empty(t, ro5a.FileIds, "Failed to set FileIds")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func testPostStoreOverwrite(t *testing.T, ss store.Store) {
|
func testPostStoreOverwrite(t *testing.T, ss store.Store) {
|
||||||
o1 := &model.Post{}
|
o1 := &model.Post{}
|
||||||
o1.ChannelId = model.NewId()
|
o1.ChannelId = model.NewId()
|
||||||
@@ -2029,56 +2368,6 @@ func testPostStoreOverwrite(t *testing.T, ss store.Store) {
|
|||||||
o3, err = ss.Post().Save(o3)
|
o3, err = ss.Post().Save(o3)
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
|
|
||||||
r1, err := ss.Post().Get(o1.Id, false)
|
|
||||||
require.Nil(t, err)
|
|
||||||
ro1 := r1.Posts[o1.Id]
|
|
||||||
|
|
||||||
r2, err := ss.Post().Get(o1.Id, false)
|
|
||||||
require.Nil(t, err)
|
|
||||||
ro2 := r2.Posts[o2.Id]
|
|
||||||
|
|
||||||
r3, err := ss.Post().Get(o3.Id, false)
|
|
||||||
require.Nil(t, err)
|
|
||||||
ro3 := r3.Posts[o3.Id]
|
|
||||||
|
|
||||||
require.Equal(t, ro1.Message, o1.Message, "Failed to save/get")
|
|
||||||
|
|
||||||
o1a := &model.Post{}
|
|
||||||
*o1a = *ro1
|
|
||||||
o1a.Message = ro1.Message + "BBBBBBBBBB"
|
|
||||||
_, err = ss.Post().Overwrite(o1a)
|
|
||||||
require.Nil(t, err)
|
|
||||||
|
|
||||||
r1, err = ss.Post().Get(o1.Id, false)
|
|
||||||
require.Nil(t, err)
|
|
||||||
ro1a := r1.Posts[o1.Id]
|
|
||||||
|
|
||||||
require.Equal(t, ro1a.Message, o1a.Message, "Failed to overwrite/get")
|
|
||||||
|
|
||||||
o2a := &model.Post{}
|
|
||||||
*o2a = *ro2
|
|
||||||
o2a.Message = ro2.Message + "DDDDDDD"
|
|
||||||
_, err = ss.Post().Overwrite(o2a)
|
|
||||||
require.Nil(t, err)
|
|
||||||
|
|
||||||
r2, err = ss.Post().Get(o1.Id, false)
|
|
||||||
require.Nil(t, err)
|
|
||||||
ro2a := r2.Posts[o2.Id]
|
|
||||||
|
|
||||||
require.Equal(t, ro2a.Message, o2a.Message, "Failed to overwrite/get")
|
|
||||||
|
|
||||||
o3a := &model.Post{}
|
|
||||||
*o3a = *ro3
|
|
||||||
o3a.Message = ro3.Message + "WWWWWWW"
|
|
||||||
_, err = ss.Post().Overwrite(o3a)
|
|
||||||
require.Nil(t, err)
|
|
||||||
|
|
||||||
r3, err = ss.Post().Get(o3.Id, false)
|
|
||||||
require.Nil(t, err)
|
|
||||||
ro3a := r3.Posts[o3.Id]
|
|
||||||
|
|
||||||
require.Equal(t, ro3a.Message, o3a.Message, "Failed to overwrite/get")
|
|
||||||
|
|
||||||
o4, err := ss.Post().Save(&model.Post{
|
o4, err := ss.Post().Save(&model.Post{
|
||||||
ChannelId: model.NewId(),
|
ChannelId: model.NewId(),
|
||||||
UserId: model.NewId(),
|
UserId: model.NewId(),
|
||||||
@@ -2087,23 +2376,78 @@ func testPostStoreOverwrite(t *testing.T, ss store.Store) {
|
|||||||
})
|
})
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
|
|
||||||
|
r1, err := ss.Post().Get(o1.Id, false)
|
||||||
|
require.Nil(t, err)
|
||||||
|
ro1 := r1.Posts[o1.Id]
|
||||||
|
|
||||||
|
r2, err := ss.Post().Get(o2.Id, false)
|
||||||
|
require.Nil(t, err)
|
||||||
|
ro2 := r2.Posts[o2.Id]
|
||||||
|
|
||||||
|
r3, err := ss.Post().Get(o3.Id, false)
|
||||||
|
require.Nil(t, err)
|
||||||
|
ro3 := r3.Posts[o3.Id]
|
||||||
|
|
||||||
r4, err := ss.Post().Get(o4.Id, false)
|
r4, err := ss.Post().Get(o4.Id, false)
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
ro4 := r4.Posts[o4.Id]
|
ro4 := r4.Posts[o4.Id]
|
||||||
|
|
||||||
o4a := &model.Post{}
|
require.Equal(t, ro1.Message, o1.Message, "Failed to save/get")
|
||||||
*o4a = *ro4
|
require.Equal(t, ro2.Message, o2.Message, "Failed to save/get")
|
||||||
o4a.Filenames = []string{}
|
require.Equal(t, ro3.Message, o3.Message, "Failed to save/get")
|
||||||
o4a.FileIds = []string{model.NewId()}
|
require.Equal(t, ro4.Message, o4.Message, "Failed to save/get")
|
||||||
_, err = ss.Post().Overwrite(o4a)
|
|
||||||
require.Nil(t, err)
|
|
||||||
|
|
||||||
r4, err = ss.Post().Get(o4.Id, false)
|
t.Run("overwrite changing message", func(t *testing.T) {
|
||||||
require.Nil(t, err)
|
o1a := &model.Post{}
|
||||||
|
*o1a = *ro1
|
||||||
|
o1a.Message = ro1.Message + "BBBBBBBBBB"
|
||||||
|
_, err = ss.Post().Overwrite(o1a)
|
||||||
|
require.Nil(t, err)
|
||||||
|
|
||||||
ro4a := r4.Posts[o4.Id]
|
o2a := &model.Post{}
|
||||||
require.Empty(t, ro4a.Filenames, "Failed to clear Filenames")
|
*o2a = *ro2
|
||||||
require.Len(t, ro4a.FileIds, 1, "Failed to set FileIds")
|
o2a.Message = ro2.Message + "DDDDDDD"
|
||||||
|
_, err = ss.Post().Overwrite(o2a)
|
||||||
|
require.Nil(t, err)
|
||||||
|
|
||||||
|
o3a := &model.Post{}
|
||||||
|
*o3a = *ro3
|
||||||
|
o3a.Message = ro3.Message + "WWWWWWW"
|
||||||
|
_, err = ss.Post().Overwrite(o3a)
|
||||||
|
require.Nil(t, err)
|
||||||
|
|
||||||
|
r1, err = ss.Post().Get(o1.Id, false)
|
||||||
|
require.Nil(t, err)
|
||||||
|
ro1a := r1.Posts[o1.Id]
|
||||||
|
|
||||||
|
r2, err = ss.Post().Get(o1.Id, false)
|
||||||
|
require.Nil(t, err)
|
||||||
|
ro2a := r2.Posts[o2.Id]
|
||||||
|
|
||||||
|
r3, err = ss.Post().Get(o3.Id, false)
|
||||||
|
require.Nil(t, err)
|
||||||
|
ro3a := r3.Posts[o3.Id]
|
||||||
|
|
||||||
|
assert.Equal(t, ro1a.Message, o1a.Message, "Failed to overwrite/get")
|
||||||
|
assert.Equal(t, ro2a.Message, o2a.Message, "Failed to overwrite/get")
|
||||||
|
assert.Equal(t, ro3a.Message, o3a.Message, "Failed to overwrite/get")
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("overwrite clearing filenames", func(t *testing.T) {
|
||||||
|
o4a := &model.Post{}
|
||||||
|
*o4a = *ro4
|
||||||
|
o4a.Filenames = []string{}
|
||||||
|
o4a.FileIds = []string{model.NewId()}
|
||||||
|
_, err = ss.Post().Overwrite(o4a)
|
||||||
|
require.Nil(t, err)
|
||||||
|
|
||||||
|
r4, err = ss.Post().Get(o4.Id, false)
|
||||||
|
require.Nil(t, err)
|
||||||
|
|
||||||
|
ro4a := r4.Posts[o4.Id]
|
||||||
|
require.Empty(t, ro4a.Filenames, "Failed to clear Filenames")
|
||||||
|
require.Len(t, ro4a.FileIds, 1, "Failed to set FileIds")
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func testPostStoreGetPostsByIds(t *testing.T, ss store.Store) {
|
func testPostStoreGetPostsByIds(t *testing.T, ss store.Store) {
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ func TestTeamStore(t *testing.T, ss store.Store) {
|
|||||||
t.Run("Update", func(t *testing.T) { testTeamStoreUpdate(t, ss) })
|
t.Run("Update", func(t *testing.T) { testTeamStoreUpdate(t, ss) })
|
||||||
t.Run("Get", func(t *testing.T) { testTeamStoreGet(t, ss) })
|
t.Run("Get", func(t *testing.T) { testTeamStoreGet(t, ss) })
|
||||||
t.Run("GetByName", func(t *testing.T) { testTeamStoreGetByName(t, ss) })
|
t.Run("GetByName", func(t *testing.T) { testTeamStoreGetByName(t, ss) })
|
||||||
|
t.Run("GetByNames", func(t *testing.T) { testTeamStoreGetByNames(t, ss) })
|
||||||
t.Run("SearchAll", func(t *testing.T) { testTeamStoreSearchAll(t, ss) })
|
t.Run("SearchAll", func(t *testing.T) { testTeamStoreSearchAll(t, ss) })
|
||||||
t.Run("SearchOpen", func(t *testing.T) { testTeamStoreSearchOpen(t, ss) })
|
t.Run("SearchOpen", func(t *testing.T) { testTeamStoreSearchOpen(t, ss) })
|
||||||
t.Run("SearchPrivate", func(t *testing.T) { testTeamStoreSearchPrivate(t, ss) })
|
t.Run("SearchPrivate", func(t *testing.T) { testTeamStoreSearchPrivate(t, ss) })
|
||||||
@@ -122,6 +123,59 @@ func testTeamStoreGet(t *testing.T, ss store.Store) {
|
|||||||
require.NotNil(t, err, "Missing id should have failed")
|
require.NotNil(t, err, "Missing id should have failed")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func testTeamStoreGetByNames(t *testing.T, ss store.Store) {
|
||||||
|
o1 := model.Team{}
|
||||||
|
o1.DisplayName = "DisplayName"
|
||||||
|
o1.Name = "z-z-z" + model.NewId() + "b"
|
||||||
|
o1.Email = MakeEmail()
|
||||||
|
o1.Type = model.TEAM_OPEN
|
||||||
|
|
||||||
|
_, err := ss.Team().Save(&o1)
|
||||||
|
require.Nil(t, err)
|
||||||
|
|
||||||
|
o2 := model.Team{}
|
||||||
|
o2.DisplayName = "DisplayName2"
|
||||||
|
o2.Name = "z-z-z" + model.NewId() + "b"
|
||||||
|
o2.Email = MakeEmail()
|
||||||
|
o2.Type = model.TEAM_OPEN
|
||||||
|
|
||||||
|
_, err = ss.Team().Save(&o2)
|
||||||
|
require.Nil(t, err)
|
||||||
|
|
||||||
|
t.Run("Get empty list", func(t *testing.T) {
|
||||||
|
var teams []*model.Team
|
||||||
|
teams, err = ss.Team().GetByNames([]string{})
|
||||||
|
require.Nil(t, err)
|
||||||
|
require.Empty(t, teams)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Get existing teams", func(t *testing.T) {
|
||||||
|
var teams []*model.Team
|
||||||
|
teams, err = ss.Team().GetByNames([]string{o1.Name, o2.Name})
|
||||||
|
require.Nil(t, err)
|
||||||
|
teamsIds := []string{}
|
||||||
|
for _, team := range teams {
|
||||||
|
teamsIds = append(teamsIds, team.Id)
|
||||||
|
}
|
||||||
|
assert.Contains(t, teamsIds, o1.Id, "invalid returned team")
|
||||||
|
assert.Contains(t, teamsIds, o2.Id, "invalid returned team")
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Get existing team and one invalid team name", func(t *testing.T) {
|
||||||
|
_, err = ss.Team().GetByNames([]string{o1.Name, ""})
|
||||||
|
require.NotNil(t, err)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Get existing team and not existing team", func(t *testing.T) {
|
||||||
|
_, err = ss.Team().GetByNames([]string{o1.Name, "not-existing-team-name"})
|
||||||
|
require.NotNil(t, err)
|
||||||
|
})
|
||||||
|
t.Run("Get not existing teams", func(t *testing.T) {
|
||||||
|
_, err = ss.Team().GetByNames([]string{"not-existing-team-name", "not-existing-team-name-2"})
|
||||||
|
require.NotNil(t, err)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func testTeamStoreGetByName(t *testing.T, ss store.Store) {
|
func testTeamStoreGetByName(t *testing.T, ss store.Store) {
|
||||||
o1 := model.Team{}
|
o1 := model.Team{}
|
||||||
o1.DisplayName = "DisplayName"
|
o1.DisplayName = "DisplayName"
|
||||||
@@ -132,12 +186,22 @@ func testTeamStoreGetByName(t *testing.T, ss store.Store) {
|
|||||||
_, err := ss.Team().Save(&o1)
|
_, err := ss.Team().Save(&o1)
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
|
|
||||||
team, err := ss.Team().GetByName(o1.Name)
|
t.Run("Get existing team", func(t *testing.T) {
|
||||||
require.Nil(t, err)
|
var team *model.Team
|
||||||
require.Equal(t, *team, o1, "invalid returned team")
|
team, err = ss.Team().GetByName(o1.Name)
|
||||||
|
require.Nil(t, err)
|
||||||
|
require.Equal(t, *team, o1, "invalid returned team")
|
||||||
|
})
|
||||||
|
|
||||||
_, err = ss.Team().GetByName("")
|
t.Run("Get invalid team name", func(t *testing.T) {
|
||||||
require.NotNil(t, err, "Missing id should have failed")
|
_, err = ss.Team().GetByName("")
|
||||||
|
require.NotNil(t, err, "Missing id should have failed")
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Get not existing team", func(t *testing.T) {
|
||||||
|
_, err = ss.Team().GetByName("not-existing-team-name")
|
||||||
|
require.NotNil(t, err, "Missing id should have failed")
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func testTeamStoreSearchAll(t *testing.T, ss store.Store) {
|
func testTeamStoreSearchAll(t *testing.T, ss store.Store) {
|
||||||
|
|||||||
@@ -4412,6 +4412,22 @@ func (s *TimerLayerPostStore) Save(post *model.Post) (*model.Post, *model.AppErr
|
|||||||
return resultVar0, resultVar1
|
return resultVar0, resultVar1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *TimerLayerPostStore) SaveMultiple(posts []*model.Post) ([]*model.Post, *model.AppError) {
|
||||||
|
start := timemodule.Now()
|
||||||
|
|
||||||
|
resultVar0, resultVar1 := s.PostStore.SaveMultiple(posts)
|
||||||
|
|
||||||
|
elapsed := float64(timemodule.Since(start)) / float64(timemodule.Second)
|
||||||
|
if s.Root.Metrics != nil {
|
||||||
|
success := "false"
|
||||||
|
if resultVar1 == nil {
|
||||||
|
success = "true"
|
||||||
|
}
|
||||||
|
s.Root.Metrics.ObserveStoreMethodDuration("PostStore.SaveMultiple", success, elapsed)
|
||||||
|
}
|
||||||
|
return resultVar0, resultVar1
|
||||||
|
}
|
||||||
|
|
||||||
func (s *TimerLayerPostStore) Search(teamId string, userId string, params *model.SearchParams) (*model.PostList, *model.AppError) {
|
func (s *TimerLayerPostStore) Search(teamId string, userId string, params *model.SearchParams) (*model.PostList, *model.AppError) {
|
||||||
start := timemodule.Now()
|
start := timemodule.Now()
|
||||||
|
|
||||||
|
|||||||
Ссылка в новой задаче
Block a user