PLT-8233: Purge ChannelMemberHistory Data when Data Retention Job runs (#7937)

* Changed the channel member history purge function to match pattern established by other data retention purge methods

* Simplifying the channel member history store and associated tests

* Regenerating mocks

* Using a constant
Этот коммит содержится в:
Jonathan
2017-12-05 16:32:23 -05:00
коммит произвёл GitHub
родитель e7725106ed
Коммит c171872472
5 изменённых файлов: 47 добавлений и 23 удалений

Просмотреть файл

@@ -4443,7 +4443,7 @@
"translation": "Failed to get records" "translation": "Failed to get records"
}, },
{ {
"id": "store.sql_channel_member_history.purge_history_before.app_error", "id": "store.sql_channel_member_history.permanent_delete_batch.app_error",
"translation": "Failed to purge records" "translation": "Failed to purge records"
}, },
{ {

Просмотреть файл

@@ -39,7 +39,7 @@ func (s SqlChannelMemberHistoryStore) LogJoinEvent(userId string, channelId stri
} }
if err := s.GetMaster().Insert(channelMemberHistory); err != nil { if err := s.GetMaster().Insert(channelMemberHistory); err != nil {
result.Err = model.NewAppError("SqlChannelMemberHistoryStore.LogJoinEvent", "store.sql_channel_member_history.log_join_event.app_error", map[string]interface{}{"ChannelMemberHistory": channelMemberHistory}, err.Error(), http.StatusInternalServerError) result.Err = model.NewAppError("SqlChannelMemberHistoryStore.LogJoinEvent", "store.sql_channel_member_history.log_join_event.app_error", nil, err.Error(), http.StatusInternalServerError)
} }
}) })
} }
@@ -55,9 +55,9 @@ func (s SqlChannelMemberHistoryStore) LogLeaveEvent(userId string, channelId str
params := map[string]interface{}{"UserId": userId, "ChannelId": channelId, "LeaveTime": leaveTime} params := map[string]interface{}{"UserId": userId, "ChannelId": channelId, "LeaveTime": leaveTime}
if sqlResult, err := s.GetMaster().Exec(query, params); err != nil { if sqlResult, err := s.GetMaster().Exec(query, params); err != nil {
result.Err = model.NewAppError("SqlChannelMemberHistoryStore.LogLeaveEvent", "store.sql_channel_member_history.log_leave_event.update_error", nil, err.Error(), http.StatusInternalServerError) result.Err = model.NewAppError("SqlChannelMemberHistoryStore.LogLeaveEvent", "store.sql_channel_member_history.log_leave_event.update_error", params, err.Error(), http.StatusInternalServerError)
} else if rows, err := sqlResult.RowsAffected(); err == nil && rows != 1 { } else if rows, err := sqlResult.RowsAffected(); err == nil && rows != 1 {
// there was no join event to update // there was no join event to update - this is best effort, so no need to raise an error
l4g.Warn("Channel join event for user %v and channel %v not found", userId, channelId) l4g.Warn("Channel join event for user %v and channel %v not found", userId, channelId)
} }
}) })
@@ -86,17 +86,36 @@ func (s SqlChannelMemberHistoryStore) GetUsersInChannelDuring(startTime int64, e
}) })
} }
func (s SqlChannelMemberHistoryStore) PurgeHistoryBefore(time int64, channelId string) store.StoreChannel { func (s SqlChannelMemberHistoryStore) PermanentDeleteBatch(endTime int64, limit int64) store.StoreChannel {
return store.Do(func(result *store.StoreResult) { return store.Do(func(result *store.StoreResult) {
query := ` var query string
DELETE FROM ChannelMemberHistory if s.DriverName() == model.DATABASE_DRIVER_POSTGRES {
WHERE ChannelId = :ChannelId query =
AND LeaveTime IS NOT NULL `DELETE FROM ChannelMemberHistory
AND LeaveTime <= :AtTime` WHERE ctid IN (
SELECT ctid FROM ChannelMemberHistory
WHERE LeaveTime IS NOT NULL
AND LeaveTime <= :EndTime
LIMIT :Limit
);`
} else {
query =
`DELETE FROM ChannelMemberHistory
WHERE LeaveTime IS NOT NULL
AND LeaveTime <= :EndTime
LIMIT :Limit`
}
params := map[string]interface{}{"AtTime": time, "ChannelId": channelId} params := map[string]interface{}{"EndTime": endTime, "Limit": limit}
if _, err := s.GetMaster().Exec(query, params); err != nil { if sqlResult, err := s.GetMaster().Exec(query, params); err != nil {
result.Err = model.NewAppError("SqlChannelMemberHistoryStore.PurgeHistoryBefore", "store.sql_channel_member_history.purge_history_before.app_error", params, err.Error(), http.StatusInternalServerError) result.Err = model.NewAppError("SqlChannelMemberHistoryStore.PermanentDeleteBatchForChannel", "store.sql_channel_member_history.permanent_delete_batch.app_error", params, err.Error(), http.StatusInternalServerError)
} else {
if rowsAffected, err1 := sqlResult.RowsAffected(); err1 != nil {
result.Err = model.NewAppError("SqlChannelMemberHistoryStore.PermanentDeleteBatchForChannel", "store.sql_channel_member_history.permanent_delete_batch.app_error", params, err.Error(), http.StatusInternalServerError)
result.Data = int64(0)
} else {
result.Data = rowsAffected
}
} }
}) })
} }

Просмотреть файл

