summaryrefslogtreecommitdiffstats
path: root/store/sqlstore
diff options
context:
space:
mode:
authorJonathan <jonfritz@gmail.com>2017-12-12 09:42:29 -0500
committerGitHub <noreply@github.com>2017-12-12 09:42:29 -0500
commitab30c4daf935d33b7e6088d82eb7c49dc2717918 (patch)
tree685605246a589cea8bb490f022672b28b338e043 /store/sqlstore
parentfa9aa85705a86db8091aba2b4ff064e127c940ff (diff)
downloadchat-ab30c4daf935d33b7e6088d82eb7c49dc2717918.tar.gz
chat-ab30c4daf935d33b7e6088d82eb7c49dc2717918.tar.bz2
chat-ab30c4daf935d33b7e6088d82eb7c49dc2717918.zip
PLT-8297: Message Export Should Still Produce Valid Exports if ChannelMemberHistory Data is Missing (#7951)
* Added a less accurate ChannelMembers fallback that is used if export period occurs before MessageExport was enabled * Fixed test names * Improved testing * Made hasDataFromBefore() a little less strict * Fixed the test to cleanly truncate the ChannelMemberHistory table without exposing the db via the interface * Renamed a function for better clarity * Binary logic is hard
Diffstat (limited to 'store/sqlstore')
-rw-r--r--store/sqlstore/channel_member_history_store.go82
1 files changed, 73 insertions, 9 deletions
diff --git a/store/sqlstore/channel_member_history_store.go b/store/sqlstore/channel_member_history_store.go
index aa5037d32..182f37ce9 100644
--- a/store/sqlstore/channel_member_history_store.go
+++ b/store/sqlstore/channel_member_history_store.go
@@ -6,6 +6,8 @@ package sqlstore
import (
"net/http"
+ "database/sql"
+
l4g "github.com/alecthomas/log4go"
"github.com/mattermost/mattermost-server/model"
"github.com/mattermost/mattermost-server/store"
@@ -65,7 +67,47 @@ func (s SqlChannelMemberHistoryStore) LogLeaveEvent(userId string, channelId str
func (s SqlChannelMemberHistoryStore) GetUsersInChannelDuring(startTime int64, endTime int64, channelId string) store.StoreChannel {
return store.Do(func(result *store.StoreResult) {
- query := `
+ if useChannelMemberHistory, err := s.hasDataAtOrBefore(startTime); err != nil {
+ result.Err = model.NewAppError("SqlChannelMemberHistoryStore.GetUsersInChannelAt", "store.sql_channel_member_history.get_users_in_channel_during.app_error", nil, err.Error(), http.StatusInternalServerError)
+ } else if useChannelMemberHistory {
+ // the export period starts after the ChannelMemberHistory table was first introduced, so we can use the
+ // data from it for our export
+ if channelMemberHistories, err := s.getFromChannelMemberHistoryTable(startTime, endTime, channelId); err != nil {
+ result.Err = model.NewAppError("SqlChannelMemberHistoryStore.GetUsersInChannelAt", "store.sql_channel_member_history.get_users_in_channel_during.app_error", nil, err.Error(), http.StatusInternalServerError)
+ } else {
+ result.Data = channelMemberHistories
+ }
+ } else {
+ // the export period starts before the ChannelMemberHistory table was introduced, so we need to fake the
+ // data by assuming that anybody who has ever joined the channel in question was present during the export period.
+ // this may not always be true, but it's better than saying that somebody wasn't there when they were
+ if channelMemberHistories, err := s.getFromChannelMembersTable(startTime, endTime, channelId); err != nil {
+ result.Err = model.NewAppError("SqlChannelMemberHistoryStore.GetUsersInChannelAt", "store.sql_channel_member_history.get_users_in_channel_during.app_error", nil, err.Error(), http.StatusInternalServerError)
+ } else {
+ result.Data = channelMemberHistories
+ }
+ }
+ })
+}
+
+func (s SqlChannelMemberHistoryStore) hasDataAtOrBefore(time int64) (bool, error) {
+ type NullableCountResult struct {
+ Min sql.NullInt64
+ }
+ var result NullableCountResult
+ query := "SELECT MIN(JoinTime) AS Min FROM ChannelMemberHistory"
+ if err := s.GetReplica().SelectOne(&result, query); err != nil {
+ return false, err
+ } else if result.Min.Valid {
+ return result.Min.Int64 <= time, nil
+ } else {
+ // if the result was null, there are no rows in the table, so there is no data from before
+ return false, nil
+ }
+}
+
+func (s SqlChannelMemberHistoryStore) getFromChannelMemberHistoryTable(startTime int64, endTime int64, channelId string) ([]*model.ChannelMemberHistory, error) {
+ query := `
SELECT
cmh.*,
u.Email
@@ -76,14 +118,37 @@ func (s SqlChannelMemberHistoryStore) GetUsersInChannelDuring(startTime int64, e
AND (cmh.LeaveTime IS NULL OR cmh.LeaveTime >= :StartTime)
ORDER BY cmh.JoinTime ASC`
- params := map[string]interface{}{"ChannelId": channelId, "StartTime": startTime, "EndTime": endTime}
- var histories []*model.ChannelMemberHistory
- if _, err := s.GetReplica().Select(&histories, query, params); err != nil {
- result.Err = model.NewAppError("SqlChannelMemberHistoryStore.GetUsersInChannelAt", "store.sql_channel_member_history.get_users_in_channel_during.app_error", params, err.Error(), http.StatusInternalServerError)
- } else {
- result.Data = histories
+ params := map[string]interface{}{"ChannelId": channelId, "StartTime": startTime, "EndTime": endTime}
+ var histories []*model.ChannelMemberHistory
+ if _, err := s.GetReplica().Select(&histories, query, params); err != nil {
+ return nil, err
+ } else {
+ return histories, nil
+ }
+}
+
+func (s SqlChannelMemberHistoryStore) getFromChannelMembersTable(startTime int64, endTime int64, channelId string) ([]*model.ChannelMemberHistory, error) {
+ query := `
+ SELECT DISTINCT
+ ch.ChannelId,
+ ch.UserId,
+ u.email
+ FROM ChannelMembers AS ch
+ INNER JOIN Users AS u ON ch.UserId = u.id
+ WHERE ch.ChannelId = :ChannelId`
+
+ params := map[string]interface{}{"ChannelId": channelId}
+ var histories []*model.ChannelMemberHistory
+ if _, err := s.GetReplica().Select(&histories, query, params); err != nil {
+ return nil, err
+ } else {
+ // we have to fill in the join/leave times, because that data doesn't exist in the channel members table
+ for _, channelMemberHistory := range histories {
+ channelMemberHistory.JoinTime = startTime
+ channelMemberHistory.LeaveTime = model.NewInt64(endTime)
}
- })
+ return histories, nil
+ }
}
func (s SqlChannelMemberHistoryStore) PermanentDeleteBatch(endTime int64, limit int64) store.StoreChannel {
@@ -112,7 +177,6 @@ func (s SqlChannelMemberHistoryStore) PermanentDeleteBatch(endTime int64, limit
} 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
}