feat: store last seen date for users and present in stats and user lists, closes #9007

This commit is contained in:
Torkel Ödegaard
2017-08-09 10:36:41 +02:00
parent 26ad025705
commit e8a20643d6
15 changed files with 249 additions and 84 deletions

View File

@@ -103,4 +103,8 @@ func addUserMigrations(mg *Migrator) {
{Name: "company", Type: DB_NVarchar, Length: 255, Nullable: true},
{Name: "theme", Type: DB_NVarchar, Length: 255, Nullable: true},
}))
mg.AddMigration("Add last_seen_at column to user", NewAddColumnMigration(userV2, &Column{
Name: "last_seen_at", Type: DB_DateTime, Nullable: true,
}))
}

View File

@@ -6,6 +6,7 @@ import (
"github.com/grafana/grafana/pkg/bus"
m "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/util"
)
func init() {
@@ -71,11 +72,18 @@ func GetOrgUsers(query *m.GetOrgUsersQuery) error {
sess := x.Table("org_user")
sess.Join("INNER", "user", fmt.Sprintf("org_user.user_id=%s.id", x.Dialect().Quote("user")))
sess.Where("org_user.org_id=?", query.OrgId)
sess.Cols("org_user.org_id", "org_user.user_id", "user.email", "user.login", "org_user.role")
sess.Cols("org_user.org_id", "org_user.user_id", "user.email", "user.login", "org_user.role", "user.last_seen_at")
sess.Asc("user.email", "user.login")
err := sess.Find(&query.Result)
return err
if err := sess.Find(&query.Result); err != nil {
return err
}
for _, user := range query.Result {
user.LastSeenAtAge = util.GetAgeString(user.LastSeenAt)
}
return nil
}
func RemoveOrgUser(cmd *m.RemoveOrgUserCommand) error {

View File

@@ -53,7 +53,7 @@ func EnsureAdminUser() {
return
}
if statsQuery.Result.UserCount > 0 {
if statsQuery.Result.Users > 0 {
return
}

View File

@@ -1,6 +1,8 @@
package sqlstore
import (
"time"
"github.com/grafana/grafana/pkg/bus"
m "github.com/grafana/grafana/pkg/models"
)
@@ -11,6 +13,8 @@ func init() {
bus.AddHandler("sql", GetAdminStats)
}
var activeUserTimeLimit time.Duration = time.Hour * 24 * 14
func GetDataSourceStats(query *m.GetDataSourceStatsQuery) error {
var rawSql = `SELECT COUNT(*) as count, type FROM data_source GROUP BY type`
query.Result = make([]*m.DataSourceStats, 0)
@@ -27,27 +31,35 @@ func GetSystemStats(query *m.GetSystemStatsQuery) error {
(
SELECT COUNT(*)
FROM ` + dialect.Quote("user") + `
) AS user_count,
) AS users,
(
SELECT COUNT(*)
FROM ` + dialect.Quote("org") + `
) AS org_count,
) AS orgs,
(
SELECT COUNT(*)
FROM ` + dialect.Quote("dashboard") + `
) AS dashboard_count,
) AS dashboards,
(
SELECT COUNT(*)
FROM ` + dialect.Quote("data_source") + `
) AS datasources,
(
SELECT COUNT(*)
FROM ` + dialect.Quote("playlist") + `
) AS playlist_count,
) AS playlists,
(
SELECT COUNT(*)
FROM ` + dialect.Quote("alert") + `
) AS alert_count
) AS alerts,
(
SELECT COUNT(*) FROM ` + dialect.Quote("user") + ` where last_seen_at > ?
) as active_users
`
activeUserDeadlineDate := time.Now().Add(-activeUserTimeLimit)
var stats m.SystemStats
_, err := x.Sql(rawSql).Get(&stats)
_, err := x.Sql(rawSql, activeUserDeadlineDate).Get(&stats)
if err != nil {
return err
}
@@ -61,43 +73,48 @@ func GetAdminStats(query *m.GetAdminStatsQuery) error {
(
SELECT COUNT(*)
FROM ` + dialect.Quote("user") + `
) AS user_count,
) AS users,
(
SELECT COUNT(*)
FROM ` + dialect.Quote("org") + `
) AS org_count,
) AS orgs,
(
SELECT COUNT(*)
FROM ` + dialect.Quote("dashboard") + `
) AS dashboard_count,
) AS dashboards,
(
SELECT COUNT(*)
FROM ` + dialect.Quote("dashboard_snapshot") + `
) AS db_snapshot_count,
) AS snapshots,
(
SELECT COUNT( DISTINCT ( ` + dialect.Quote("term") + ` ))
FROM ` + dialect.Quote("dashboard_tag") + `
) AS db_tag_count,
) AS tags,
(
SELECT COUNT(*)
FROM ` + dialect.Quote("data_source") + `
) AS data_source_count,
) AS datasources,
(
SELECT COUNT(*)
FROM ` + dialect.Quote("playlist") + `
) AS playlist_count,
) AS playlists,
(
SELECT COUNT(DISTINCT ` + dialect.Quote("dashboard_id") + ` )
FROM ` + dialect.Quote("star") + `
) AS starred_db_count,
SELECT COUNT(*) FROM ` + dialect.Quote("star") + `
) AS stars,
(
SELECT COUNT(*)
FROM ` + dialect.Quote("alert") + `
) AS alert_count
) AS alerts,
(
SELECT COUNT(*)
from ` + dialect.Quote("user") + ` where last_seen_at > ?
) as active_users
`
activeUserDeadlineDate := time.Now().Add(-activeUserTimeLimit)
var stats m.AdminStats
_, err := x.Sql(rawSql).Get(&stats)
_, err := x.Sql(rawSql, activeUserDeadlineDate).Get(&stats)
if err != nil {
return err
}

