[MM-40917] - Inactive Server Email Notification (#19374)

* [MM-40917] - Inactive Server Email Notification

* add email template

* make store layers

* add some store tests

* fix translations

* fix logic

* improve

* fix lint

* feedback-impl

* fix wrong text

* optimize queries

* move feature flag check

* feedback impl-1

* add line

* feedback impl

Co-authored-by: Mattermod <mattermod@users.noreply.github.com>
Этот коммит содержится в:
Allan Guwatudde
2022-02-22 20:41:58 +03:00
коммит произвёл GitHub
родитель 1b1ba687bb
Коммит 8d6d1c51c2
17 изменённых файлов: 1038 добавлений и 1 удалений

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

@@ -5489,6 +5489,24 @@ func (s *OpenTracingLayerPostStore) GetFlaggedPostsForTeam(userID string, teamID
return result, err
}
func (s *OpenTracingLayerPostStore) GetLastPostRowCreateAt() (int64, error) {
origCtx := s.Root.Store.Context()
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "PostStore.GetLastPostRowCreateAt")
s.Root.Store.SetContext(newCtx)
defer func() {
s.Root.Store.SetContext(origCtx)
}()
defer span.Finish()
result, err := s.PostStore.GetLastPostRowCreateAt()
if err != nil {
span.LogFields(spanlog.Error(err))
ext.Error.Set(span, true)
}
return result, err
}
func (s *OpenTracingLayerPostStore) GetMaxPostSize() int {
origCtx := s.Root.Store.Context()
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "PostStore.GetMaxPostSize")
@@ -7261,6 +7279,24 @@ func (s *OpenTracingLayerSessionStore) Get(ctx context.Context, sessionIDOrToken
return result, err
}
func (s *OpenTracingLayerSessionStore) GetLastSessionRowCreateAt() (int64, error) {
origCtx := s.Root.Store.Context()
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "SessionStore.GetLastSessionRowCreateAt")
s.Root.Store.SetContext(newCtx)
defer func() {
s.Root.Store.SetContext(origCtx)
}()
defer span.Finish()
result, err := s.SessionStore.GetLastSessionRowCreateAt()
if err != nil {
span.LogFields(spanlog.Error(err))
ext.Error.Set(span, true)
}
return result, err
}
func (s *OpenTracingLayerSessionStore) GetSessions(userID string) ([]*model.Session, error) {
origCtx := s.Root.Store.Context()
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "SessionStore.GetSessions")

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

