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.
This commit is contained in:
Gabe Jackson
2022-02-07 12:24:50 -05:00
committed by GitHub
parent d2cabaebab
commit ca8eb1347b
2 changed files with 56 additions and 8 deletions

View File

@@ -83,17 +83,18 @@ func (a *App) BulkExport(writer io.Writer, outPath string, opts BulkExportOpts)
}
mlog.Info("Bulk export: exporting teams")
if err := a.exportAllTeams(writer); err != nil {
teamNames, err := a.exportAllTeams(writer)
if err != nil {
return err
}
mlog.Info("Bulk export: exporting channels")
if err := a.exportAllChannels(writer); err != nil {
if err = a.exportAllChannels(writer, teamNames); err != nil {
return err
}
mlog.Info("Bulk export: exporting users")
if err := a.exportAllUsers(writer); err != nil {
if err = a.exportAllUsers(writer); err != nil {
return err
}
@@ -165,12 +166,13 @@ func (a *App) exportVersion(writer io.Writer) *model.AppError {
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)
teamNames := make(map[string]bool)
for {
teams, err := a.Srv().Store.Team().GetAllForExportAfter(1000, afterId)
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 {
@@ -184,18 +186,19 @@ func (a *App) exportAllTeams(writer io.Writer) *model.AppError {
if team.DeleteAt != 0 {
continue
}
teamNames[team.Name] = true
teamLine := ImportLineFromTeam(team)
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)
for {
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 {
continue
}
// Skip channels on deleted teams.
if ok := teamNames[channel.TeamName]; !ok {
continue
}
channelLine := ImportLineFromChannel(channel)
if err := a.exportWriteLine(writer, channelLine); err != nil {

View File

@@ -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)
}
}