[MM-59519] preserve DM/GM unread/read state over export and import (#27707)
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
c2c37cea20
Коммит
4b3de1861f
@@ -815,7 +815,7 @@ func (a *App) exportAllDirectChannels(ctx request.CTX, job *model.Job, writer io
|
||||
afterId = channel.Id
|
||||
|
||||
// Skip if there are no active members in the channel
|
||||
if len(*channel.Members) == 0 {
|
||||
if len(channel.Members) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -829,7 +829,12 @@ func (a *App) exportAllDirectChannels(ctx request.CTX, job *model.Job, writer io
|
||||
return err
|
||||
}
|
||||
|
||||
channelLine := ImportLineFromDirectChannel(channel, favoritedBy)
|
||||
shownBy, err := a.buildShownByList(channel)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
channelLine := ImportLineFromDirectChannel(channel, favoritedBy, shownBy)
|
||||
if err := a.exportWriteLine(writer, channelLine); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -862,6 +867,55 @@ func (a *App) buildFavoritedByList(channelID string) ([]string, *model.AppError)
|
||||
return userIDs, nil
|
||||
}
|
||||
|
||||
func (a *App) buildShownByList(channel *model.DirectChannelForExport) ([]string, *model.AppError) {
|
||||
shownBy := make([]string, 0)
|
||||
switch channel.Type {
|
||||
case model.ChannelTypeGroup:
|
||||
for _, member := range channel.Members {
|
||||
prefs, err := a.Srv().Store().Preference().GetCategory(member.UserId, model.PreferenceCategoryGroupChannelShow)
|
||||
if err != nil {
|
||||
return nil, model.NewAppError("buildShownByList", "app.preference.get_category.app_error", nil, "", http.StatusInternalServerError).Wrap(err)
|
||||
}
|
||||
|
||||
for i := range prefs {
|
||||
if prefs[i].Name == channel.Id && prefs[i].Value == "true" {
|
||||
user, err := a.Srv().Store().User().Get(context.Background(), member.UserId)
|
||||
if err != nil {
|
||||
return nil, model.NewAppError("buildShownByList", "app.user.get.app_error", nil, "", http.StatusInternalServerError).Wrap(err)
|
||||
}
|
||||
|
||||
shownBy = append(shownBy, user.Username)
|
||||
}
|
||||
}
|
||||
}
|
||||
case model.ChannelTypeDirect:
|
||||
for i, member := range channel.Members {
|
||||
otherMember := member // in case it's a channel with self
|
||||
if len(channel.Members) == 2 {
|
||||
// since the are only two members, the other member is should be the remainder of i+1/2
|
||||
otherMember = channel.Members[(i+1)%2]
|
||||
}
|
||||
prefs, err := a.Srv().Store().Preference().GetCategoryAndName(model.PreferenceCategoryDirectChannelShow, otherMember.UserId)
|
||||
if err != nil {
|
||||
return nil, model.NewAppError("buildShownByList", "app.preference.get_category.app_error", nil, "", http.StatusInternalServerError).Wrap(err)
|
||||
}
|
||||
|
||||
for _, pref := range prefs {
|
||||
if pref.Value == "true" && pref.UserId == member.UserId {
|
||||
user, err := a.Srv().Store().User().Get(context.Background(), member.UserId)
|
||||
if err != nil {
|
||||
return nil, model.NewAppError("buildShownByList", "app.user.get.app_error", nil, "", http.StatusInternalServerError).Wrap(err)
|
||||
}
|
||||
|
||||
shownBy = append(shownBy, user.Username)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return shownBy, nil
|
||||
}
|
||||
|
||||
func (a *App) exportAllDirectPosts(ctx request.CTX, job *model.Job, writer io.Writer, withAttachments, includeArchivedChannels bool) ([]imports.AttachmentImportData, *model.AppError) {
|
||||
var attachments []imports.AttachmentImportData
|
||||
afterId := strings.Repeat("0", 26)
|
||||
|
||||
@@ -40,17 +40,17 @@ func ImportLineFromChannel(channel *model.ChannelForExport) *imports.LineImportD
|
||||
}
|
||||
}
|
||||
|
||||
func ImportLineFromDirectChannel(channel *model.DirectChannelForExport, favoritedBy []string) *imports.LineImportData {
|
||||
channelMembers := *channel.Members
|
||||
func ImportLineFromDirectChannel(channel *model.DirectChannelForExport, favoritedBy, shownBy []string) *imports.LineImportData {
|
||||
channelMembers := channel.Members
|
||||
if len(channelMembers) == 1 {
|
||||
channelMembers = []string{channelMembers[0], channelMembers[0]}
|
||||
channelMembers = []*model.ChannelMemberForExport{channelMembers[0], channelMembers[0]}
|
||||
}
|
||||
|
||||
line := &imports.LineImportData{
|
||||
Type: "direct_channel",
|
||||
DirectChannel: &imports.DirectChannelImportData{
|
||||
Header: &channel.Header,
|
||||
Members: &channelMembers,
|
||||
Header: &channel.Header,
|
||||
Participants: importDirectChannelMembersFromChannelMembers(channelMembers),
|
||||
},
|
||||
}
|
||||
|
||||
@@ -58,9 +58,82 @@ func ImportLineFromDirectChannel(channel *model.DirectChannelForExport, favorite
|
||||
line.DirectChannel.FavoritedBy = &favoritedBy
|
||||
}
|
||||
|
||||
if len(shownBy) != 0 {
|
||||
line.DirectChannel.ShownBy = &shownBy
|
||||
}
|
||||
|
||||
return line
|
||||
}
|
||||
|
||||
func importDirectChannelMembersFromChannelMembers(members []*model.ChannelMemberForExport) []*imports.DirectChannelMemberImportData {
|
||||
importedMembers := make([]*imports.DirectChannelMemberImportData, len(members))
|
||||
for i, member := range members {
|
||||
props := member.NotifyProps
|
||||
notifyProps := imports.UserChannelNotifyPropsImportData{}
|
||||
|
||||
desktop, exist := props[model.DesktopNotifyProp]
|
||||
if exist {
|
||||
notifyProps.Desktop = &desktop
|
||||
}
|
||||
mobile, exist := props[model.PushNotifyProp]
|
||||
if exist {
|
||||
notifyProps.Mobile = &mobile
|
||||
}
|
||||
email, exist := props[model.EmailNotifyProp]
|
||||
if exist {
|
||||
notifyProps.Email = &email
|
||||
}
|
||||
ignoreMentions, exist := props[model.IgnoreChannelMentionsNotifyProp]
|
||||
if exist {
|
||||
notifyProps.IgnoreChannelMentions = &ignoreMentions
|
||||
}
|
||||
channelAutoFallow, exist := props[model.ChannelAutoFollowThreads]
|
||||
if exist {
|
||||
notifyProps.ChannelAutoFollowThreads = &channelAutoFallow
|
||||
}
|
||||
markUnread, exist := props[model.MarkUnreadNotifyProp]
|
||||
if exist {
|
||||
notifyProps.MarkUnread = &markUnread
|
||||
}
|
||||
|
||||
dcm := &imports.DirectChannelMemberImportData{
|
||||
Username: &member.Username,
|
||||
NotifyProps: ¬ifyProps,
|
||||
}
|
||||
|
||||
if member.SchemeUser {
|
||||
dcm.SchemeUser = &member.SchemeUser
|
||||
}
|
||||
if member.SchemeAdmin {
|
||||
dcm.SchemeAdmin = &member.SchemeAdmin
|
||||
}
|
||||
if member.SchemeGuest {
|
||||
dcm.SchemeGuest = &member.SchemeGuest
|
||||
}
|
||||
if member.LastViewedAt != 0 {
|
||||
dcm.LastViewedAt = &member.LastViewedAt
|
||||
}
|
||||
if member.MentionCount != 0 {
|
||||
dcm.MentionCount = &member.MentionCount
|
||||
}
|
||||
if member.MentionCountRoot != 0 {
|
||||
dcm.MentionCountRoot = &member.MentionCountRoot
|
||||
}
|
||||
if member.MsgCount != 0 {
|
||||
dcm.MsgCount = &member.MsgCount
|
||||
}
|
||||
if member.MsgCountRoot != 0 {
|
||||
dcm.MsgCountRoot = &member.MsgCountRoot
|
||||
}
|
||||
if member.UrgentMentionCount != 0 {
|
||||
dcm.UrgentMentionCount = &member.UrgentMentionCount
|
||||
}
|
||||
|
||||
importedMembers[i] = dcm
|
||||
}
|
||||
return importedMembers
|
||||
}
|
||||
|
||||
func ImportLineFromUser(user *model.User, exportedPrefs map[string]*string) *imports.LineImportData {
|
||||
// Bulk Importer doesn't accept "empty string" for AuthService.
|
||||
var authService *string
|
||||
|
||||
@@ -269,8 +269,9 @@ func TestExportDMChannel(t *testing.T) {
|
||||
// Ensure the Members of the imported DM channel is the same was from the exported
|
||||
channels, nErr = th2.App.Srv().Store().Channel().GetAllDirectChannelsForExportAfter(1000, "00000000", false)
|
||||
require.NoError(t, nErr)
|
||||
require.Equal(t, 1, len(channels))
|
||||
assert.ElementsMatch(t, []string{th1.BasicUser.Username, th1.BasicUser2.Username}, *channels[0].Members)
|
||||
require.Len(t, channels, 1)
|
||||
require.Len(t, channels[0].Members, 2)
|
||||
assert.ElementsMatch(t, []string{th1.BasicUser.Username, th1.BasicUser2.Username}, []string{channels[0].Members[0].Username, channels[0].Members[1].Username})
|
||||
|
||||
// Ensure the favorited channel was retained
|
||||
fav, nErr := th2.App.Srv().Store().Preference().Get(th2.BasicUser2.Id, model.PreferenceCategoryFavoriteChannel, channels[0].Id)
|
||||
@@ -340,8 +341,8 @@ func TestExportDMChannelToSelf(t *testing.T) {
|
||||
channels, nErr = th2.App.Srv().Store().Channel().GetAllDirectChannelsForExportAfter(1000, "00000000", false)
|
||||
require.NoError(t, nErr)
|
||||
assert.Equal(t, 1, len(channels))
|
||||
assert.Equal(t, 1, len((*channels[0].Members)))
|
||||
assert.Equal(t, th1.BasicUser.Username, (*channels[0].Members)[0])
|
||||
assert.Equal(t, 1, len((channels[0].Members)))
|
||||
assert.Equal(t, th1.BasicUser.Username, channels[0].Members[0].Username)
|
||||
}
|
||||
|
||||
func TestExportGMChannel(t *testing.T) {
|
||||
@@ -416,8 +417,8 @@ func TestExportGMandDMChannels(t *testing.T) {
|
||||
// Adding some determinism so its possible to assert on slice index
|
||||
sort.Slice(channels, func(i, j int) bool { return channels[i].Type > channels[j].Type })
|
||||
assert.Equal(t, 2, len(channels))
|
||||
assert.ElementsMatch(t, []string{th1.BasicUser.Username, user1.Username, user2.Username}, *channels[0].Members)
|
||||
assert.ElementsMatch(t, []string{th1.BasicUser.Username, th1.BasicUser2.Username}, *channels[1].Members)
|
||||
assert.ElementsMatch(t, []string{th1.BasicUser.Username, user1.Username, user2.Username}, []string{channels[0].Members[0].Username, channels[0].Members[1].Username, channels[0].Members[2].Username})
|
||||
assert.ElementsMatch(t, []string{th1.BasicUser.Username, th1.BasicUser2.Username}, []string{channels[1].Members[0].Username, channels[1].Members[1].Username})
|
||||
}
|
||||
|
||||
func TestExportDMandGMPost(t *testing.T) {
|
||||
|
||||
@@ -1758,40 +1758,187 @@ func (a *App) importDirectChannel(rctx request.CTX, data *imports.DirectChannelI
|
||||
return nil
|
||||
}
|
||||
|
||||
var members []string
|
||||
if data.Participants != nil {
|
||||
members = make([]string, len(data.Participants))
|
||||
for i, member := range data.Participants {
|
||||
members[i] = *member.Username
|
||||
}
|
||||
} else if data.Members != nil {
|
||||
members = make([]string, len(*data.Members))
|
||||
copy(members, *data.Members)
|
||||
} else {
|
||||
return model.NewAppError("BulkImport", "app.import.import_direct_channel.no_members.error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
var userIDs []string
|
||||
userMap, err := a.getUsersByUsernames(*data.Members)
|
||||
userMap, err := a.getUsersByUsernames(members)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, user := range *data.Members {
|
||||
for _, user := range members {
|
||||
userIDs = append(userIDs, userMap[strings.ToLower(user)].Id)
|
||||
}
|
||||
|
||||
var channel *model.Channel
|
||||
|
||||
if len(userIDs) == 2 {
|
||||
ch, err := a.createDirectChannel(rctx, userIDs[0], userIDs[1])
|
||||
if err != nil && err.Id != store.ChannelExistsError {
|
||||
return model.NewAppError("BulkImport", "app.import.import_direct_channel.create_direct_channel.error", nil, "", http.StatusBadRequest).Wrap(err)
|
||||
ch, err2 := a.createDirectChannel(rctx, userIDs[0], userIDs[1])
|
||||
if err2 != nil && err2.Id != store.ChannelExistsError {
|
||||
return model.NewAppError("BulkImport", "app.import.import_direct_channel.create_direct_channel.error", nil, "", http.StatusBadRequest).Wrap(err2)
|
||||
}
|
||||
channel = ch
|
||||
} else {
|
||||
ch, err := a.createGroupChannel(rctx, userIDs)
|
||||
if err != nil && err.Id != store.ChannelExistsError {
|
||||
return model.NewAppError("BulkImport", "app.import.import_direct_channel.create_group_channel.error", nil, "", http.StatusBadRequest).Wrap(err)
|
||||
ch, err2 := a.createGroupChannel(rctx, userIDs)
|
||||
if err2 != nil && err2.Id != store.ChannelExistsError {
|
||||
return model.NewAppError("BulkImport", "app.import.import_direct_channel.create_group_channel.error", nil, "", http.StatusBadRequest).Wrap(err2)
|
||||
}
|
||||
channel = ch
|
||||
}
|
||||
|
||||
totalMembers, err := a.GetChannelMemberCount(rctx, channel.Id)
|
||||
if err != nil {
|
||||
return model.NewAppError("BulkImport", "app.import.import_direct_channel.get_channel_members.error", nil, "", http.StatusBadRequest).Wrap(err)
|
||||
}
|
||||
|
||||
var ems = make([]model.ChannelMember, 0, totalMembers)
|
||||
var page int
|
||||
|
||||
for int64(len(ems)) < totalMembers {
|
||||
res, err := a.GetChannelMembersPage(rctx, channel.Id, page, 100)
|
||||
if err != nil {
|
||||
return model.NewAppError("BulkImport", "app.import.import_direct_channel.get_channel_members.error", nil, "", http.StatusBadRequest).Wrap(err)
|
||||
}
|
||||
ems = append(ems, res...)
|
||||
page++
|
||||
}
|
||||
|
||||
existingMembers := make(map[string]model.ChannelMember)
|
||||
for _, member := range ems {
|
||||
existingMembers[member.UserId] = member
|
||||
}
|
||||
|
||||
newChannelMembers := make([]*model.ChannelMember, 0)
|
||||
for _, member := range data.Participants {
|
||||
m := &model.ChannelMember{
|
||||
NotifyProps: model.GetDefaultChannelNotifyProps(),
|
||||
}
|
||||
if member.LastViewedAt != nil {
|
||||
m.LastViewedAt = *member.LastViewedAt
|
||||
}
|
||||
if member.MsgCount != nil {
|
||||
m.MsgCount = *member.MsgCount
|
||||
}
|
||||
if member.MentionCount != nil {
|
||||
m.MentionCount = *member.MentionCount
|
||||
}
|
||||
if member.MentionCountRoot != nil {
|
||||
m.MentionCountRoot = *member.MentionCountRoot
|
||||
}
|
||||
if member.UrgentMentionCount != nil {
|
||||
m.UrgentMentionCount = *member.UrgentMentionCount
|
||||
}
|
||||
if member.MsgCountRoot != nil {
|
||||
m.MsgCountRoot = *member.MsgCountRoot
|
||||
}
|
||||
if member.SchemeUser != nil {
|
||||
m.SchemeUser = *member.SchemeUser
|
||||
}
|
||||
if member.SchemeAdmin != nil {
|
||||
m.SchemeAdmin = *member.SchemeAdmin
|
||||
}
|
||||
if member.SchemeGuest != nil {
|
||||
m.SchemeGuest = *member.SchemeGuest
|
||||
}
|
||||
|
||||
if member.NotifyProps != nil {
|
||||
if member.NotifyProps.Desktop != nil {
|
||||
if value, ok := m.NotifyProps[model.DesktopNotifyProp]; !ok || value != *member.NotifyProps.Desktop {
|
||||
m.NotifyProps[model.DesktopNotifyProp] = *member.NotifyProps.Desktop
|
||||
}
|
||||
}
|
||||
|
||||
if member.NotifyProps.MarkUnread != nil {
|
||||
if value, ok := m.NotifyProps[model.DesktopSoundNotifyProp]; !ok || value != *member.NotifyProps.MarkUnread {
|
||||
m.NotifyProps[model.MarkUnreadNotifyProp] = *member.NotifyProps.MarkUnread
|
||||
}
|
||||
}
|
||||
|
||||
if member.NotifyProps.Mobile != nil {
|
||||
if value, ok := m.NotifyProps[model.PushNotifyProp]; !ok || value != *member.NotifyProps.Mobile {
|
||||
m.NotifyProps[model.PushNotifyProp] = *member.NotifyProps.Mobile
|
||||
}
|
||||
}
|
||||
|
||||
if member.NotifyProps.Email != nil {
|
||||
if value, ok := m.NotifyProps[model.EmailNotifyProp]; !ok || value != *member.NotifyProps.Email {
|
||||
m.NotifyProps[model.EmailNotifyProp] = *member.NotifyProps.Email
|
||||
}
|
||||
}
|
||||
|
||||
if member.NotifyProps.IgnoreChannelMentions != nil {
|
||||
if value, ok := m.NotifyProps[model.IgnoreChannelMentionsNotifyProp]; !ok || value != *member.NotifyProps.IgnoreChannelMentions {
|
||||
m.NotifyProps[model.IgnoreChannelMentionsNotifyProp] = *member.NotifyProps.IgnoreChannelMentions
|
||||
}
|
||||
}
|
||||
|
||||
if member.NotifyProps.ChannelAutoFollowThreads != nil {
|
||||
if value, ok := m.NotifyProps[model.ChannelAutoFollowThreads]; !ok || value != *member.NotifyProps.ChannelAutoFollowThreads {
|
||||
m.NotifyProps[model.ChannelAutoFollowThreads] = *member.NotifyProps.ChannelAutoFollowThreads
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
u := userMap[strings.ToLower(*member.Username)]
|
||||
if existing, ok := existingMembers[u.Id]; ok {
|
||||
// Decide which membership is newer. We have LastViewedAt in the import data, which should
|
||||
// give us a good idea of which membership is newer.
|
||||
if existing.LastViewedAt > m.LastViewedAt {
|
||||
continue
|
||||
}
|
||||
}
|
||||
m.UserId = u.Id
|
||||
m.ChannelId = channel.Id
|
||||
newChannelMembers = append(newChannelMembers, m)
|
||||
}
|
||||
|
||||
// the channel memberships are already created in the channel creation
|
||||
// we always going to update the channel memberships
|
||||
if len(newChannelMembers) > 0 {
|
||||
_, nErr := a.Srv().Store().Channel().UpdateMultipleMembers(newChannelMembers)
|
||||
if nErr != nil {
|
||||
return model.NewAppError("BulkImport", "app.import.import_direct_channel.create_group_channel.error", nil, "", http.StatusBadRequest).Wrap(nErr)
|
||||
}
|
||||
}
|
||||
|
||||
var preferences model.Preferences
|
||||
|
||||
for _, userID := range userIDs {
|
||||
preferences = append(preferences, model.Preference{
|
||||
UserId: userID,
|
||||
Category: model.PreferenceCategoryDirectChannelShow,
|
||||
Name: channel.Id,
|
||||
Value: "true",
|
||||
})
|
||||
if data.ShownBy != nil {
|
||||
for _, username := range *data.ShownBy {
|
||||
switch channel.Type {
|
||||
case model.ChannelTypeDirect:
|
||||
otherUserId := userMap[strings.ToLower(username)].Id
|
||||
for uname, user := range userMap {
|
||||
if uname != username {
|
||||
otherUserId = user.Id
|
||||
break
|
||||
}
|
||||
}
|
||||
preferences = append(preferences, model.Preference{
|
||||
UserId: userMap[strings.ToLower(username)].Id,
|
||||
Category: model.PreferenceCategoryDirectChannelShow,
|
||||
Name: otherUserId,
|
||||
Value: "true",
|
||||
})
|
||||
case model.ChannelTypeGroup:
|
||||
preferences = append(preferences, model.Preference{
|
||||
UserId: userMap[strings.ToLower(username)].Id,
|
||||
Category: model.PreferenceCategoryGroupChannelShow,
|
||||
Name: channel.Id,
|
||||
Value: "true",
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if data.FavoritedBy != nil {
|
||||
@@ -1805,14 +1952,16 @@ func (a *App) importDirectChannel(rctx request.CTX, data *imports.DirectChannelI
|
||||
}
|
||||
}
|
||||
|
||||
if err := a.Srv().Store().Preference().Save(preferences); err != nil {
|
||||
var appErr *model.AppError
|
||||
switch {
|
||||
case errors.As(err, &appErr):
|
||||
appErr.StatusCode = http.StatusBadRequest
|
||||
return appErr
|
||||
default:
|
||||
return model.NewAppError("importDirectChannel", "app.preference.save.updating.app_error", nil, "", http.StatusBadRequest).Wrap(err)
|
||||
if len(preferences) > 0 {
|
||||
if err := a.Srv().Store().Preference().Save(preferences); err != nil {
|
||||
var appErr *model.AppError
|
||||
switch {
|
||||
case errors.As(err, &appErr):
|
||||
appErr.StatusCode = http.StatusBadRequest
|
||||
return appErr
|
||||
default:
|
||||
return model.NewAppError("importDirectChannel", "app.preference.save.updating.app_error", nil, "", http.StatusBadRequest).Wrap(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3161,6 +3161,7 @@ func TestImportImportPost(t *testing.T) {
|
||||
func TestImportImportDirectChannel(t *testing.T) {
|
||||
th := Setup(t).InitBasic()
|
||||
defer th.TearDown()
|
||||
user3 := th.CreateUser()
|
||||
|
||||
// Check how many channels are in the database.
|
||||
directChannelCount, err := th.App.Srv().Store().Channel().AnalyticsTypeCount("", model.ChannelTypeDirect)
|
||||
@@ -3169,161 +3170,363 @@ func TestImportImportDirectChannel(t *testing.T) {
|
||||
groupChannelCount, err := th.App.Srv().Store().Channel().AnalyticsTypeCount("", model.ChannelTypeGroup)
|
||||
require.NoError(t, err, "Failed to get group channel count.")
|
||||
|
||||
// Do an invalid channel in dry-run mode.
|
||||
data := imports.DirectChannelImportData{
|
||||
Members: &[]string{
|
||||
model.NewId(),
|
||||
},
|
||||
Header: ptrStr("Channel Header"),
|
||||
// We need to generate the dataset twice to test the same data with different formats.
|
||||
generateDataset := func(data imports.DirectChannelImportData) map[string]imports.DirectChannelImportData {
|
||||
members := make([]string, len(data.Participants))
|
||||
for i, member := range data.Participants {
|
||||
members[i] = *member.Username
|
||||
}
|
||||
|
||||
return map[string]imports.DirectChannelImportData{
|
||||
"Participants": data,
|
||||
"Members": {
|
||||
Members: &members,
|
||||
},
|
||||
}
|
||||
}
|
||||
err = th.App.importDirectChannel(th.Context, &data, true)
|
||||
require.Error(t, err)
|
||||
|
||||
// Check that no more channels are in the DB.
|
||||
AssertChannelCount(t, th.App, model.ChannelTypeDirect, directChannelCount)
|
||||
AssertChannelCount(t, th.App, model.ChannelTypeGroup, groupChannelCount)
|
||||
t.Run("Invalid channel in dry-run mode", func(t *testing.T) {
|
||||
dataset := generateDataset(imports.DirectChannelImportData{
|
||||
Participants: []*imports.DirectChannelMemberImportData{
|
||||
{
|
||||
Username: model.NewString(model.NewId()),
|
||||
},
|
||||
},
|
||||
Header: ptrStr("Channel Header"),
|
||||
})
|
||||
for name, data := range dataset {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
err = th.App.importDirectChannel(th.Context, &data, true)
|
||||
require.Error(t, err)
|
||||
|
||||
// Do a valid DIRECT channel with a nonexistent member in dry-run mode.
|
||||
data.Members = &[]string{
|
||||
model.NewId(),
|
||||
model.NewId(),
|
||||
}
|
||||
appErr := th.App.importDirectChannel(th.Context, &data, true)
|
||||
require.Nil(t, appErr)
|
||||
// Check that no more channels are in the DB.
|
||||
AssertChannelCount(t, th.App, model.ChannelTypeDirect, directChannelCount)
|
||||
AssertChannelCount(t, th.App, model.ChannelTypeGroup, groupChannelCount)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
// Check that no more channels are in the DB.
|
||||
AssertChannelCount(t, th.App, model.ChannelTypeDirect, directChannelCount)
|
||||
AssertChannelCount(t, th.App, model.ChannelTypeGroup, groupChannelCount)
|
||||
t.Run("Valid DIRECT channel with a nonexistent member in dry-run mode", func(t *testing.T) {
|
||||
dataset := generateDataset(imports.DirectChannelImportData{
|
||||
Participants: []*imports.DirectChannelMemberImportData{
|
||||
{
|
||||
Username: model.NewString(model.NewId()),
|
||||
},
|
||||
{
|
||||
Username: model.NewString(model.NewId()),
|
||||
},
|
||||
},
|
||||
})
|
||||
for name, data := range dataset {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
appErr := th.App.importDirectChannel(th.Context, &data, true)
|
||||
require.Nil(t, appErr)
|
||||
|
||||
// Do a valid GROUP channel with a nonexistent member in dry-run mode.
|
||||
data.Members = &[]string{
|
||||
model.NewId(),
|
||||
model.NewId(),
|
||||
model.NewId(),
|
||||
}
|
||||
appErr = th.App.importDirectChannel(th.Context, &data, true)
|
||||
require.Nil(t, appErr)
|
||||
// Check that no more channels are in the DB.
|
||||
AssertChannelCount(t, th.App, model.ChannelTypeDirect, directChannelCount)
|
||||
AssertChannelCount(t, th.App, model.ChannelTypeGroup, groupChannelCount)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
// Check that no more channels are in the DB.
|
||||
AssertChannelCount(t, th.App, model.ChannelTypeDirect, directChannelCount)
|
||||
AssertChannelCount(t, th.App, model.ChannelTypeGroup, groupChannelCount)
|
||||
t.Run("Valid GROUP channel with a nonexistent member in dry-run mode", func(t *testing.T) {
|
||||
dataset := generateDataset(imports.DirectChannelImportData{
|
||||
Participants: []*imports.DirectChannelMemberImportData{
|
||||
{
|
||||
Username: model.NewString(model.NewId()),
|
||||
},
|
||||
{
|
||||
Username: model.NewString(model.NewId()),
|
||||
},
|
||||
{
|
||||
Username: model.NewString(model.NewId()),
|
||||
},
|
||||
},
|
||||
})
|
||||
for name, data := range dataset {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
appErr := th.App.importDirectChannel(th.Context, &data, true)
|
||||
require.Nil(t, appErr)
|
||||
|
||||
// Do an invalid channel in apply mode.
|
||||
data.Members = &[]string{
|
||||
model.NewId(),
|
||||
}
|
||||
err = th.App.importDirectChannel(th.Context, &data, false)
|
||||
require.Error(t, err)
|
||||
// Check that no more channels are in the DB.
|
||||
AssertChannelCount(t, th.App, model.ChannelTypeDirect, directChannelCount)
|
||||
AssertChannelCount(t, th.App, model.ChannelTypeGroup, groupChannelCount)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
// Check that no more channels are in the DB.
|
||||
AssertChannelCount(t, th.App, model.ChannelTypeDirect, directChannelCount)
|
||||
AssertChannelCount(t, th.App, model.ChannelTypeGroup, groupChannelCount)
|
||||
t.Run("Invalid channel in apply mode", func(t *testing.T) {
|
||||
dataset := generateDataset(imports.DirectChannelImportData{
|
||||
Participants: []*imports.DirectChannelMemberImportData{
|
||||
{
|
||||
Username: model.NewString(model.NewId()),
|
||||
},
|
||||
},
|
||||
})
|
||||
for name, data := range dataset {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
err = th.App.importDirectChannel(th.Context, &data, false)
|
||||
require.Error(t, err)
|
||||
|
||||
// Do a valid DIRECT channel.
|
||||
data.Members = &[]string{
|
||||
th.BasicUser.Username,
|
||||
th.BasicUser2.Username,
|
||||
}
|
||||
appErr = th.App.importDirectChannel(th.Context, &data, false)
|
||||
require.Nil(t, appErr)
|
||||
// Check that no more channels are in the DB.
|
||||
AssertChannelCount(t, th.App, model.ChannelTypeDirect, directChannelCount)
|
||||
AssertChannelCount(t, th.App, model.ChannelTypeGroup, groupChannelCount)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
// Check that one more DIRECT channel is in the DB.
|
||||
AssertChannelCount(t, th.App, model.ChannelTypeDirect, directChannelCount+1)
|
||||
AssertChannelCount(t, th.App, model.ChannelTypeGroup, groupChannelCount)
|
||||
t.Run("Valid DIRECT channel ", func(t *testing.T) {
|
||||
dataset := generateDataset(imports.DirectChannelImportData{
|
||||
Participants: []*imports.DirectChannelMemberImportData{
|
||||
{
|
||||
Username: model.NewString(th.BasicUser.Username),
|
||||
},
|
||||
{
|
||||
Username: model.NewString(th.BasicUser2.Username),
|
||||
},
|
||||
},
|
||||
})
|
||||
for name, data := range dataset {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
appErr := th.App.importDirectChannel(th.Context, &data, false)
|
||||
require.Nil(t, appErr)
|
||||
|
||||
// Do the same DIRECT channel again.
|
||||
appErr = th.App.importDirectChannel(th.Context, &data, false)
|
||||
require.Nil(t, appErr)
|
||||
// Check that one more DIRECT channel is in the DB.
|
||||
AssertChannelCount(t, th.App, model.ChannelTypeDirect, directChannelCount+1)
|
||||
AssertChannelCount(t, th.App, model.ChannelTypeGroup, groupChannelCount)
|
||||
|
||||
// Check that no more channels are in the DB.
|
||||
AssertChannelCount(t, th.App, model.ChannelTypeDirect, directChannelCount+1)
|
||||
AssertChannelCount(t, th.App, model.ChannelTypeGroup, groupChannelCount)
|
||||
// Do the same DIRECT channel again.
|
||||
appErr = th.App.importDirectChannel(th.Context, &data, false)
|
||||
require.Nil(t, appErr)
|
||||
|
||||
// Update the channel's HEADER
|
||||
data.Header = ptrStr("New Channel Header 2")
|
||||
appErr = th.App.importDirectChannel(th.Context, &data, false)
|
||||
require.Nil(t, appErr)
|
||||
// Check that no more channels are in the DB.
|
||||
AssertChannelCount(t, th.App, model.ChannelTypeDirect, directChannelCount+1)
|
||||
AssertChannelCount(t, th.App, model.ChannelTypeGroup, groupChannelCount)
|
||||
|
||||
// Check that no more channels are in the DB.
|
||||
AssertChannelCount(t, th.App, model.ChannelTypeDirect, directChannelCount+1)
|
||||
AssertChannelCount(t, th.App, model.ChannelTypeGroup, groupChannelCount)
|
||||
// Update the channel's HEADER
|
||||
data.Header = ptrStr("New Channel Header 2")
|
||||
appErr = th.App.importDirectChannel(th.Context, &data, false)
|
||||
require.Nil(t, appErr)
|
||||
|
||||
// Get the channel to check that the header was updated.
|
||||
channel, appErr := th.App.GetOrCreateDirectChannel(th.Context, th.BasicUser.Id, th.BasicUser2.Id)
|
||||
require.Nil(t, appErr)
|
||||
require.Equal(t, channel.Header, *data.Header)
|
||||
// Check that no more channels are in the DB.
|
||||
AssertChannelCount(t, th.App, model.ChannelTypeDirect, directChannelCount+1)
|
||||
AssertChannelCount(t, th.App, model.ChannelTypeGroup, groupChannelCount)
|
||||
|
||||
// Do a GROUP channel with an extra invalid member.
|
||||
user3 := th.CreateUser()
|
||||
data.Members = &[]string{
|
||||
th.BasicUser.Username,
|
||||
th.BasicUser2.Username,
|
||||
user3.Username,
|
||||
model.NewId(),
|
||||
}
|
||||
appErr = th.App.importDirectChannel(th.Context, &data, false)
|
||||
require.NotNil(t, appErr)
|
||||
// Get the channel to check that the header was updated.
|
||||
channel, appErr := th.App.GetOrCreateDirectChannel(th.Context, th.BasicUser.Id, th.BasicUser2.Id)
|
||||
require.Nil(t, appErr)
|
||||
require.Equal(t, channel.Header, *data.Header)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
// Check that no more channels are in the DB.
|
||||
AssertChannelCount(t, th.App, model.ChannelTypeDirect, directChannelCount+1)
|
||||
AssertChannelCount(t, th.App, model.ChannelTypeGroup, groupChannelCount)
|
||||
t.Run("GROUP channel with an extra invalid member", func(t *testing.T) {
|
||||
dataset := generateDataset(imports.DirectChannelImportData{
|
||||
Participants: []*imports.DirectChannelMemberImportData{
|
||||
{
|
||||
Username: model.NewString(th.BasicUser.Username),
|
||||
},
|
||||
{
|
||||
Username: model.NewString(th.BasicUser2.Username),
|
||||
},
|
||||
{
|
||||
Username: model.NewString(user3.Username),
|
||||
},
|
||||
{
|
||||
Username: model.NewString(model.NewId()),
|
||||
},
|
||||
},
|
||||
})
|
||||
for name, data := range dataset {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
appErr := th.App.importDirectChannel(th.Context, &data, false)
|
||||
require.NotNil(t, appErr)
|
||||
|
||||
// Do a valid GROUP channel.
|
||||
data.Members = &[]string{
|
||||
th.BasicUser.Username,
|
||||
th.BasicUser2.Username,
|
||||
user3.Username,
|
||||
}
|
||||
appErr = th.App.importDirectChannel(th.Context, &data, false)
|
||||
require.Nil(t, appErr)
|
||||
// Check that no more channels are in the DB.
|
||||
AssertChannelCount(t, th.App, model.ChannelTypeDirect, directChannelCount+1)
|
||||
AssertChannelCount(t, th.App, model.ChannelTypeGroup, groupChannelCount)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
// Check that one more GROUP channel is in the DB.
|
||||
AssertChannelCount(t, th.App, model.ChannelTypeDirect, directChannelCount+1)
|
||||
AssertChannelCount(t, th.App, model.ChannelTypeGroup, groupChannelCount+1)
|
||||
t.Run("Valid GROUP channel", func(t *testing.T) {
|
||||
dataset := generateDataset(imports.DirectChannelImportData{
|
||||
Participants: []*imports.DirectChannelMemberImportData{
|
||||
{
|
||||
Username: model.NewString(th.BasicUser.Username),
|
||||
},
|
||||
{
|
||||
Username: model.NewString(th.BasicUser2.Username),
|
||||
},
|
||||
{
|
||||
Username: model.NewString(user3.Username),
|
||||
},
|
||||
},
|
||||
})
|
||||
for name, data := range dataset {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
appErr := th.App.importDirectChannel(th.Context, &data, false)
|
||||
require.Nil(t, appErr)
|
||||
|
||||
// Do the same DIRECT channel again.
|
||||
appErr = th.App.importDirectChannel(th.Context, &data, false)
|
||||
require.Nil(t, appErr)
|
||||
// Check that one more GROUP channel is in the DB.
|
||||
AssertChannelCount(t, th.App, model.ChannelTypeDirect, directChannelCount+1)
|
||||
AssertChannelCount(t, th.App, model.ChannelTypeGroup, groupChannelCount+1)
|
||||
|
||||
// Check that no more channels are in the DB.
|
||||
AssertChannelCount(t, th.App, model.ChannelTypeDirect, directChannelCount+1)
|
||||
AssertChannelCount(t, th.App, model.ChannelTypeGroup, groupChannelCount+1)
|
||||
// Do the same DIRECT channel again.
|
||||
appErr = th.App.importDirectChannel(th.Context, &data, false)
|
||||
require.Nil(t, appErr)
|
||||
|
||||
// Update the channel's HEADER
|
||||
data.Header = ptrStr("New Channel Header 3")
|
||||
appErr = th.App.importDirectChannel(th.Context, &data, false)
|
||||
require.Nil(t, appErr)
|
||||
// Check that no more channels are in the DB.
|
||||
AssertChannelCount(t, th.App, model.ChannelTypeDirect, directChannelCount+1)
|
||||
AssertChannelCount(t, th.App, model.ChannelTypeGroup, groupChannelCount+1)
|
||||
|
||||
// Check that no more channels are in the DB.
|
||||
AssertChannelCount(t, th.App, model.ChannelTypeDirect, directChannelCount+1)
|
||||
AssertChannelCount(t, th.App, model.ChannelTypeGroup, groupChannelCount+1)
|
||||
// Update the channel's HEADER
|
||||
data.Header = ptrStr("New Channel Header 3")
|
||||
appErr = th.App.importDirectChannel(th.Context, &data, false)
|
||||
require.Nil(t, appErr)
|
||||
|
||||
// Get the channel to check that the header was updated.
|
||||
userIDs := []string{
|
||||
th.BasicUser.Id,
|
||||
th.BasicUser2.Id,
|
||||
user3.Id,
|
||||
}
|
||||
channel, appErr = th.App.createGroupChannel(th.Context, userIDs)
|
||||
require.Equal(t, appErr.Id, store.ChannelExistsError)
|
||||
require.Equal(t, channel.Header, *data.Header)
|
||||
// Check that no more channels are in the DB.
|
||||
AssertChannelCount(t, th.App, model.ChannelTypeDirect, directChannelCount+1)
|
||||
AssertChannelCount(t, th.App, model.ChannelTypeGroup, groupChannelCount+1)
|
||||
|
||||
// Import a channel with some favorites.
|
||||
data.Members = &[]string{
|
||||
th.BasicUser.Username,
|
||||
th.BasicUser2.Username,
|
||||
}
|
||||
data.FavoritedBy = &[]string{
|
||||
th.BasicUser.Username,
|
||||
th.BasicUser2.Username,
|
||||
}
|
||||
appErr = th.App.importDirectChannel(th.Context, &data, false)
|
||||
require.Nil(t, appErr)
|
||||
// Get the channel to check that the header was updated.
|
||||
userIDs := []string{
|
||||
th.BasicUser.Id,
|
||||
th.BasicUser2.Id,
|
||||
user3.Id,
|
||||
}
|
||||
channel, appErr := th.App.createGroupChannel(th.Context, userIDs)
|
||||
require.Equal(t, appErr.Id, store.ChannelExistsError)
|
||||
require.Equal(t, channel.Header, *data.Header)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
channel, appErr = th.App.GetOrCreateDirectChannel(th.Context, th.BasicUser.Id, th.BasicUser2.Id)
|
||||
require.Nil(t, appErr)
|
||||
checkPreference(t, th.App, th.BasicUser.Id, model.PreferenceCategoryFavoriteChannel, channel.Id, "true")
|
||||
checkPreference(t, th.App, th.BasicUser2.Id, model.PreferenceCategoryFavoriteChannel, channel.Id, "true")
|
||||
t.Run("Import a channel with some favorites", func(t *testing.T) {
|
||||
dataset := generateDataset(imports.DirectChannelImportData{
|
||||
Participants: []*imports.DirectChannelMemberImportData{
|
||||
{
|
||||
Username: model.NewString(th.BasicUser.Username),
|
||||
},
|
||||
{
|
||||
Username: model.NewString(th.BasicUser2.Username),
|
||||
},
|
||||
},
|
||||
})
|
||||
for name, data := range dataset {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
data.FavoritedBy = &[]string{
|
||||
th.BasicUser.Username,
|
||||
th.BasicUser2.Username,
|
||||
}
|
||||
appErr := th.App.importDirectChannel(th.Context, &data, false)
|
||||
require.Nil(t, appErr)
|
||||
|
||||
channel, appErr := th.App.GetOrCreateDirectChannel(th.Context, th.BasicUser.Id, th.BasicUser2.Id)
|
||||
require.Nil(t, appErr)
|
||||
checkPreference(t, th.App, th.BasicUser.Id, model.PreferenceCategoryFavoriteChannel, channel.Id, "true")
|
||||
checkPreference(t, th.App, th.BasicUser2.Id, model.PreferenceCategoryFavoriteChannel, channel.Id, "true")
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("Import a DM channel and user last view should be imported", func(t *testing.T) {
|
||||
lastView := model.GetMillis()
|
||||
data := imports.DirectChannelImportData{
|
||||
Participants: []*imports.DirectChannelMemberImportData{
|
||||
{
|
||||
Username: model.NewString(th.BasicUser.Username),
|
||||
LastViewedAt: ptrInt64(lastView),
|
||||
},
|
||||
{
|
||||
Username: model.NewString(th.BasicUser2.Username),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
appErr := th.App.importDirectChannel(th.Context, &data, false)
|
||||
require.Nil(t, appErr)
|
||||
|
||||
channel, appErr := th.App.GetOrCreateDirectChannel(th.Context, th.BasicUser.Id, th.BasicUser2.Id)
|
||||
require.Nil(t, appErr)
|
||||
|
||||
members, appErr := th.App.GetChannelMembersPage(th.Context, channel.Id, 0, 100)
|
||||
require.Nil(t, appErr)
|
||||
require.Len(t, members, 2)
|
||||
|
||||
for _, member := range members {
|
||||
if member.UserId == th.BasicUser.Id {
|
||||
require.Equal(t, member.LastViewedAt, lastView)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("Import a DM channel and preserve if the channel was shown to users", func(t *testing.T) {
|
||||
data := imports.DirectChannelImportData{
|
||||
Participants: []*imports.DirectChannelMemberImportData{
|
||||
{
|
||||
Username: model.NewString(th.BasicUser.Username),
|
||||
},
|
||||
{
|
||||
Username: model.NewString(th.BasicUser2.Username),
|
||||
},
|
||||
},
|
||||
ShownBy: &[]string{
|
||||
th.BasicUser.Username,
|
||||
},
|
||||
}
|
||||
|
||||
appErr := th.App.importDirectChannel(th.Context, &data, false)
|
||||
require.Nil(t, appErr)
|
||||
|
||||
channel, appErr := th.App.GetOrCreateDirectChannel(th.Context, th.BasicUser.Id, th.BasicUser2.Id)
|
||||
require.Nil(t, appErr)
|
||||
|
||||
members, appErr := th.App.GetChannelMembersPage(th.Context, channel.Id, 0, 100)
|
||||
require.Nil(t, appErr)
|
||||
require.Len(t, members, 2)
|
||||
|
||||
for _, member := range members {
|
||||
if member.UserId == th.BasicUser.Id {
|
||||
checkPreference(t, th.App, th.BasicUser.Id, model.PreferenceCategoryDirectChannelShow, th.BasicUser2.Id, "true")
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("Import a GM channel and preserve if the channel was shown to users", func(t *testing.T) {
|
||||
data := imports.DirectChannelImportData{
|
||||
Participants: []*imports.DirectChannelMemberImportData{
|
||||
{
|
||||
Username: model.NewString(th.BasicUser.Username),
|
||||
},
|
||||
{
|
||||
Username: model.NewString(th.BasicUser2.Username),
|
||||
},
|
||||
{
|
||||
Username: model.NewString(user3.Username),
|
||||
},
|
||||
},
|
||||
ShownBy: &[]string{
|
||||
th.BasicUser.Username,
|
||||
},
|
||||
}
|
||||
|
||||
appErr := th.App.importDirectChannel(th.Context, &data, false)
|
||||
require.Nil(t, appErr)
|
||||
|
||||
channel, appErr := th.App.GetGroupChannel(th.Context, []string{th.BasicUser.Id, th.BasicUser2.Id, user3.Id})
|
||||
require.Nil(t, appErr)
|
||||
|
||||
members, appErr := th.App.GetChannelMembersPage(th.Context, channel.Id, 0, 100)
|
||||
require.Nil(t, appErr)
|
||||
require.Len(t, members, 3)
|
||||
|
||||
for _, member := range members {
|
||||
if member.UserId == th.BasicUser.Id {
|
||||
checkPreference(t, th.App, th.BasicUser.Id, model.PreferenceCategoryGroupChannelShow, channel.Id, "true")
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestImportImportDirectPost(t *testing.T) {
|
||||
@@ -3332,9 +3535,13 @@ func TestImportImportDirectPost(t *testing.T) {
|
||||
|
||||
// Create the DIRECT channel.
|
||||
channelData := imports.DirectChannelImportData{
|
||||
Members: &[]string{
|
||||
th.BasicUser.Username,
|
||||
th.BasicUser2.Username,
|
||||
Participants: []*imports.DirectChannelMemberImportData{
|
||||
{
|
||||
Username: model.NewString(th.BasicUser.Username),
|
||||
},
|
||||
{
|
||||
Username: model.NewString(th.BasicUser2.Username),
|
||||
},
|
||||
},
|
||||
}
|
||||
appErr := th.App.importDirectChannel(th.Context, &channelData, false)
|
||||
@@ -3688,10 +3895,16 @@ func TestImportImportDirectPost(t *testing.T) {
|
||||
// Create the GROUP channel.
|
||||
user3 := th.CreateUser()
|
||||
channelData = imports.DirectChannelImportData{
|
||||
Members: &[]string{
|
||||
th.BasicUser.Username,
|
||||
th.BasicUser2.Username,
|
||||
user3.Username,
|
||||
Participants: []*imports.DirectChannelMemberImportData{
|
||||
{
|
||||
Username: model.NewString(th.BasicUser.Username),
|
||||
},
|
||||
{
|
||||
Username: model.NewString(th.BasicUser2.Username),
|
||||
},
|
||||
{
|
||||
Username: model.NewString(user3.Username),
|
||||
},
|
||||
},
|
||||
}
|
||||
appErr = th.App.importDirectChannel(th.Context, &channelData, false)
|
||||
|
||||
@@ -123,10 +123,27 @@ type UserChannelImportData struct {
|
||||
LastViewedAt *int64 `json:"last_viewed_at,omitempty"`
|
||||
}
|
||||
|
||||
type DirectChannelMemberImportData struct {
|
||||
Username *string `json:"username"`
|
||||
NotifyProps *UserChannelNotifyPropsImportData `json:"notify_props,omitempty"`
|
||||
SchemeUser *bool `json:"scheme_user,omitempty"`
|
||||
SchemeAdmin *bool `json:"scheme_admin,omitempty"`
|
||||
SchemeGuest *bool `json:"scheme_guest,omitempty"`
|
||||
MentionCount *int64 `json:"mention_count,omitempty"`
|
||||
MentionCountRoot *int64 `json:"mention_count_root,omitempty"`
|
||||
UrgentMentionCount *int64 `json:"urgend_mention_count,omitempty"`
|
||||
MsgCount *int64 `json:"msg_count,omitempty"`
|
||||
MsgCountRoot *int64 `json:"msg_count_root,omitempty"`
|
||||
LastViewedAt *int64 `json:"last_viewed_at,omitempty"`
|
||||
}
|
||||
|
||||
type UserChannelNotifyPropsImportData struct {
|
||||
Desktop *string `json:"desktop"`
|
||||
Mobile *string `json:"mobile"`
|
||||
MarkUnread *string `json:"mark_unread"`
|
||||
Desktop *string `json:"desktop"`
|
||||
Mobile *string `json:"mobile"`
|
||||
MarkUnread *string `json:"mark_unread"`
|
||||
Email *string `json:"email,omitempty"`
|
||||
IgnoreChannelMentions *string `json:"ignore_channel_mentions,omitempty"`
|
||||
ChannelAutoFollowThreads *string `json:"channel_auto_follow_threads,omitempty"`
|
||||
}
|
||||
|
||||
type EmojiImportData struct {
|
||||
@@ -173,8 +190,10 @@ type PostImportData struct {
|
||||
}
|
||||
|
||||
type DirectChannelImportData struct {
|
||||
Members *[]string `json:"members"`
|
||||
FavoritedBy *[]string `json:"favorited_by"`
|
||||
Members *[]string `json:"members,omitempty"`
|
||||
Participants []*DirectChannelMemberImportData `json:"participants,omitempty"`
|
||||
FavoritedBy *[]string `json:"favorited_by,omitempty"`
|
||||
ShownBy *[]string `json:"shown_by,omitempty"`
|
||||
|
||||
Header *string `json:"header"`
|
||||
}
|
||||
|
||||
@@ -489,11 +489,19 @@ func ValidatePostImportData(data *PostImportData, maxPostSize int) *model.AppErr
|
||||
}
|
||||
|
||||
func ValidateDirectChannelImportData(data *DirectChannelImportData) *model.AppError {
|
||||
if data.Members == nil {
|
||||
if data.Participants == nil && data.Members == nil {
|
||||
return model.NewAppError("BulkImport", "app.import.validate_direct_channel_import_data.members_required.error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if len(*data.Members) != 2 {
|
||||
if data.Participants != nil && len(data.Participants) != 2 {
|
||||
if len(data.Participants) < model.ChannelGroupMinUsers {
|
||||
return model.NewAppError("BulkImport", "app.import.validate_direct_channel_import_data.members_too_few.error", nil, "", http.StatusBadRequest)
|
||||
} else if len(data.Participants) > model.ChannelGroupMaxUsers {
|
||||
return model.NewAppError("BulkImport", "app.import.validate_direct_channel_import_data.members_too_many.error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
}
|
||||
|
||||
if data.Members != nil && len(*data.Members) != 2 {
|
||||
if len(*data.Members) < model.ChannelGroupMinUsers {
|
||||
return model.NewAppError("BulkImport", "app.import.validate_direct_channel_import_data.members_too_few.error", nil, "", http.StatusBadRequest)
|
||||
} else if len(*data.Members) > model.ChannelGroupMaxUsers {
|
||||
@@ -508,12 +516,20 @@ func ValidateDirectChannelImportData(data *DirectChannelImportData) *model.AppEr
|
||||
if data.FavoritedBy != nil {
|
||||
for _, favoriter := range *data.FavoritedBy {
|
||||
found := false
|
||||
for _, member := range *data.Members {
|
||||
if favoriter == member {
|
||||
for _, member := range data.Participants {
|
||||
if favoriter == *member.Username {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if data.Members != nil {
|
||||
for _, member := range *data.Members {
|
||||
if favoriter == member {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
return model.NewAppError("BulkImport", "app.import.validate_direct_channel_import_data.unknown_favoriter.error", map[string]any{"Username": favoriter}, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
@@ -4088,7 +4088,7 @@ func (s SqlChannelStore) GetAllDirectChannelsForExportAfter(limit int, afterId s
|
||||
channelIds = append(channelIds, channel.Id)
|
||||
}
|
||||
query = s.getQueryBuilder().
|
||||
Select("u.Username as Username, ChannelId, UserId, cm.Roles as Roles, LastViewedAt, MsgCount, MentionCount, MentionCountRoot, COALESCE(UrgentMentionCount, 0) UrgentMentionCount, cm.NotifyProps as NotifyProps, LastUpdateAt, SchemeUser, SchemeAdmin, (SchemeGuest IS NOT NULL AND SchemeGuest) as SchemeGuest").
|
||||
Select("u.Username as Username, ChannelId, UserId, cm.Roles as Roles, LastViewedAt, MsgCount, MsgCountRoot, MentionCount, MentionCountRoot, COALESCE(UrgentMentionCount, 0) UrgentMentionCount, cm.NotifyProps as NotifyProps, LastUpdateAt, SchemeUser, SchemeAdmin, (SchemeGuest IS NOT NULL AND SchemeGuest) as SchemeGuest").
|
||||
From("ChannelMembers cm").
|
||||
Join("Users u ON ( u.Id = cm.UserId )").
|
||||
Where(sq.Eq{"cm.ChannelId": channelIds})
|
||||
@@ -4106,12 +4106,11 @@ func (s SqlChannelStore) GetAllDirectChannelsForExportAfter(limit int, afterId s
|
||||
// Populate each channel with its members
|
||||
dmChannelsMap := make(map[string]*model.DirectChannelForExport)
|
||||
for _, channel := range directChannelsForExport {
|
||||
channel.Members = &[]string{}
|
||||
channel.Members = []*model.ChannelMemberForExport{}
|
||||
dmChannelsMap[channel.Id] = channel
|
||||
}
|
||||
for _, member := range channelMembers {
|
||||
members := dmChannelsMap[member.ChannelId].Members
|
||||
*members = append(*members, member.Username)
|
||||
dmChannelsMap[member.ChannelId].Members = append(dmChannelsMap[member.ChannelId].Members, member)
|
||||
}
|
||||
|
||||
return directChannelsForExport, nil
|
||||
|
||||
@@ -7852,7 +7852,7 @@ func testChannelStoreExportAllDirectChannelsDeletedChannel(t *testing.T, rctx re
|
||||
d1, nErr = ss.Channel().GetAllDirectChannelsForExportAfter(10000, strings.Repeat("0", 26), true)
|
||||
assert.NoError(t, nErr)
|
||||
assert.Len(t, d1, 1)
|
||||
assert.Len(t, *d1[0].Members, 2)
|
||||
assert.Len(t, d1[0].Members, 2)
|
||||
|
||||
// Manually truncate Channels table until testlib can handle cleanups
|
||||
s.GetMasterX().Exec("TRUNCATE Channels")
|
||||
|
||||
@@ -832,7 +832,17 @@ func (v *Validator) validateDirectChannel(info ImportFileInfo, line imports.Line
|
||||
}
|
||||
}
|
||||
|
||||
if data.Members != nil {
|
||||
if data.Participants != nil {
|
||||
for i, member := range data.Participants {
|
||||
if _, ok := v.users[*member.Username]; !ok {
|
||||
return &ImportValidationError{
|
||||
ImportFileInfo: info,
|
||||
FieldName: fmt.Sprintf("direct_channel.members[%d]", i),
|
||||
Err: fmt.Errorf("reference to unknown user %q", *member.Username),
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if data.Members != nil {
|
||||
for i, member := range *data.Members {
|
||||
if _, ok := v.users[member]; !ok {
|
||||
return &ImportValidationError{
|
||||
|
||||
@@ -394,10 +394,17 @@ func createPost(team string, channel string, allUsers []string, createAt int64)
|
||||
|
||||
func createDirectChannel(members []string) imports.LineImportData {
|
||||
header := fake.Sentence()
|
||||
var p []*imports.DirectChannelMemberImportData
|
||||
|
||||
for _, m := range members {
|
||||
p = append(p, &imports.DirectChannelMemberImportData{
|
||||
Username: model.NewString(m),
|
||||
})
|
||||
}
|
||||
|
||||
channel := imports.DirectChannelImportData{
|
||||
Members: &members,
|
||||
Header: &header,
|
||||
Participants: p,
|
||||
Header: &header,
|
||||
}
|
||||
return imports.LineImportData{
|
||||
Type: "direct_channel",
|
||||
|
||||
@@ -5174,6 +5174,14 @@
|
||||
"id": "app.import.import_direct_channel.create_group_channel.error",
|
||||
"translation": "Failed to create group channel"
|
||||
},
|
||||
{
|
||||
"id": "app.import.import_direct_channel.get_channel_members.error",
|
||||
"translation": "Failed to get channel members for direct channel"
|
||||
},
|
||||
{
|
||||
"id": "app.import.import_direct_channel.no_members.error",
|
||||
"translation": "There are no members for the direct channel"
|
||||
},
|
||||
{
|
||||
"id": "app.import.import_direct_channel.update_header_failed.error",
|
||||
"translation": "Failed to update direct channel header"
|
||||
|
||||
@@ -122,7 +122,7 @@ type ChannelForExport struct {
|
||||
|
||||
type DirectChannelForExport struct {
|
||||
Channel
|
||||
Members *[]string
|
||||
Members []*ChannelMemberForExport
|
||||
}
|
||||
|
||||
type ChannelModeration struct {
|
||||
|
||||
Ссылка в новой задаче
Block a user