View File

@@ -22,6 +22,7 @@ func init() {
bus.AddHandler("sql", GetUserByLogin)
bus.AddHandler("sql", GetUserByEmail)
bus.AddHandler("sql", SetUsingOrg)
bus.AddHandler("sql", UpdateUserLastSeenAt)
bus.AddHandler("sql", GetUserProfile)
bus.AddHandler("sql", GetSignedInUser)
bus.AddHandler("sql", SearchUsers)
@@ -260,6 +261,24 @@ func ChangeUserPassword(cmd *m.ChangeUserPasswordCommand) error {
})
}
func UpdateUserLastSeenAt(cmd *m.UpdateUserLastSeenAtCommand) error {
return inTransaction(func(sess *DBSession) error {
if cmd.UserId <= 0 {
}
user := m.User{
Id: cmd.UserId,
LastSeenAt: time.Now(),
}
if _, err := sess.Id(cmd.UserId).Update(&user); err != nil {
return err
}
return nil
})
}
func SetUsingOrg(cmd *m.SetUsingOrgCommand) error {
getOrgsForUserCmd := &m.GetUserOrgListQuery{UserId: cmd.UserId}
GetUserOrgList(getOrgsForUserCmd)
@@ -324,15 +343,16 @@ func GetSignedInUser(query *m.GetSignedInUserQuery) error {
}
var rawSql = `SELECT
u.id as user_id,
u.is_admin as is_grafana_admin,
u.email as email,
u.login as login,
u.name as name,
u.help_flags1 as help_flags1,
org.name as org_name,
org_user.role as org_role,
org.id as org_id
u.id as user_id,
u.is_admin as is_grafana_admin,
u.email as email,
u.login as login,
u.name as name,
u.help_flags1 as help_flags1,
u.last_seen_at as last_seen_at,
org.name as org_name,
org_user.role as org_role,
org.id as org_id
FROM ` + dialect.Quote("user") + ` as u
LEFT OUTER JOIN org_user on org_user.org_id = ` + orgId + ` and org_user.user_id = u.id
LEFT OUTER JOIN org on org.id = org_user.org_id `
@@ -367,27 +387,49 @@ func SearchUsers(query *m.SearchUsersQuery) error {
query.Result = m.SearchUserQueryResult{
Users: make([]*m.UserSearchHitDTO, 0),
}
queryWithWildcards := "%" + query.Query + "%"
whereConditions := make([]string, 0)
whereParams := make([]interface{}, 0)
sess := x.Table("user")
if query.Query != "" {
sess.Where("email LIKE ? OR name LIKE ? OR login like ?", queryWithWildcards, queryWithWildcards, queryWithWildcards)
if query.OrgId > 0 {
whereConditions = append(whereConditions, "org_id = ?")
whereParams = append(whereParams, query.OrgId)
}
if query.Query != "" {
whereConditions = append(whereConditions, "(email LIKE ? OR name LIKE ? OR login like ?)")
whereParams = append(whereParams, queryWithWildcards, queryWithWildcards, queryWithWildcards)
}
if len(whereConditions) > 0 {
sess.Where(strings.Join(whereConditions, " AND "), whereParams...)
}
offset := query.Limit * (query.Page - 1)
sess.Limit(query.Limit, offset)
sess.Cols("id", "email", "name", "login", "is_admin")
sess.Cols("id", "email", "name", "login", "is_admin", "last_seen_at")
if err := sess.Find(&query.Result.Users); err != nil {
return err
}
// get total
user := m.User{}
countSess := x.Table("user")
if query.Query != "" {
countSess.Where("email LIKE ? OR name LIKE ? OR login like ?", queryWithWildcards, queryWithWildcards, queryWithWildcards)
if len(whereConditions) > 0 {
countSess.Where(strings.Join(whereConditions, " AND "), whereParams...)
}
count, err := countSess.Count(&user)
query.Result.TotalCount = count
for _, user := range query.Result.Users {
user.LastSeenAtAge = util.GetAgeString(user.LastSeenAt)
}
return err
}