diff --git a/app/export.go b/app/export.go index 853755a3a7..0116a6ea39 100644 --- a/app/export.go +++ b/app/export.go @@ -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 { diff --git a/app/export_test.go b/app/export_test.go index a427883e74..5f38b8e53d 100644 --- a/app/export_test.go +++ b/app/export_test.go @@ -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) + } +}