@@ -165,7 +165,7 @@ type ChannelMemberHistoryStore interface {
LogJoinEvent(userId string, channelId string, joinTime int64) StoreChannel LogJoinEvent(userId string, channelId string, joinTime int64) StoreChannel
LogLeaveEvent(userId string, channelId string, leaveTime int64) StoreChannel LogLeaveEvent(userId string, channelId string, leaveTime int64) StoreChannel
GetUsersInChannelDuring(startTime int64, endTime int64, channelId string) StoreChannel GetUsersInChannelDuring(startTime int64, endTime int64, channelId string) StoreChannel
PurgeHistoryBefore(time int64, channelId string) StoreChannel PermanentDeleteBatch(endTime int64, limit int64) StoreChannel
} }
type PostStore interface { type PostStore interface {

Просмотреть файл

@@ -6,6 +6,8 @@ package storetest
import ( import (
"testing" "testing"
"math"
"github.com/mattermost/mattermost-server/model" "github.com/mattermost/mattermost-server/model"
"github.com/mattermost/mattermost-server/store" "github.com/mattermost/mattermost-server/store"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
@@ -15,7 +17,7 @@ func TestChannelMemberHistoryStore(t *testing.T, ss store.Store) {
t.Run("Log Join Event", func(t *testing.T) { testLogJoinEvent(t, ss) }) t.Run("Log Join Event", func(t *testing.T) { testLogJoinEvent(t, ss) })
t.Run("Log Leave Event", func(t *testing.T) { testLogLeaveEvent(t, ss) }) t.Run("Log Leave Event", func(t *testing.T) { testLogLeaveEvent(t, ss) })
t.Run("Get Users In Channel At Time", func(t *testing.T) { testGetUsersInChannelAt(t, ss) }) t.Run("Get Users In Channel At Time", func(t *testing.T) { testGetUsersInChannelAt(t, ss) })
t.Run("Purge History", func(t *testing.T) { testPurgeHistoryBefore(t, ss) }) t.Run("Purge History", func(t *testing.T) { testPermanentDeleteBatch(t, ss) })
} }
func testLogJoinEvent(t *testing.T, ss store.Store) { func testLogJoinEvent(t *testing.T, ss store.Store) {
@@ -135,7 +137,7 @@ func testGetUsersInChannelAt(t *testing.T, ss store.Store) {
assert.Len(t, channelMembers, 0) assert.Len(t, channelMembers, 0)
} }
func testPurgeHistoryBefore(t *testing.T, ss store.Store) { func testPermanentDeleteBatch(t *testing.T, ss store.Store) {
// create a test channel // create a test channel
channel := model.Channel{ channel := model.Channel{
TeamId: model.NewId(), TeamId: model.NewId(),
@@ -171,8 +173,11 @@ func testPurgeHistoryBefore(t *testing.T, ss store.Store) {
channelMembers := store.Must(ss.ChannelMemberHistory().GetUsersInChannelDuring(joinTime+10, leaveTime-10, channel.Id)).([]*model.ChannelMemberHistory) channelMembers := store.Must(ss.ChannelMemberHistory().GetUsersInChannelDuring(joinTime+10, leaveTime-10, channel.Id)).([]*model.ChannelMemberHistory)
assert.Len(t, channelMembers, 2) assert.Len(t, channelMembers, 2)
// but if we purge the old data, only the user that didn't leave is left // the permanent delete should delete at least one record
store.Must(ss.ChannelMemberHistory().PurgeHistoryBefore(leaveTime, channel.Id)) rowsDeleted := store.Must(ss.ChannelMemberHistory().PermanentDeleteBatch(leaveTime, math.MaxInt64)).(int64)
assert.NotEqual(t, int64(0), rowsDeleted)
// after the delete, there should be one less member in the channel
channelMembers = store.Must(ss.ChannelMemberHistory().GetUsersInChannelDuring(joinTime+10, leaveTime-10, channel.Id)).([]*model.ChannelMemberHistory) channelMembers = store.Must(ss.ChannelMemberHistory().GetUsersInChannelDuring(joinTime+10, leaveTime-10, channel.Id)).([]*model.ChannelMemberHistory)
assert.Len(t, channelMembers, 1) assert.Len(t, channelMembers, 1)
assert.Equal(t, user2.Id, channelMembers[0].UserId) assert.Equal(t, user2.Id, channelMembers[0].UserId)

Просмотреть файл

@@ -60,13 +60,13 @@ func (_m *ChannelMemberHistoryStore) LogLeaveEvent(userId string, channelId stri
return r0 return r0
} }
// PurgeHistoryBefore provides a mock function with given fields: time, channelId // PermanentDeleteBatch provides a mock function with given fields: endTime, limit
func (_m *ChannelMemberHistoryStore) PurgeHistoryBefore(time int64, channelId string) store.StoreChannel { func (_m *ChannelMemberHistoryStore) PermanentDeleteBatch(endTime int64, limit int64) store.StoreChannel {
ret := _m.Called(time, channelId) ret := _m.Called(endTime, limit)
var r0 store.StoreChannel var r0 store.StoreChannel
if rf, ok := ret.Get(0).(func(int64, string) store.StoreChannel); ok { if rf, ok := ret.Get(0).(func(int64, int64) store.StoreChannel); ok {
r0 = rf(time, channelId) r0 = rf(endTime, limit)
} else { } else {
if ret.Get(0) != nil { if ret.Get(0) != nil {
r0 = ret.Get(0).(store.StoreChannel) r0 = ret.Get(0).(store.StoreChannel)