MM-47171 Export direct channel favorites (#21570)
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
279754c6b0
Коммит
b73bf144aa
@@ -626,7 +626,12 @@ func (a *App) exportAllDirectChannels(writer io.Writer) *model.AppError {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
channelLine := ImportLineFromDirectChannel(channel)
|
favoritedBy, err := a.buildFavoritedByList(channel.Id)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
channelLine := ImportLineFromDirectChannel(channel, favoritedBy)
|
||||||
if err := a.exportWriteLine(writer, channelLine); err != nil {
|
if err := a.exportWriteLine(writer, channelLine); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -636,6 +641,29 @@ func (a *App) exportAllDirectChannels(writer io.Writer) *model.AppError {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *App) buildFavoritedByList(channelID string) ([]string, *model.AppError) {
|
||||||
|
prefs, err := a.Srv().Store().Preference().GetCategoryAndName(model.PreferenceCategoryFavoriteChannel, channelID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, model.NewAppError("buildFavoritedByList", "app.preference.get_category.app_error", nil, "", http.StatusInternalServerError).Wrap(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
userIDs := make([]string, 0, len(prefs))
|
||||||
|
for _, pref := range prefs {
|
||||||
|
if pref.Value != "true" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
user, err := a.Srv().Store().User().Get(context.Background(), pref.UserId)
|
||||||
|
if err != nil {
|
||||||
|
return nil, model.NewAppError("buildFavoritedByList", "app.user.get.app_error", nil, "", http.StatusInternalServerError).Wrap(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
userIDs = append(userIDs, user.Username)
|
||||||
|
}
|
||||||
|
|
||||||
|
return userIDs, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (a *App) exportAllDirectPosts(ctx request.CTX, writer io.Writer, withAttachments bool) ([]imports.AttachmentImportData, *model.AppError) {
|
func (a *App) exportAllDirectPosts(ctx request.CTX, writer io.Writer, withAttachments bool) ([]imports.AttachmentImportData, *model.AppError) {
|
||||||
var attachments []imports.AttachmentImportData
|
var attachments []imports.AttachmentImportData
|
||||||
afterId := strings.Repeat("0", 26)
|
afterId := strings.Repeat("0", 26)
|
||||||
|
|||||||
@@ -39,18 +39,25 @@ func ImportLineFromChannel(channel *model.ChannelForExport) *imports.LineImportD
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func ImportLineFromDirectChannel(channel *model.DirectChannelForExport) *imports.LineImportData {
|
func ImportLineFromDirectChannel(channel *model.DirectChannelForExport, favoritedBy []string) *imports.LineImportData {
|
||||||
channelMembers := *channel.Members
|
channelMembers := *channel.Members
|
||||||
if len(channelMembers) == 1 {
|
if len(channelMembers) == 1 {
|
||||||
channelMembers = []string{channelMembers[0], channelMembers[0]}
|
channelMembers = []string{channelMembers[0], channelMembers[0]}
|
||||||
}
|
}
|
||||||
return &imports.LineImportData{
|
|
||||||
|
line := &imports.LineImportData{
|
||||||
Type: "direct_channel",
|
Type: "direct_channel",
|
||||||
DirectChannel: &imports.DirectChannelImportData{
|
DirectChannel: &imports.DirectChannelImportData{
|
||||||
Header: &channel.Header,
|
Header: &channel.Header,
|
||||||
Members: &channelMembers,
|
Members: &channelMembers,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(favoritedBy) != 0 {
|
||||||
|
line.DirectChannel.FavoritedBy = &favoritedBy
|
||||||
|
}
|
||||||
|
|
||||||
|
return line
|
||||||
}
|
}
|
||||||
|
|
||||||
func ImportLineFromUser(user *model.User, exportedPrefs map[string]*string) *imports.LineImportData {
|
func ImportLineFromUser(user *model.User, exportedPrefs map[string]*string) *imports.LineImportData {
|
||||||
|
|||||||
@@ -223,7 +223,16 @@ func TestExportDMChannel(t *testing.T) {
|
|||||||
defer th1.TearDown()
|
defer th1.TearDown()
|
||||||
|
|
||||||
// DM Channel
|
// DM Channel
|
||||||
th1.CreateDmChannel(th1.BasicUser2)
|
ch := th1.CreateDmChannel(th1.BasicUser2)
|
||||||
|
|
||||||
|
th1.App.Srv().Store().Preference().Save(model.Preferences{
|
||||||
|
{
|
||||||
|
UserId: th1.BasicUser2.Id,
|
||||||
|
Category: model.PreferenceCategoryFavoriteChannel,
|
||||||
|
Name: ch.Id,
|
||||||
|
Value: "true",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
var b bytes.Buffer
|
var b bytes.Buffer
|
||||||
err := th1.App.BulkExport(th1.Context, &b, "somePath", model.BulkExportOpts{})
|
err := th1.App.BulkExport(th1.Context, &b, "somePath", model.BulkExportOpts{})
|
||||||
@@ -250,6 +259,12 @@ func TestExportDMChannel(t *testing.T) {
|
|||||||
require.NoError(t, nErr)
|
require.NoError(t, nErr)
|
||||||
require.Equal(t, 1, len(channels))
|
require.Equal(t, 1, len(channels))
|
||||||
assert.ElementsMatch(t, []string{th1.BasicUser.Username, th1.BasicUser2.Username}, *channels[0].Members)
|
assert.ElementsMatch(t, []string{th1.BasicUser.Username, th1.BasicUser2.Username}, *channels[0].Members)
|
||||||
|
|
||||||
|
// Ensure the favorited channel was retained
|
||||||
|
fav, nErr := th2.App.Srv().Store().Preference().Get(th2.BasicUser2.Id, model.PreferenceCategoryFavoriteChannel, channels[0].Id)
|
||||||
|
require.NoError(t, nErr)
|
||||||
|
require.NotNil(t, fav)
|
||||||
|
require.Equal(t, "true", fav.Value)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("Invalid DM channel export", func(t *testing.T) {
|
t.Run("Invalid DM channel export", func(t *testing.T) {
|
||||||
|
|||||||
@@ -6624,6 +6624,24 @@ func (s *OpenTracingLayerPreferenceStore) GetCategory(userID string, category st
|
|||||||
return result, err
|
return result, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *OpenTracingLayerPreferenceStore) GetCategoryAndName(category string, nane string) (model.Preferences, error) {
|
||||||
|
origCtx := s.Root.Store.Context()
|
||||||
|
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "PreferenceStore.GetCategoryAndName")
|
||||||
|
s.Root.Store.SetContext(newCtx)
|
||||||
|
defer func() {
|
||||||
|
s.Root.Store.SetContext(origCtx)
|
||||||
|
}()
|
||||||
|
|
||||||
|
defer span.Finish()
|
||||||
|
result, err := s.PreferenceStore.GetCategoryAndName(category, nane)
|
||||||
|
if err != nil {
|
||||||
|
span.LogFields(spanlog.Error(err))
|
||||||
|
ext.Error.Set(span, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
return result, err
|
||||||
|
}
|
||||||
|
|
||||||
func (s *OpenTracingLayerPreferenceStore) PermanentDeleteByUser(userID string) error {
|
func (s *OpenTracingLayerPreferenceStore) PermanentDeleteByUser(userID string) error {
|
||||||
origCtx := s.Root.Store.Context()
|
origCtx := s.Root.Store.Context()
|
||||||
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "PreferenceStore.PermanentDeleteByUser")
|
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "PreferenceStore.PermanentDeleteByUser")
|
||||||
|
|||||||
@@ -7515,6 +7515,27 @@ func (s *RetryLayerPreferenceStore) GetCategory(userID string, category string)
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *RetryLayerPreferenceStore) GetCategoryAndName(category string, nane string) (model.Preferences, error) {
|
||||||
|
|
||||||
|
tries := 0
|
||||||
|
for {
|
||||||
|
result, err := s.PreferenceStore.GetCategoryAndName(category, nane)
|
||||||
|
if err == nil {
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
if !isRepeatableError(err) {
|
||||||
|
return result, err
|
||||||
|
}
|
||||||
|
tries++
|
||||||
|
if tries >= 3 {
|
||||||
|
err = errors.Wrap(err, "giving up after 3 consecutive repeatable transaction failures")
|
||||||
|
return result, err
|
||||||
|
}
|
||||||
|
timepkg.Sleep(100 * timepkg.Millisecond)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
func (s *RetryLayerPreferenceStore) PermanentDeleteByUser(userID string) error {
|
func (s *RetryLayerPreferenceStore) PermanentDeleteByUser(userID string) error {
|
||||||
|
|
||||||
tries := 0
|
tries := 0
|
||||||
|
|||||||
@@ -140,6 +140,23 @@ func (s SqlPreferenceStore) Get(userId string, category string, name string) (*m
|
|||||||
return &preference, nil
|
return &preference, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s SqlPreferenceStore) GetCategoryAndName(category string, name string) (model.Preferences, error) {
|
||||||
|
var preferences model.Preferences
|
||||||
|
query, args, err := s.getQueryBuilder().
|
||||||
|
Select("*").
|
||||||
|
From("Preferences").
|
||||||
|
Where(sq.Eq{"Category": category}).
|
||||||
|
Where(sq.Eq{"Name": name}).
|
||||||
|
ToSql()
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "could not build sql query to get preference")
|
||||||
|
}
|
||||||
|
if err = s.GetReplicaX().Select(&preferences, query, args...); err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "failed to find Preference with category=%s, name=%s", category, name)
|
||||||
|
}
|
||||||
|
return preferences, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (s SqlPreferenceStore) GetCategory(userId string, category string) (model.Preferences, error) {
|
func (s SqlPreferenceStore) GetCategory(userId string, category string) (model.Preferences, error) {
|
||||||
var preferences model.Preferences
|
var preferences model.Preferences
|
||||||
query, args, err := s.getQueryBuilder().
|
query, args, err := s.getQueryBuilder().
|
||||||
|
|||||||
@@ -633,6 +633,7 @@ type CommandWebhookStore interface {
|
|||||||
type PreferenceStore interface {
|
type PreferenceStore interface {
|
||||||
Save(preferences model.Preferences) error
|
Save(preferences model.Preferences) error
|
||||||
GetCategory(userID string, category string) (model.Preferences, error)
|
GetCategory(userID string, category string) (model.Preferences, error)
|
||||||
|
GetCategoryAndName(category string, nane string) (model.Preferences, error)
|
||||||
Get(userID string, category string, name string) (*model.Preference, error)
|
Get(userID string, category string, name string) (*model.Preference, error)
|
||||||
GetAll(userID string) (model.Preferences, error)
|
GetAll(userID string) (model.Preferences, error)
|
||||||
Delete(userID, category, name string) error
|
Delete(userID, category, name string) error
|
||||||
|
|||||||
@@ -167,6 +167,29 @@ func (_m *PreferenceStore) GetCategory(userID string, category string) (model.Pr
|
|||||||
return r0, r1
|
return r0, r1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetCategoryAndName provides a mock function with given fields: category, nane
|
||||||
|
func (_m *PreferenceStore) GetCategoryAndName(category string, nane string) (model.Preferences, error) {
|
||||||
|
ret := _m.Called(category, nane)
|
||||||
|
|
||||||
|
var r0 model.Preferences
|
||||||
|
if rf, ok := ret.Get(0).(func(string, string) model.Preferences); ok {
|
||||||
|
r0 = rf(category, nane)
|
||||||
|
} else {
|
||||||
|
if ret.Get(0) != nil {
|
||||||
|
r0 = ret.Get(0).(model.Preferences)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var r1 error
|
||||||
|
if rf, ok := ret.Get(1).(func(string, string) error); ok {
|
||||||
|
r1 = rf(category, nane)
|
||||||
|
} else {
|
||||||
|
r1 = ret.Error(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
return r0, r1
|
||||||
|
}
|
||||||
|
|
||||||
// PermanentDeleteByUser provides a mock function with given fields: userID
|
// PermanentDeleteByUser provides a mock function with given fields: userID
|
||||||
func (_m *PreferenceStore) PermanentDeleteByUser(userID string) error {
|
func (_m *PreferenceStore) PermanentDeleteByUser(userID string) error {
|
||||||
ret := _m.Called(userID)
|
ret := _m.Called(userID)
|
||||||
|
|||||||
@@ -5987,6 +5987,22 @@ func (s *TimerLayerPreferenceStore) GetCategory(userID string, category string)
|
|||||||
return result, err
|
return result, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *TimerLayerPreferenceStore) GetCategoryAndName(category string, nane string) (model.Preferences, error) {
|
||||||
|
start := time.Now()
|
||||||
|
|
||||||
|
result, err := s.PreferenceStore.GetCategoryAndName(category, nane)
|
||||||
|
|
||||||
|
elapsed := float64(time.Since(start)) / float64(time.Second)
|
||||||
|
if s.Root.Metrics != nil {
|
||||||
|
success := "false"
|
||||||
|
if err == nil {
|
||||||
|
success = "true"
|
||||||
|
}
|
||||||
|
s.Root.Metrics.ObserveStoreMethodDuration("PreferenceStore.GetCategoryAndName", success, elapsed)
|
||||||
|
}
|
||||||
|
return result, err
|
||||||
|
}
|
||||||
|
|
||||||
func (s *TimerLayerPreferenceStore) PermanentDeleteByUser(userID string) error {
|
func (s *TimerLayerPreferenceStore) PermanentDeleteByUser(userID string) error {
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
|
|
||||||
|
|||||||
Ссылка в новой задаче
Block a user