MM-27918 In-Product notices support (#15316)

Этот коммит содержится в:
Eli Yukelzon
2020-09-21 10:28:46 +03:00
коммит произвёл GitHub
родитель 43ed6ad690
Коммит 4e9ddd4686
63 изменённых файлов: 4549 добавлений и 7 удалений

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

@@ -36,6 +36,7 @@ type OpenTracingLayer struct {
PluginStore store.PluginStore
PostStore store.PostStore
PreferenceStore store.PreferenceStore
ProductNoticesStore store.ProductNoticesStore
ReactionStore store.ReactionStore
RoleStore store.RoleStore
SchemeStore store.SchemeStore
@@ -124,6 +125,10 @@ func (s *OpenTracingLayer) Preference() store.PreferenceStore {
return s.PreferenceStore
}
func (s *OpenTracingLayer) ProductNotices() store.ProductNoticesStore {
return s.ProductNoticesStore
}
func (s *OpenTracingLayer) Reaction() store.ReactionStore {
return s.ReactionStore
}
@@ -270,6 +275,11 @@ type OpenTracingLayerPreferenceStore struct {
Root *OpenTracingLayer
}
type OpenTracingLayerProductNoticesStore struct {
store.ProductNoticesStore
Root *OpenTracingLayer
}
type OpenTracingLayerReactionStore struct {
store.ReactionStore
Root *OpenTracingLayer
@@ -5537,6 +5547,78 @@ func (s *OpenTracingLayerPreferenceStore) Save(preferences *model.Preferences) e
return err
}
func (s *OpenTracingLayerProductNoticesStore) Clear(notices []string) error {
origCtx := s.Root.Store.Context()
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "ProductNoticesStore.Clear")
s.Root.Store.SetContext(newCtx)
defer func() {
s.Root.Store.SetContext(origCtx)
}()
defer span.Finish()
err := s.ProductNoticesStore.Clear(notices)
if err != nil {
span.LogFields(spanlog.Error(err))
ext.Error.Set(span, true)
}
return err
}
func (s *OpenTracingLayerProductNoticesStore) ClearOldNotices(currentNotices *model.ProductNotices) error {
origCtx := s.Root.Store.Context()
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "ProductNoticesStore.ClearOldNotices")
s.Root.Store.SetContext(newCtx)
defer func() {
s.Root.Store.SetContext(origCtx)
}()
defer span.Finish()
err := s.ProductNoticesStore.ClearOldNotices(currentNotices)
if err != nil {
span.LogFields(spanlog.Error(err))
ext.Error.Set(span, true)
}
return err
}
func (s *OpenTracingLayerProductNoticesStore) GetViews(userId string) ([]model.ProductNoticeViewState, error) {
origCtx := s.Root.Store.Context()
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "ProductNoticesStore.GetViews")
s.Root.Store.SetContext(newCtx)
defer func() {
s.Root.Store.SetContext(origCtx)
}()
defer span.Finish()
result, err := s.ProductNoticesStore.GetViews(userId)
if err != nil {
span.LogFields(spanlog.Error(err))
ext.Error.Set(span, true)
}
return result, err
}
func (s *OpenTracingLayerProductNoticesStore) View(userId string, notices []string) error {
origCtx := s.Root.Store.Context()
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "ProductNoticesStore.View")
s.Root.Store.SetContext(newCtx)
defer func() {
s.Root.Store.SetContext(origCtx)
}()
defer span.Finish()
err := s.ProductNoticesStore.View(userId, notices)
if err != nil {
span.LogFields(spanlog.Error(err))
ext.Error.Set(span, true)
}
return err
}
func (s *OpenTracingLayerReactionStore) BulkGetForPosts(postIds []string) ([]*model.Reaction, error) {
origCtx := s.Root.Store.Context()
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "ReactionStore.BulkGetForPosts")
@@ -9585,6 +9667,7 @@ func New(childStore store.Store, ctx context.Context) *OpenTracingLayer {
newStore.PluginStore = &OpenTracingLayerPluginStore{PluginStore: childStore.Plugin(), Root: &newStore}
newStore.PostStore = &OpenTracingLayerPostStore{PostStore: childStore.Post(), Root: &newStore}
newStore.PreferenceStore = &OpenTracingLayerPreferenceStore{PreferenceStore: childStore.Preference(), Root: &newStore}
newStore.ProductNoticesStore = &OpenTracingLayerProductNoticesStore{ProductNoticesStore: childStore.ProductNotices(), Root: &newStore}
newStore.ReactionStore = &OpenTracingLayerReactionStore{ReactionStore: childStore.Reaction(), Root: &newStore}
newStore.RoleStore = &OpenTracingLayerRoleStore{RoleStore: childStore.Role(), Root: &newStore}
newStore.SchemeStore = &OpenTracingLayerSchemeStore{SchemeStore: childStore.Scheme(), Root: &newStore}

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

@@ -38,6 +38,7 @@ type RetryLayer struct {
PluginStore store.PluginStore
PostStore store.PostStore
PreferenceStore store.PreferenceStore
ProductNoticesStore store.ProductNoticesStore
ReactionStore store.ReactionStore
RoleStore store.RoleStore
SchemeStore store.SchemeStore
@@ -126,6 +127,10 @@ func (s *RetryLayer) Preference() store.PreferenceStore {
return s.PreferenceStore
}
func (s *RetryLayer) ProductNotices() store.ProductNoticesStore {
return s.ProductNoticesStore
}
func (s *RetryLayer) Reaction() store.ReactionStore {
return s.ReactionStore
}
@@ -272,6 +277,11 @@ type RetryLayerPreferenceStore struct {
Root *RetryLayer
}
type RetryLayerProductNoticesStore struct {
store.ProductNoticesStore
Root *RetryLayer
}
type RetryLayerReactionStore struct {
store.ReactionStore
Root *RetryLayer
@@ -4706,6 +4716,86 @@ func (s *RetryLayerPreferenceStore) Save(preferences *model.Preferences) error {
}
func (s *RetryLayerProductNoticesStore) Clear(notices []string) error {
tries := 0
for {
err := s.ProductNoticesStore.Clear(notices)
if err == nil {
return nil
}
if !isRepeatableError(err) {
return err
}
tries++
if tries >= 3 {
err = errors.Wrap(err, "giving up after 3 consecutive repeatable transaction failures")
return err
}
}
}
func (s *RetryLayerProductNoticesStore) ClearOldNotices(currentNotices *model.ProductNotices) error {
tries := 0
for {
err := s.ProductNoticesStore.ClearOldNotices(currentNotices)
if err == nil {
return nil
}
if !isRepeatableError(err) {
return err
}
tries++
if tries >= 3 {
err = errors.Wrap(err, "giving up after 3 consecutive repeatable transaction failures")
return err
}
}
}
func (s *RetryLayerProductNoticesStore) GetViews(userId string) ([]model.ProductNoticeViewState, error) {
tries := 0
for {
result, err := s.ProductNoticesStore.GetViews(userId)
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
}
}
}
func (s *RetryLayerProductNoticesStore) View(userId string, notices []string) error {
tries := 0
for {
err := s.ProductNoticesStore.View(userId, notices)
if err == nil {
return nil
}
if !isRepeatableError(err) {
return err
}
tries++
if tries >= 3 {
err = errors.Wrap(err, "giving up after 3 consecutive repeatable transaction failures")
return err
}
}
}
func (s *RetryLayerReactionStore) BulkGetForPosts(postIds []string) ([]*model.Reaction, error) {
tries := 0
@@ -8261,6 +8351,7 @@ func New(childStore store.Store) *RetryLayer {
newStore.PluginStore = &RetryLayerPluginStore{PluginStore: childStore.Plugin(), Root: &newStore}
newStore.PostStore = &RetryLayerPostStore{PostStore: childStore.Post(), Root: &newStore}
newStore.PreferenceStore = &RetryLayerPreferenceStore{PreferenceStore: childStore.Preference(), Root: &newStore}
newStore.ProductNoticesStore = &RetryLayerProductNoticesStore{ProductNoticesStore: childStore.ProductNotices(), Root: &newStore}
newStore.ReactionStore = &RetryLayerReactionStore{ReactionStore: childStore.Reaction(), Root: &newStore}
newStore.RoleStore = &RetryLayerRoleStore{RoleStore: childStore.Role(), Root: &newStore}
newStore.SchemeStore = &RetryLayerSchemeStore{SchemeStore: childStore.Scheme(), Root: &newStore}

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

@@ -34,6 +34,7 @@ func genStore() *mocks.Store {
mock.On("Plugin").Return(&mocks.PluginStore{})
mock.On("Post").Return(&mocks.PostStore{})
mock.On("Preference").Return(&mocks.PreferenceStore{})
mock.On("ProductNotices").Return(&mocks.ProductNoticesStore{})
mock.On("Reaction").Return(&mocks.ReactionStore{})
mock.On("Role").Return(&mocks.RoleStore{})
mock.On("Scheme").Return(&mocks.SchemeStore{})

125
store/sqlstore/product_notices_store.go Обычный файл
Просмотреть файл

@@ -0,0 +1,125 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
package sqlstore
import (
sq "github.com/Masterminds/squirrel"
"github.com/mattermost/mattermost-server/v5/model"
"github.com/mattermost/mattermost-server/v5/store"
"time"
"github.com/pkg/errors"
)
type SqlProductNoticesStore struct {
SqlStore
}
func newSqlProductNoticesStore(sqlStore SqlStore) store.ProductNoticesStore {
s := SqlProductNoticesStore{sqlStore}
for _, db := range sqlStore.GetAllConns() {
table := db.AddTableWithName(model.ProductNoticeViewState{}, "ProductNoticeViewState").SetKeys(false, "UserId", "NoticeId")
table.ColMap("UserId").SetMaxSize(26)
table.ColMap("NoticeId").SetMaxSize(26)
}
return s
}
func (s SqlProductNoticesStore) createIndexesIfNotExists() {
s.CreateIndexIfNotExists("idx_notice_views_timestamp", "ProductNoticeViewState", "Timestamp")
s.CreateIndexIfNotExists("idx_notice_views_user_id", "ProductNoticeViewState", "UserId")
s.CreateIndexIfNotExists("idx_notice_views_notice_id", "ProductNoticeViewState", "NoticeId")
s.CreateCompositeIndexIfNotExists("idx_notice_views_user_notice", "ProductNoticeViewState", []string{"UserId", "NoticeId"})
}
func (s SqlProductNoticesStore) Clear(notices []string) error {
sql, args, _ := s.getQueryBuilder().Delete("ProductNoticeViewState").Where(sq.Eq{"NoticeId": notices}).ToSql()
if _, err := s.GetMaster().Exec(sql, args...); err != nil {
return errors.Wrapf(err, "failed to delete records from ProductNoticeViewState")
}
return nil
}
func (s SqlProductNoticesStore) ClearOldNotices(currentNotices *model.ProductNotices) error {
var notices []string
for _, currentNotice := range *currentNotices {
notices = append(notices, currentNotice.ID)
}
sql, args, _ := s.getQueryBuilder().Delete("ProductNoticeViewState").Where(sq.NotEq{"NoticeId": notices}).ToSql()
if _, err := s.GetMaster().Exec(sql, args...); err != nil {
return errors.Wrapf(err, "failed to delete records from ProductNoticeViewState")
}
return nil
}
func (s SqlProductNoticesStore) View(userId string, notices []string) error {
transaction, err := s.GetMaster().Begin()
if err != nil {
return errors.Wrap(err, "begin_transaction")
}
defer finalizeTransaction(transaction)
var noticeStates []model.ProductNoticeViewState
sql, args, _ := s.getQueryBuilder().
Select("*").
From("ProductNoticeViewState").
Where(sq.And{sq.Eq{"UserId": userId}, sq.Eq{"NoticeId": notices}}).
ToSql()
if _, err := transaction.Select(&noticeStates, sql, args...); err != nil {
return errors.Wrapf(err, "failed to get ProductNoticeViewState with userId=%s", userId)
}
now := time.Now().UTC().Unix()
// update existing records
for i := range noticeStates {
noticeStates[i].Viewed += 1
noticeStates[i].Timestamp = now
if _, err := transaction.Update(&noticeStates[i]); err != nil {
return errors.Wrapf(err, "failed to update ProductNoticeViewState")
}
}
// add new ones
haveNoticeState := func(n string) bool {
for _, ns := range noticeStates {
if ns.NoticeId == n {
return true
}
}
return false
}
for _, noticeId := range notices {
if !haveNoticeState(noticeId) {
if err := transaction.Insert(&model.ProductNoticeViewState{
UserId: userId,
NoticeId: noticeId,
Viewed: 1,
Timestamp: now,
}); err != nil {
return errors.Wrapf(err, "failed to insert ProductNoticeViewState")
}
}
}
if err := transaction.Commit(); err != nil {
return errors.Wrap(err, "commit_transaction")
}
return nil
}
func (s SqlProductNoticesStore) GetViews(userId string) ([]model.ProductNoticeViewState, error) {
var noticeStates []model.ProductNoticeViewState
sql, args, _ := s.getQueryBuilder().Select("*").From("ProductNoticeViewState").Where(sq.Eq{"UserId": userId}).ToSql()
if _, err := s.GetReplica().Select(&noticeStates, sql, args...); err != nil {
return nil, errors.Wrapf(err, "failed to get ProductNoticeViewState with userId=%s", userId)
}
return noticeStates, nil
}

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

@@ -0,0 +1,14 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
package sqlstore
import (
"testing"
"github.com/mattermost/mattermost-server/v5/store/storetest"
)
func TestProductNoticesStore(t *testing.T) {
StoreTest(t, storetest.TestProductNoticesStore)
}

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

@@ -98,6 +98,7 @@ type SqlSupplierStores struct {
role store.RoleStore
scheme store.SchemeStore
TermsOfService store.TermsOfServiceStore
productNotices store.ProductNoticesStore
group store.GroupStore
UserTermsOfService store.UserTermsOfServiceStore
linkMetadata store.LinkMetadataStore
@@ -170,7 +171,7 @@ func NewSqlSupplier(settings model.SqlSettings, metrics einterfaces.MetricsInter
supplier.stores.role = newSqlRoleStore(supplier)
supplier.stores.scheme = newSqlSchemeStore(supplier)
supplier.stores.group = newSqlGroupStore(supplier)
supplier.stores.productNotices = newSqlProductNoticesStore(supplier)
err := supplier.GetMaster().CreateTablesIfNotExists()
if err != nil {
mlog.Critical("Error creating database tables.", mlog.Err(err))
@@ -209,6 +210,7 @@ func NewSqlSupplier(settings model.SqlSettings, metrics einterfaces.MetricsInter
supplier.stores.userAccessToken.(*SqlUserAccessTokenStore).createIndexesIfNotExists()
supplier.stores.plugin.(*SqlPluginStore).createIndexesIfNotExists()
supplier.stores.TermsOfService.(SqlTermsOfServiceStore).createIndexesIfNotExists()
supplier.stores.productNotices.(SqlProductNoticesStore).createIndexesIfNotExists()
supplier.stores.UserTermsOfService.(SqlUserTermsOfServiceStore).createIndexesIfNotExists()
supplier.stores.linkMetadata.(*SqlLinkMetadataStore).createIndexesIfNotExists()
supplier.stores.group.(*SqlGroupStore).createIndexesIfNotExists()
@@ -1169,6 +1171,10 @@ func (ss *SqlSupplier) TermsOfService() store.TermsOfServiceStore {
return ss.stores.TermsOfService
}
func (ss *SqlSupplier) ProductNotices() store.ProductNoticesStore {
return ss.stores.productNotices
}
func (ss *SqlSupplier) UserTermsOfService() store.UserTermsOfServiceStore {
return ss.stores.UserTermsOfService
}

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

@@ -50,6 +50,7 @@ type Store interface {
ChannelMemberHistory() ChannelMemberHistoryStore
Plugin() PluginStore
TermsOfService() TermsOfServiceStore
ProductNotices() ProductNoticesStore
Group() GroupStore
UserTermsOfService() UserTermsOfServiceStore
LinkMetadata() LinkMetadataStore
@@ -646,6 +647,13 @@ type TermsOfServiceStore interface {
Get(id string, allowFromCache bool) (*model.TermsOfService, error)
}
type ProductNoticesStore interface {
View(userId string, notices []string) error
Clear(notices []string) error
ClearOldNotices(currentNotices *model.ProductNotices) error
GetViews(userId string) ([]model.ProductNoticeViewState, error)
}
type UserTermsOfServiceStore interface {
GetByUser(userId string) (*model.UserTermsOfService, error)
Save(userTermsOfService *model.UserTermsOfService) (*model.UserTermsOfService, error)

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

@@ -0,0 +1,80 @@
// Code generated by mockery v1.0.0. DO NOT EDIT.
// Regenerate this file using `make store-mocks`.
package mocks
import (
model "github.com/mattermost/mattermost-server/v5/model"
mock "github.com/stretchr/testify/mock"
)
// ProductNoticesStore is an autogenerated mock type for the ProductNoticesStore type
type ProductNoticesStore struct {
mock.Mock
}
// Clear provides a mock function with given fields: notices
func (_m *ProductNoticesStore) Clear(notices []string) error {
ret := _m.Called(notices)
var r0 error
if rf, ok := ret.Get(0).(func([]string) error); ok {
r0 = rf(notices)
} else {
r0 = ret.Error(0)
}
return r0
}
// ClearOldNotices provides a mock function with given fields: currentNotices
func (_m *ProductNoticesStore) ClearOldNotices(currentNotices *model.ProductNotices) error {
ret := _m.Called(currentNotices)
var r0 error
if rf, ok := ret.Get(0).(func(*model.ProductNotices) error); ok {
r0 = rf(currentNotices)
} else {
r0 = ret.Error(0)
}
return r0
}
// GetViews provides a mock function with given fields: userId
func (_m *ProductNoticesStore) GetViews(userId string) ([]model.ProductNoticeViewState, error) {
ret := _m.Called(userId)
var r0 []model.ProductNoticeViewState
if rf, ok := ret.Get(0).(func(string) []model.ProductNoticeViewState); ok {
r0 = rf(userId)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).([]model.ProductNoticeViewState)
}
}
var r1 error
if rf, ok := ret.Get(1).(func(string) error); ok {
r1 = rf(userId)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// View provides a mock function with given fields: userId, notices
func (_m *ProductNoticesStore) View(userId string, notices []string) error {
ret := _m.Called(userId, notices)
var r0 error
if rf, ok := ret.Get(0).(func(string, []string) error); ok {
r0 = rf(userId, notices)
} else {
r0 = ret.Error(0)
}
return r0
}

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

@@ -395,6 +395,22 @@ func (_m *Store) Preference() store.PreferenceStore {
return r0
}
// ProductNotices provides a mock function with given fields:
func (_m *Store) ProductNotices() store.ProductNoticesStore {
ret := _m.Called()
var r0 store.ProductNoticesStore
if rf, ok := ret.Get(0).(func() store.ProductNoticesStore); ok {
r0 = rf()
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(store.ProductNoticesStore)
}
}
return r0
}
// Reaction provides a mock function with given fields:
func (_m *Store) Reaction() store.ReactionStore {
ret := _m.Called()

79
store/storetest/product_notices_store.go Обычный файл
Просмотреть файл

@@ -0,0 +1,79 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
package storetest
import (
"github.com/mattermost/mattermost-server/v5/model"
"testing"
"github.com/mattermost/mattermost-server/v5/store"
"github.com/stretchr/testify/require"
)
func TestProductNoticesStore(t *testing.T, ss store.Store) {
t.Run("TestAddViewed", func(t *testing.T) { testAddViewed(t, ss) })
t.Run("TestUpdateViewed", func(t *testing.T) { testUpdateViewed(t, ss) })
t.Run("TestClearOld", func(t *testing.T) { testClearOld(t, ss) })
}
func testAddViewed(t *testing.T, ss store.Store) {
notices := []string{"noticeA", "noticeB"}
defer ss.ProductNotices().Clear(notices)
err := ss.ProductNotices().View("testuser", notices)
require.NoError(t, err)
err = ss.ProductNotices().View("testuser2", notices)
require.NoError(t, err)
res, err := ss.ProductNotices().GetViews("testuser")
require.NoError(t, err)
require.Len(t, res, 2)
}
func testUpdateViewed(t *testing.T, ss store.Store) {
noticesA := []string{"noticeA", "noticeB"}
noticesB := []string{"noticeB", "noticeC"}
defer ss.ProductNotices().Clear(noticesA)
defer ss.ProductNotices().Clear(noticesB)
// mark two notices
err := ss.ProductNotices().View("testuser", noticesA)
require.NoError(t, err)
// mark one old and one new
err = ss.ProductNotices().View("testuser", noticesB)
require.NoError(t, err)
res, err := ss.ProductNotices().GetViews("testuser")
require.NoError(t, err)
require.Len(t, res, 3)
// make sure that one B has two views
require.Equal(t, res[0].Viewed, int32(1))
require.Equal(t, res[1].Viewed, int32(2))
require.Equal(t, res[2].Viewed, int32(1))
// make sure that B's timestamp was updated
require.GreaterOrEqual(t, res[1].Timestamp, res[0].Timestamp)
}
func testClearOld(t *testing.T, ss store.Store) {
noticesA := []string{"noticeA", "noticeB"}
defer ss.ProductNotices().Clear(noticesA)
// mark two notices
err := ss.ProductNotices().View("testuser", noticesA)
require.NoError(t, err)
err = ss.ProductNotices().ClearOldNotices(&model.ProductNotices{
{
ID: "noticeA",
},
{
ID: "noticeC",
},
})
require.NoError(t, err)
res, err := ss.ProductNotices().GetViews("testuser")
require.NoError(t, err)
require.Len(t, res, 1)
}

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

@@ -47,6 +47,7 @@ type Store struct {
GroupStore mocks.GroupStore
UserTermsOfServiceStore mocks.UserTermsOfServiceStore
LinkMetadataStore mocks.LinkMetadataStore
ProductNoticesStore mocks.ProductNoticesStore
context context.Context
}
@@ -57,6 +58,7 @@ func (s *Store) Channel() store.ChannelStore { return &s.C
func (s *Store) Post() store.PostStore { return &s.PostStore }
func (s *Store) User() store.UserStore { return &s.UserStore }
func (s *Store) Bot() store.BotStore { return &s.BotStore }
func (s *Store) ProductNotices() store.ProductNoticesStore { return &s.ProductNoticesStore }
func (s *Store) Audit() store.AuditStore { return &s.AuditStore }
func (s *Store) ClusterDiscovery() store.ClusterDiscoveryStore { return &s.ClusterDiscoveryStore }
func (s *Store) Compliance() store.ComplianceStore { return &s.ComplianceStore }
@@ -131,5 +133,6 @@ func (s *Store) AssertExpectations(t mock.TestingT) bool {
&s.PluginStore,
&s.RoleStore,
&s.SchemeStore,
&s.ProductNoticesStore,
)
}

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

@@ -36,6 +36,7 @@ type TimerLayer struct {
PluginStore store.PluginStore
PostStore store.PostStore
PreferenceStore store.PreferenceStore
ProductNoticesStore store.ProductNoticesStore
ReactionStore store.ReactionStore
RoleStore store.RoleStore
SchemeStore store.SchemeStore
@@ -124,6 +125,10 @@ func (s *TimerLayer) Preference() store.PreferenceStore {
return s.PreferenceStore
}
func (s *TimerLayer) ProductNotices() store.ProductNoticesStore {
return s.ProductNoticesStore
}
func (s *TimerLayer) Reaction() store.ReactionStore {
return s.ReactionStore
}
@@ -270,6 +275,11 @@ type TimerLayerPreferenceStore struct {
Root *TimerLayer
}
type TimerLayerProductNoticesStore struct {
store.ProductNoticesStore
Root *TimerLayer
}
type TimerLayerReactionStore struct {
store.ReactionStore
Root *TimerLayer
@@ -5015,6 +5025,70 @@ func (s *TimerLayerPreferenceStore) Save(preferences *model.Preferences) error {
return err
}
func (s *TimerLayerProductNoticesStore) Clear(notices []string) error {
start := timemodule.Now()
err := s.ProductNoticesStore.Clear(notices)
elapsed := float64(timemodule.Since(start)) / float64(timemodule.Second)
if s.Root.Metrics != nil {
success := "false"
if err == nil {
success = "true"
}
s.Root.Metrics.ObserveStoreMethodDuration("ProductNoticesStore.Clear", success, elapsed)
}
return err
}
func (s *TimerLayerProductNoticesStore) ClearOldNotices(currentNotices *model.ProductNotices) error {
start := timemodule.Now()
err := s.ProductNoticesStore.ClearOldNotices(currentNotices)
elapsed := float64(timemodule.Since(start)) / float64(timemodule.Second)
if s.Root.Metrics != nil {
success := "false"
if err == nil {
success = "true"
}
s.Root.Metrics.ObserveStoreMethodDuration("ProductNoticesStore.ClearOldNotices", success, elapsed)
}
return err
}
func (s *TimerLayerProductNoticesStore) GetViews(userId string) ([]model.ProductNoticeViewState, error) {
start := timemodule.Now()
result, err := s.ProductNoticesStore.GetViews(userId)
elapsed := float64(timemodule.Since(start)) / float64(timemodule.Second)
if s.Root.Metrics != nil {
success := "false"
if err == nil {
success = "true"
}
s.Root.Metrics.ObserveStoreMethodDuration("ProductNoticesStore.GetViews", success, elapsed)
}
return result, err
}
func (s *TimerLayerProductNoticesStore) View(userId string, notices []string) error {
start := timemodule.Now()
err := s.ProductNoticesStore.View(userId, notices)
elapsed := float64(timemodule.Since(start)) / float64(timemodule.Second)
if s.Root.Metrics != nil {
success := "false"
if err == nil {
success = "true"
}
s.Root.Metrics.ObserveStoreMethodDuration("ProductNoticesStore.View", success, elapsed)
}
return err
}
func (s *TimerLayerReactionStore) BulkGetForPosts(postIds []string) ([]*model.Reaction, error) {
start := timemodule.Now()
@@ -8669,6 +8743,7 @@ func New(childStore store.Store, metrics einterfaces.MetricsInterface) *TimerLay
newStore.PluginStore = &TimerLayerPluginStore{PluginStore: childStore.Plugin(), Root: &newStore}
newStore.PostStore = &TimerLayerPostStore{PostStore: childStore.Post(), Root: &newStore}
newStore.PreferenceStore = &TimerLayerPreferenceStore{PreferenceStore: childStore.Preference(), Root: &newStore}
newStore.ProductNoticesStore = &TimerLayerProductNoticesStore{ProductNoticesStore: childStore.ProductNotices(), Root: &newStore}
newStore.ReactionStore = &TimerLayerReactionStore{ReactionStore: childStore.Reaction(), Root: &newStore}
newStore.RoleStore = &TimerLayerRoleStore{RoleStore: childStore.Role(), Root: &newStore}
newStore.SchemeStore = &TimerLayerSchemeStore{SchemeStore: childStore.Scheme(), Root: &newStore}