Skip exporting channels for deleted teams (#19494)
This corrects a bug where exports that contained deleted teams could fail to import. Channels must be skipped that belong to these deleted teams in order to produce a valid import bundle.
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
d2cabaebab
Коммит
ca8eb1347b
@@ -83,17 +83,18 @@ func (a *App) BulkExport(writer io.Writer, outPath string, opts BulkExportOpts)
|
|||||||
}
|
}
|
||||||
|
|
||||||
mlog.Info("Bulk export: exporting teams")
|
mlog.Info("Bulk export: exporting teams")
|
||||||
if err := a.exportAllTeams(writer); err != nil {
|
teamNames, err := a.exportAllTeams(writer)
|
||||||
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
mlog.Info("Bulk export: exporting channels")
|
mlog.Info("Bulk export: exporting channels")
|
||||||
if err := a.exportAllChannels(writer); err != nil {
|
if err = a.exportAllChannels(writer, teamNames); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
mlog.Info("Bulk export: exporting users")
|
mlog.Info("Bulk export: exporting users")
|
||||||
if err := a.exportAllUsers(writer); err != nil {
|
if err = a.exportAllUsers(writer); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -165,12 +166,13 @@ func (a *App) exportVersion(writer io.Writer) *model.AppError {
|
|||||||
return a.exportWriteLine(writer, versionLine)
|
return a.exportWriteLine(writer, versionLine)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *App) exportAllTeams(writer io.Writer) *model.AppError {
|
func (a *App) exportAllTeams(writer io.Writer) (map[string]bool, *model.AppError) {
|
||||||
afterId := strings.Repeat("0", 26)
|
afterId := strings.Repeat("0", 26)
|
||||||
|
teamNames := make(map[string]bool)
|
||||||
for {
|
for {
|
||||||
teams, err := a.Srv().Store.Team().GetAllForExportAfter(1000, afterId)
|
teams, err := a.Srv().Store.Team().GetAllForExportAfter(1000, afterId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return model.NewAppError("exportAllTeams", "app.team.get_all.app_error", nil, err.Error(), http.StatusInternalServerError)
|
return nil, model.NewAppError("exportAllTeams", "app.team.get_all.app_error", nil, err.Error(), http.StatusInternalServerError)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(teams) == 0 {
|
if len(teams) == 0 {
|
||||||
@@ -184,18 +186,19 @@ func (a *App) exportAllTeams(writer io.Writer) *model.AppError {
|
|||||||
if team.DeleteAt != 0 {
|
if team.DeleteAt != 0 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
teamNames[team.Name] = true
|
||||||
|
|
||||||
teamLine := ImportLineFromTeam(team)
|
teamLine := ImportLineFromTeam(team)
|
||||||
if err := a.exportWriteLine(writer, teamLine); err != nil {
|
if err := a.exportWriteLine(writer, teamLine); err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return teamNames, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *App) exportAllChannels(writer io.Writer) *model.AppError {
|
func (a *App) exportAllChannels(writer io.Writer, teamNames map[string]bool) *model.AppError {
|
||||||
afterId := strings.Repeat("0", 26)
|
afterId := strings.Repeat("0", 26)
|
||||||
for {
|
for {
|
||||||
channels, err := a.Srv().Store.Channel().GetAllChannelsForExportAfter(1000, afterId)
|
channels, err := a.Srv().Store.Channel().GetAllChannelsForExportAfter(1000, afterId)
|
||||||
@@ -215,6 +218,10 @@ func (a *App) exportAllChannels(writer io.Writer) *model.AppError {
|
|||||||
if channel.DeleteAt != 0 {
|
if channel.DeleteAt != 0 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
// Skip channels on deleted teams.
|
||||||
|
if ok := teamNames[channel.TeamName]; !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
channelLine := ImportLineFromChannel(channel)
|
channelLine := ImportLineFromChannel(channel)
|
||||||
if err := a.exportWriteLine(writer, channelLine); err != nil {
|
if err := a.exportWriteLine(writer, channelLine); err != nil {
|
||||||
|
|||||||
@@ -703,3 +703,44 @@ func TestBuildPostReplies(t *testing.T) {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestExportDeletedTeams(t *testing.T) {
|
||||||
|
th1 := Setup(t).InitBasic()
|
||||||
|
defer th1.TearDown()
|
||||||
|
|
||||||
|
team1 := th1.CreateTeam()
|
||||||
|
channel1 := th1.CreateChannel(team1)
|
||||||
|
th1.CreatePost(channel1)
|
||||||
|
|
||||||
|
// Delete the team to check that this is handled correctly on import.
|
||||||
|
err := th1.App.SoftDeleteTeam(team1.Id)
|
||||||
|
require.Nil(t, err)
|
||||||
|
|
||||||
|
var b bytes.Buffer
|
||||||
|
err = th1.App.BulkExport(&b, "somePath", BulkExportOpts{})
|
||||||
|
require.Nil(t, err)
|
||||||
|
|
||||||
|
th2 := Setup(t)
|
||||||
|
defer th2.TearDown()
|
||||||
|
err, i := th2.App.BulkImport(th2.Context, &b, nil, false, 5)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Equal(t, 0, i)
|
||||||
|
|
||||||
|
teams1, err := th1.App.GetAllTeams()
|
||||||
|
assert.Nil(t, err)
|
||||||
|
teams2, err := th2.App.GetAllTeams()
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Equal(t, len(teams1), len(teams2))
|
||||||
|
assert.ElementsMatch(t, teams1, teams2)
|
||||||
|
|
||||||
|
channels1, err := th1.App.GetAllChannels(0, 10, model.ChannelSearchOpts{})
|
||||||
|
assert.Nil(t, err)
|
||||||
|
channels2, err := th2.App.GetAllChannels(0, 10, model.ChannelSearchOpts{})
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Equal(t, len(channels1), len(channels2))
|
||||||
|
assert.ElementsMatch(t, channels1, channels2)
|
||||||
|
for _, team := range teams2 {
|
||||||
|
assert.NotContains(t, team.Name, team1.Name)
|
||||||
|
assert.NotContains(t, team.Id, team1.Id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Ссылка в новой задаче
Block a user