MM-29400 Mark all current notices as viewed for newly created users (#15840)

* Added clearing of notices for new users

* ci kick
Этот коммит содержится в:
Eli Yukelzon
2020-10-07 17:46:07 +03:00
коммит произвёл GitHub
родитель 25fd59a435
Коммит f2e5e1562d
4 изменённых файлов: 40 добавлений и 3 удалений

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

@@ -177,6 +177,8 @@ type AppIface interface {
// To get the plugins environment when the plugins are disabled, manually acquire the plugins // To get the plugins environment when the plugins are disabled, manually acquire the plugins
// lock instead. // lock instead.
GetPluginsEnvironment() *plugin.Environment GetPluginsEnvironment() *plugin.Environment
// GetProductNotices is called from the frontend to fetch the product notices that are relevant to the caller
GetProductNotices(userId, teamId string, client model.NoticeClientType, clientVersion string, locale string) (model.NoticeMessages, *model.AppError)
// GetPublicKey will return the actual public key saved in the `name` file. // GetPublicKey will return the actual public key saved in the `name` file.
GetPublicKey(name string) ([]byte, *model.AppError) GetPublicKey(name string) ([]byte, *model.AppError)
// GetSanitizedConfig gets the configuration for a system admin without any secrets. // GetSanitizedConfig gets the configuration for a system admin without any secrets.
@@ -314,6 +316,13 @@ type AppIface interface {
UpdateChannel(channel *model.Channel) (*model.Channel, *model.AppError) UpdateChannel(channel *model.Channel) (*model.Channel, *model.AppError)
// UpdateChannelScheme saves the new SchemeId of the channel passed. // UpdateChannelScheme saves the new SchemeId of the channel passed.
UpdateChannelScheme(channel *model.Channel) (*model.Channel, *model.AppError) UpdateChannelScheme(channel *model.Channel) (*model.Channel, *model.AppError)
// UpdateProductNotices is called periodically from a scheduled worker to fetch new notices and update the cache
UpdateProductNotices() *model.AppError
// UpdateViewedProductNotices is called from the frontend to mark a set of notices as 'viewed' by user
UpdateViewedProductNotices(userId string, noticeIds []string) *model.AppError
// UpdateViewedProductNoticesForNewUser is called when new user is created to mark all current notices for this
// user as viewed in order to avoid showing them imminently on first login
UpdateViewedProductNoticesForNewUser(userId string)
// UpdateWebConnUserActivity sets the LastUserActivityAt of the hub for the given session. // UpdateWebConnUserActivity sets the LastUserActivityAt of the hub for the given session.
UpdateWebConnUserActivity(session model.Session, activityAt int64) UpdateWebConnUserActivity(session model.Session, activityAt int64)
// UploadFile uploads a single file in form of a completely constructed byte array for a channel. // UploadFile uploads a single file in form of a completely constructed byte array for a channel.
@@ -629,7 +638,6 @@ type AppIface interface {
GetPreferencesForUser(userId string) (model.Preferences, *model.AppError) GetPreferencesForUser(userId string) (model.Preferences, *model.AppError)
GetPrevPostIdFromPostList(postList *model.PostList) string GetPrevPostIdFromPostList(postList *model.PostList) string
GetPrivateChannelsForTeam(teamId string, offset int, limit int) (*model.ChannelList, *model.AppError) GetPrivateChannelsForTeam(teamId string, offset int, limit int) (*model.ChannelList, *model.AppError)
GetProductNotices(userId, teamId string, client model.NoticeClientType, clientVersion string, locale string) (model.NoticeMessages, *model.AppError)
GetProfileImage(user *model.User) ([]byte, bool, *model.AppError) GetProfileImage(user *model.User) ([]byte, bool, *model.AppError)
GetPublicChannelsByIdsForTeam(teamId string, channelIds []string) (*model.ChannelList, *model.AppError) GetPublicChannelsByIdsForTeam(teamId string, channelIds []string) (*model.ChannelList, *model.AppError)
GetPublicChannelsForTeam(teamId string, offset int, limit int) (*model.ChannelList, *model.AppError) GetPublicChannelsForTeam(teamId string, offset int, limit int) (*model.ChannelList, *model.AppError)
@@ -973,7 +981,6 @@ type AppIface interface {
UpdatePasswordSendEmail(user *model.User, newPassword, method string) *model.AppError UpdatePasswordSendEmail(user *model.User, newPassword, method string) *model.AppError
UpdatePost(post *model.Post, safeUpdate bool) (*model.Post, *model.AppError) UpdatePost(post *model.Post, safeUpdate bool) (*model.Post, *model.AppError)
UpdatePreferences(userId string, preferences model.Preferences) *model.AppError UpdatePreferences(userId string, preferences model.Preferences) *model.AppError
UpdateProductNotices() *model.AppError
UpdateRole(role *model.Role) (*model.Role, *model.AppError) UpdateRole(role *model.Role) (*model.Role, *model.AppError)
UpdateScheme(scheme *model.Scheme) (*model.Scheme, *model.AppError) UpdateScheme(scheme *model.Scheme) (*model.Scheme, *model.AppError)
UpdateSessionsIsGuest(userId string, isGuest bool) UpdateSessionsIsGuest(userId string, isGuest bool)
@@ -990,7 +997,6 @@ type AppIface interface {
UpdateUserAuth(userId string, userAuth *model.UserAuth) (*model.UserAuth, *model.AppError) UpdateUserAuth(userId string, userAuth *model.UserAuth) (*model.UserAuth, *model.AppError)
UpdateUserNotifyProps(userId string, props map[string]string) (*model.User, *model.AppError) UpdateUserNotifyProps(userId string, props map[string]string) (*model.User, *model.AppError)
UpdateUserRoles(userId string, newRoles string, sendWebSocketEvent bool) (*model.User, *model.AppError) UpdateUserRoles(userId string, newRoles string, sendWebSocketEvent bool) (*model.User, *model.AppError)
UpdateViewedProductNotices(userId string, noticeIds []string) *model.AppError
UploadData(us *model.UploadSession, rd io.Reader) (*model.FileInfo, *model.AppError) UploadData(us *model.UploadSession, rd io.Reader) (*model.FileInfo, *model.AppError)
UploadEmojiImage(id string, imageData *multipart.FileHeader) *model.AppError UploadEmojiImage(id string, imageData *multipart.FileHeader) *model.AppError
UploadMultipartFiles(teamId string, channelId string, userId string, fileHeaders []*multipart.FileHeader, clientIds []string, now time.Time) (*model.FileUploadResponse, *model.AppError) UploadMultipartFiles(teamId string, channelId string, userId string, fileHeaders []*multipart.FileHeader, clientIds []string, now time.Time) (*model.FileUploadResponse, *model.AppError)

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

@@ -15248,6 +15248,21 @@ func (a *OpenTracingAppLayer) UpdateViewedProductNotices(userId string, noticeId
return resultVar0 return resultVar0
} }
func (a *OpenTracingAppLayer) UpdateViewedProductNoticesForNewUser(userId string) {
origCtx := a.ctx
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.UpdateViewedProductNoticesForNewUser")
a.ctx = newCtx
a.app.Srv().Store.SetContext(newCtx)
defer func() {
a.app.Srv().Store.SetContext(origCtx)
a.ctx = origCtx
}()
defer span.Finish()
a.app.UpdateViewedProductNoticesForNewUser(userId)
}
func (a *OpenTracingAppLayer) UpdateWebConnUserActivity(session model.Session, activityAt int64) { func (a *OpenTracingAppLayer) UpdateWebConnUserActivity(session model.Session, activityAt int64) {
origCtx := a.ctx origCtx := a.ctx
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.UpdateWebConnUserActivity") span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.UpdateWebConnUserActivity")

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

@@ -200,6 +200,7 @@ func validateConfigEntry(conf *model.Config, path string, expectedValue interfac
return val == expectedValue return val == expectedValue
} }
// GetProductNotices is called from the frontend to fetch the product notices that are relevant to the caller
func (a *App) GetProductNotices(userId, teamId string, client model.NoticeClientType, clientVersion string, locale string) (model.NoticeMessages, *model.AppError) { func (a *App) GetProductNotices(userId, teamId string, client model.NoticeClientType, clientVersion string, locale string) (model.NoticeMessages, *model.AppError) {
isSystemAdmin := a.SessionHasPermissionTo(*a.Session(), model.PERMISSION_MANAGE_SYSTEM) isSystemAdmin := a.SessionHasPermissionTo(*a.Session(), model.PERMISSION_MANAGE_SYSTEM)
isTeamAdmin := a.SessionHasPermissionToTeam(*a.Session(), teamId, model.PERMISSION_MANAGE_TEAM) isTeamAdmin := a.SessionHasPermissionToTeam(*a.Session(), teamId, model.PERMISSION_MANAGE_TEAM)
@@ -275,6 +276,7 @@ func (a *App) GetProductNotices(userId, teamId string, client model.NoticeClient
return filteredNotices, nil return filteredNotices, nil
} }
// UpdateViewedProductNotices is called from the frontend to mark a set of notices as 'viewed' by user
func (a *App) UpdateViewedProductNotices(userId string, noticeIds []string) *model.AppError { func (a *App) UpdateViewedProductNotices(userId string, noticeIds []string) *model.AppError {
if err := a.Srv().Store.ProductNotices().View(userId, noticeIds); err != nil { if err := a.Srv().Store.ProductNotices().View(userId, noticeIds); err != nil {
return model.NewAppError("UpdateViewedProductNotices", "api.system.update_viewed_notices.failed", nil, err.Error(), http.StatusBadRequest) return model.NewAppError("UpdateViewedProductNotices", "api.system.update_viewed_notices.failed", nil, err.Error(), http.StatusBadRequest)
@@ -282,6 +284,19 @@ func (a *App) UpdateViewedProductNotices(userId string, noticeIds []string) *mod
return nil return nil
} }
// UpdateViewedProductNoticesForNewUser is called when new user is created to mark all current notices for this
// user as viewed in order to avoid showing them imminently on first login
func (a *App) UpdateViewedProductNoticesForNewUser(userId string) {
var noticeIds []string
for _, notice := range cachedNotices {
noticeIds = append(noticeIds, notice.ID)
}
if err := a.Srv().Store.ProductNotices().View(userId, noticeIds); err != nil {
mlog.Error("Cannot update product notices viewed state for user", mlog.String("userId", userId))
}
}
// UpdateProductNotices is called periodically from a scheduled worker to fetch new notices and update the cache
func (a *App) UpdateProductNotices() *model.AppError { func (a *App) UpdateProductNotices() *model.AppError {
url := *a.Srv().Config().AnnouncementSettings.NoticesURL url := *a.Srv().Config().AnnouncementSettings.NoticesURL
skip := *a.Srv().Config().AnnouncementSettings.NoticesSkipCache skip := *a.Srv().Config().AnnouncementSettings.NoticesSkipCache

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

@@ -314,6 +314,7 @@ func (a *App) createUser(user *model.User) (*model.User, *model.AppError) {
mlog.Error("Encountered error saving tutorial preference", mlog.Err(err)) mlog.Error("Encountered error saving tutorial preference", mlog.Err(err))
} }
go a.UpdateViewedProductNoticesForNewUser(ruser.Id)
ruser.Sanitize(map[string]bool{}) ruser.Sanitize(map[string]bool{})
return ruser, nil return ruser, nil
} }