[MM-55014][MM-55015] Add last login timestamp for users, add materialized view and refresh job to keep track of post stats for Postgres (#25152)
* [MM-55014][MM-55015] Add last login timestamp for users, add materialized view and refresh job for Postgres * Check fixes * Fix type issue * Add verification that lastlogin was updated * PR feedback * Morge'd * Morge'd again * Merge'd * Update admin setting strings * WIP * PR feedback * Oops * Fix i18n --------- Co-authored-by: Mattermost Build <build@mattermost.com>
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
41c08a3715
Коммит
1bd72bdb99
@@ -54,7 +54,7 @@ func newSqlUserStore(sqlStore *SqlStore, metrics einterfaces.MetricsInterface) s
|
||||
// note: we are providing field names explicitly here to maintain order of columns (needed when using raw queries)
|
||||
us.usersQuery = us.getQueryBuilder().
|
||||
Select("u.Id", "u.CreateAt", "u.UpdateAt", "u.DeleteAt", "u.Username", "u.Password", "u.AuthData", "u.AuthService", "u.Email", "u.EmailVerified", "u.Nickname", "u.FirstName", "u.LastName", "u.Position", "u.Roles", "u.AllowMarketing", "u.Props", "u.NotifyProps", "u.LastPasswordUpdate", "u.LastPictureUpdate", "u.FailedAttempts", "u.Locale", "u.Timezone", "u.MfaActive", "u.MfaSecret",
|
||||
"b.UserId IS NOT NULL AS IsBot", "COALESCE(b.Description, '') AS BotDescription", "COALESCE(b.LastIconUpdate, 0) AS BotLastIconUpdate", "u.RemoteId").
|
||||
"b.UserId IS NOT NULL AS IsBot", "COALESCE(b.Description, '') AS BotDescription", "COALESCE(b.LastIconUpdate, 0) AS BotLastIconUpdate", "u.RemoteId", "u.LastLogin").
|
||||
From("Users u").
|
||||
LeftJoin("Bots b ON ( b.UserId = u.Id )")
|
||||
|
||||
@@ -193,6 +193,7 @@ func (us SqlUserStore) Update(user *model.User, trustedUpdateData bool) (*model.
|
||||
user.FailedAttempts = oldUser.FailedAttempts
|
||||
user.MfaSecret = oldUser.MfaSecret
|
||||
user.MfaActive = oldUser.MfaActive
|
||||
user.LastLogin = oldUser.LastLogin
|
||||
|
||||
if !trustedUpdateData {
|
||||
user.Roles = oldUser.Roles
|
||||
@@ -222,7 +223,7 @@ func (us SqlUserStore) Update(user *model.User, trustedUpdateData bool) (*model.
|
||||
AllowMarketing=:AllowMarketing, Props=:Props, NotifyProps=:NotifyProps,
|
||||
LastPasswordUpdate=:LastPasswordUpdate, LastPictureUpdate=:LastPictureUpdate,
|
||||
FailedAttempts=:FailedAttempts,Locale=:Locale, Timezone=:Timezone, MfaActive=:MfaActive,
|
||||
MfaSecret=:MfaSecret, RemoteId=:RemoteId
|
||||
MfaSecret=:MfaSecret, RemoteId=:RemoteId, LastLogin=:LastLogin
|
||||
WHERE Id=:Id`
|
||||
|
||||
user.Props = wrapBinaryParamStringMap(us.IsBinaryParamEnabled(), user.Props)
|
||||
@@ -355,6 +356,27 @@ func (us SqlUserStore) UpdateAuthData(userId string, service string, authData *s
|
||||
return userId, nil
|
||||
}
|
||||
|
||||
func (us SqlUserStore) UpdateLastLogin(userId string, lastLogin int64) error {
|
||||
updateAt := model.GetMillis()
|
||||
|
||||
updateQuery := us.getQueryBuilder().
|
||||
Update("Users").
|
||||
Set("LastLogin", lastLogin).
|
||||
Set("UpdateAt", updateAt).
|
||||
Where(sq.Eq{"Id": userId})
|
||||
|
||||
queryString, args, err := updateQuery.ToSql()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "update_last_login_tosql")
|
||||
}
|
||||
|
||||
if _, err := us.GetMasterX().Exec(queryString, args...); err != nil {
|
||||
return errors.Wrapf(err, "failed to update User with userId=%s", userId)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ResetAuthDataToEmailForUsers resets the AuthData of users whose AuthService
|
||||
// is |service| to their Email. If userIDs is non-empty, only the users whose
|
||||
// IDs are in userIDs will be affected. If dryRun is true, only the number
|
||||
@@ -449,7 +471,7 @@ func (us SqlUserStore) Get(ctx context.Context, id string) (*model.User, error)
|
||||
&user.Nickname, &user.FirstName, &user.LastName, &user.Position, &user.Roles,
|
||||
&user.AllowMarketing, &props, ¬ifyProps, &user.LastPasswordUpdate, &user.LastPictureUpdate,
|
||||
&user.FailedAttempts, &user.Locale, &timezone, &user.MfaActive, &user.MfaSecret,
|
||||
&user.IsBot, &user.BotDescription, &user.BotLastIconUpdate, &user.RemoteId)
|
||||
&user.IsBot, &user.BotDescription, &user.BotLastIconUpdate, &user.RemoteId, &user.LastLogin)
|
||||
if err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
return nil, store.NewErrNotFound("User", id)
|
||||
@@ -851,7 +873,7 @@ func (us SqlUserStore) GetAllProfilesInChannel(ctx context.Context, channelID st
|
||||
for rows.Next() {
|
||||
var user model.User
|
||||
var props, notifyProps, timezone []byte
|
||||
if err = rows.Scan(&user.Id, &user.CreateAt, &user.UpdateAt, &user.DeleteAt, &user.Username, &user.Password, &user.AuthData, &user.AuthService, &user.Email, &user.EmailVerified, &user.Nickname, &user.FirstName, &user.LastName, &user.Position, &user.Roles, &user.AllowMarketing, &props, ¬ifyProps, &user.LastPasswordUpdate, &user.LastPictureUpdate, &user.FailedAttempts, &user.Locale, &timezone, &user.MfaActive, &user.MfaSecret, &user.IsBot, &user.BotDescription, &user.BotLastIconUpdate, &user.RemoteId); err != nil {
|
||||
if err = rows.Scan(&user.Id, &user.CreateAt, &user.UpdateAt, &user.DeleteAt, &user.Username, &user.Password, &user.AuthData, &user.AuthService, &user.Email, &user.EmailVerified, &user.Nickname, &user.FirstName, &user.LastName, &user.Position, &user.Roles, &user.AllowMarketing, &props, ¬ifyProps, &user.LastPasswordUpdate, &user.LastPictureUpdate, &user.FailedAttempts, &user.Locale, &timezone, &user.MfaActive, &user.MfaSecret, &user.IsBot, &user.BotDescription, &user.BotLastIconUpdate, &user.RemoteId, &user.LastLogin); err != nil {
|
||||
return nil, errors.Wrap(err, "failed to scan values from rows into User entity")
|
||||
}
|
||||
if err = json.Unmarshal(props, &user.Props); err != nil {
|
||||
@@ -2231,3 +2253,15 @@ func (us SqlUserStore) GetUsersWithInvalidEmails(page int, perPage int, restrict
|
||||
|
||||
return users, nil
|
||||
}
|
||||
|
||||
func (us SqlUserStore) RefreshPostStatsForUsers() error {
|
||||
if us.DriverName() == model.DatabaseDriverPostgres {
|
||||
if _, err := us.GetReplicaX().Exec("REFRESH MATERIALIZED VIEW poststats"); err != nil {
|
||||
return errors.Wrap(err, "users_refresh_post_stats_exec")
|
||||
}
|
||||
} else {
|
||||
mlog.Debug("Skipped running refresh post stats, only available on Postgres")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
Ссылка в новой задаче
Block a user