@@ -6211,6 +6211,27 @@ func (s *RetryLayerPostStore) GetFlaggedPostsForTeam(userID string, teamID strin
}
func (s *RetryLayerPostStore) GetLastPostRowCreateAt() (int64, error) {
tries := 0
for {
result, err := s.PostStore.GetLastPostRowCreateAt()
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 *RetryLayerPostStore) GetMaxPostSize() int {
return s.PostStore.GetMaxPostSize()
@@ -8260,6 +8281,27 @@ func (s *RetryLayerSessionStore) Get(ctx context.Context, sessionIDOrToken strin
}
func (s *RetryLayerSessionStore) GetLastSessionRowCreateAt() (int64, error) {
tries := 0
for {
result, err := s.SessionStore.GetLastSessionRowCreateAt()
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 *RetryLayerSessionStore) GetSessions(userID string) ([]*model.Session, error) {
tries := 0

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

@@ -2057,6 +2057,17 @@ func (s *SqlPostStore) AnalyticsPostCount(teamId string, mustHaveFile bool, must
return v, nil
}
func (s *SqlPostStore) GetLastPostRowCreateAt() (int64, error) {
query := `SELECT CREATEAT FROM Posts ORDER BY CREATEAT DESC LIMIT 1`
var createAt int64
err := s.GetReplicaX().Get(&createAt, query)
if err != nil {
return 0, errors.Wrapf(err, "failed to get last post createat")
}
return createAt, nil
}
func (s *SqlPostStore) GetPostsCreatedAt(channelId string, time int64) ([]*model.Post, error) {
query := `SELECT * FROM Posts WHERE CreateAt = ? AND ChannelId = ?`

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

@@ -217,6 +217,17 @@ func (me SqlSessionStore) UpdateExpiresAt(sessionId string, time int64) error {
return nil
}
func (me *SqlSessionStore) GetLastSessionRowCreateAt() (int64, error) {
query := `SELECT CREATEAT FROM Sessions ORDER BY CREATEAT DESC LIMIT 1`
var createAt int64
err := me.GetReplicaX().Get(&createAt, query)
if err != nil {
return 0, errors.Wrapf(err, "failed to get last session creatat")
}
return createAt, nil
}
func (me SqlSessionStore) UpdateLastActivityAt(sessionId string, time int64) error {
_, err := me.GetMasterX().Exec("UPDATE Sessions SET LastActivityAt = ? WHERE Id = ?", time, sessionId)
if err != nil {

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

@@ -347,6 +347,7 @@ type PostStore interface {
AnalyticsPostCount(teamID string, mustHaveFile bool, mustHaveHashtag bool) (int64, error)
ClearCaches()
InvalidateLastPostTimeCache(channelID string)
GetLastPostRowCreateAt() (int64, error)
GetPostsCreatedAt(channelID string, time int64) ([]*model.Post, error)
Overwrite(post *model.Post) (*model.Post, error)
OverwriteMultiple(posts []*model.Post) ([]*model.Post, int, error)
@@ -462,6 +463,7 @@ type SessionStore interface {
Remove(sessionIDOrToken string) error
RemoveAllSessions() error
PermanentDeleteSessionsByUser(teamID string) error
GetLastSessionRowCreateAt() (int64, error)
UpdateExpiresAt(sessionID string, time int64) error
UpdateLastActivityAt(sessionID string, time int64) error
UpdateRoles(userID string, roles string) (string, error)

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

@@ -252,6 +252,27 @@ func (_m *PostStore) GetFlaggedPostsForTeam(userID string, teamID string, offset
return r0, r1
}
// GetLastPostRowCreateAt provides a mock function with given fields:
func (_m *PostStore) GetLastPostRowCreateAt() (int64, error) {
ret := _m.Called()
var r0 int64
if rf, ok := ret.Get(0).(func() int64); ok {
r0 = rf()
} else {
r0 = ret.Get(0).(int64)
}
var r1 error
if rf, ok := ret.Get(1).(func() error); ok {
r1 = rf()
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// GetMaxPostSize provides a mock function with given fields:
func (_m *PostStore) GetMaxPostSize() int {
ret := _m.Called()

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

@@ -74,6 +74,27 @@ func (_m *SessionStore) Get(ctx context.Context, sessionIDOrToken string) (*mode
return r0, r1
}
// GetLastSessionRowCreateAt provides a mock function with given fields:
func (_m *SessionStore) GetLastSessionRowCreateAt() (int64, error) {
ret := _m.Called()
var r0 int64
if rf, ok := ret.Get(0).(func() int64); ok {
r0 = rf()
} else {
r0 = ret.Get(0).(int64)
}
var r1 error
if rf, ok := ret.Get(1).(func() error); ok {
r1 = rf()
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// GetSessions provides a mock function with given fields: userID
func (_m *SessionStore) GetSessions(userID string) ([]*model.Session, error) {
ret := _m.Called(userID)

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

@@ -43,6 +43,7 @@ func TestPostStore(t *testing.T, ss store.Store, s SqlStore) {
t.Run("GetFlaggedPosts", func(t *testing.T) { testPostStoreGetFlaggedPosts(t, ss) })
t.Run("GetFlaggedPostsForChannel", func(t *testing.T) { testPostStoreGetFlaggedPostsForChannel(t, ss) })
t.Run("GetPostsCreatedAt", func(t *testing.T) { testPostStoreGetPostsCreatedAt(t, ss) })
t.Run("GetLastPostRowCreateAt", func(t *testing.T) { testPostStoreGetLastPostRowCreateAt(t, ss) })
t.Run("Overwrite", func(t *testing.T) { testPostStoreOverwrite(t, ss) })
t.Run("OverwriteMultiple", func(t *testing.T) { testPostStoreOverwriteMultiple(t, ss) })
t.Run("GetPostsByIds", func(t *testing.T) { testPostStoreGetPostsByIds(t, ss) })
@@ -2484,6 +2485,31 @@ func testPostStoreGetFlaggedPostsForChannel(t *testing.T, ss store.Store) {
require.Len(t, r.Order, 0, "should have 0 posts")
}
func testPostStoreGetLastPostRowCreateAt(t *testing.T, ss store.Store) {
createTime1 := model.GetMillis() + 1
o0 := &model.Post{}
o0.ChannelId = model.NewId()
o0.UserId = model.NewId()
o0.Message = NewTestId()
o0.CreateAt = createTime1
o0, err := ss.Post().Save(o0)
require.NoError(t, err)
createTime2 := model.GetMillis() + 2
o1 := &model.Post{}
o1.ChannelId = o0.ChannelId
o1.UserId = model.NewId()
o1.Message = "Latest message"
o1.CreateAt = createTime2
_, err = ss.Post().Save(o1)
require.NoError(t, err)
createAt, err := ss.Post().GetLastPostRowCreateAt()
require.NoError(t, err)
assert.Equal(t, createAt, createTime2)
}
func testPostStoreGetPostsCreatedAt(t *testing.T, ss store.Store) {
createTime := model.GetMillis() + 1

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

@@ -33,6 +33,7 @@ func TestSessionStore(t *testing.T, ss store.Store) {
t.Run("SessionUpdateDeviceId2", func(t *testing.T) { testSessionUpdateDeviceId2(t, ss) })
t.Run("UpdateExpiresAt", func(t *testing.T) { testSessionStoreUpdateExpiresAt(t, ss) })
t.Run("UpdateLastActivityAt", func(t *testing.T) { testSessionStoreUpdateLastActivityAt(t, ss) })
t.Run("GetLastSessionRowCreateAt", func(t *testing.T) { testSessionStoreGetLastSessionRowCreateAt(t, ss) })
t.Run("SessionCount", func(t *testing.T) { testSessionCount(t, ss) })
t.Run("GetSessionsExpired", func(t *testing.T) { testGetSessionsExpired(t, ss) })
t.Run("UpdateExpiredNotify", func(t *testing.T) { testUpdateExpiredNotify(t, ss) })
@@ -46,6 +47,23 @@ func testSessionStoreSave(t *testing.T, ss store.Store) {
require.NoError(t, err)
}
func testSessionStoreGetLastSessionRowCreateAt(t *testing.T, ss store.Store) {
s1 := &model.Session{}
s1.UserId = model.NewId()
_, err := ss.Session().Save(s1)
require.NoError(t, err)
latestSessionUserid := model.NewId()
s2 := &model.Session{}
s2.UserId = latestSessionUserid
latestSession, err := ss.Session().Save(s2)
require.NoError(t, err)
createAt, err := ss.Session().GetLastSessionRowCreateAt()
require.NoError(t, err)
assert.Equal(t, latestSession.CreateAt, createAt)
}
func testSessionGet(t *testing.T, ss store.Store) {
s1 := &model.Session{}
s1.UserId = model.NewId()

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

@@ -4970,6 +4970,22 @@ func (s *TimerLayerPostStore) GetFlaggedPostsForTeam(userID string, teamID strin
return result, err
}
func (s *TimerLayerPostStore) GetLastPostRowCreateAt() (int64, error) {
start := timemodule.Now()
result, err := s.PostStore.GetLastPostRowCreateAt()
elapsed := float64(timemodule.Since(start)) / float64(timemodule.Second)
if s.Root.Metrics != nil {
success := "false"
if err == nil {
success = "true"
}
s.Root.Metrics.ObserveStoreMethodDuration("PostStore.GetLastPostRowCreateAt", success, elapsed)
}
return result, err
}
func (s *TimerLayerPostStore) GetMaxPostSize() int {
start := timemodule.Now()
@@ -6553,6 +6569,22 @@ func (s *TimerLayerSessionStore) Get(ctx context.Context, sessionIDOrToken strin
return result, err
}
func (s *TimerLayerSessionStore) GetLastSessionRowCreateAt() (int64, error) {
start := timemodule.Now()
result, err := s.SessionStore.GetLastSessionRowCreateAt()
elapsed := float64(timemodule.Since(start)) / float64(timemodule.Second)
if s.Root.Metrics != nil {
success := "false"
if err == nil {
success = "true"
}
s.Root.Metrics.ObserveStoreMethodDuration("SessionStore.GetLastSessionRowCreateAt", success, elapsed)
}
return result, err
}
func (s *TimerLayerSessionStore) GetSessions(userID string) ([]*model.Session, error) {
start := timemodule.Now()