2022-06-28 07:32:25 -05:00
package userimpl
import (
"context"
2022-07-19 09:01:05 -05:00
"fmt"
2022-10-04 05:17:55 -05:00
"strconv"
2022-09-28 06:18:19 -05:00
"strings"
2022-09-28 09:17:09 -05:00
"time"
2022-06-28 07:32:25 -05:00
"github.com/grafana/grafana/pkg/events"
2022-10-19 08:02:15 -05:00
"github.com/grafana/grafana/pkg/infra/db"
2022-09-27 06:58:49 -05:00
"github.com/grafana/grafana/pkg/infra/log"
2022-10-05 02:34:36 -05:00
"github.com/grafana/grafana/pkg/services/accesscontrol"
2022-07-19 09:01:05 -05:00
"github.com/grafana/grafana/pkg/services/sqlstore/migrator"
2022-06-28 07:32:25 -05:00
"github.com/grafana/grafana/pkg/services/user"
2022-09-27 06:58:49 -05:00
"github.com/grafana/grafana/pkg/setting"
2022-10-05 02:34:36 -05:00
"github.com/grafana/grafana/pkg/util"
2022-06-28 07:32:25 -05:00
)
type store interface {
Insert ( context . Context , * user . User ) ( int64 , error )
2022-08-02 09:58:05 -05:00
GetByID ( context . Context , int64 ) ( * user . User , error )
2024-07-26 09:09:08 -05:00
GetByUID ( ctx context . Context , orgId int64 , uid string ) ( * user . User , error )
2024-04-29 01:53:05 -05:00
GetByLogin ( context . Context , * user . GetUserByLoginQuery ) ( * user . User , error )
GetByEmail ( context . Context , * user . GetUserByEmailQuery ) ( * user . User , error )
2022-07-19 09:01:05 -05:00
Delete ( context . Context , int64 ) error
2024-03-22 10:45:18 -05:00
LoginConflict ( ctx context . Context , login , email string ) error
2022-09-28 09:17:09 -05:00
Update ( context . Context , * user . UpdateUserCommand ) error
UpdateLastSeenAt ( context . Context , * user . UpdateUserLastSeenAtCommand ) error
2022-10-04 05:17:55 -05:00
GetSignedInUser ( context . Context , * user . GetSignedInUserQuery ) ( * user . SignedInUser , error )
2022-10-04 07:14:32 -05:00
GetProfile ( context . Context , * user . GetUserProfileQuery ) ( * user . UserProfileDTO , error )
2022-10-05 02:34:36 -05:00
BatchDisableUsers ( context . Context , * user . BatchDisableUsersCommand ) error
Search ( context . Context , * user . SearchUsersQuery ) ( * user . SearchUserQueryResult , error )
2022-11-14 13:08:10 -06:00
Count ( ctx context . Context ) ( int64 , error )
2023-08-16 03:56:47 -05:00
CountUserAccountsWithEmptyRole ( ctx context . Context ) ( int64 , error )
2022-06-28 07:32:25 -05:00
}
type sqlStore struct {
2022-07-19 09:01:05 -05:00
db db . DB
dialect migrator . Dialect
2022-09-27 06:58:49 -05:00
logger log . Logger
cfg * setting . Cfg
}
func ProvideStore ( db db . DB , cfg * setting . Cfg ) sqlStore {
return sqlStore {
db : db ,
dialect : db . GetDialect ( ) ,
cfg : cfg ,
logger : log . New ( "user.store" ) ,
}
2022-06-28 07:32:25 -05:00
}
func ( ss * sqlStore ) Insert ( ctx context . Context , cmd * user . User ) ( int64 , error ) {
var err error
2024-06-25 08:19:49 -05:00
err = ss . db . WithDbSession ( ctx , func ( sess * db . Session ) error {
2022-06-28 07:32:25 -05:00
sess . UseBool ( "is_admin" )
2024-02-01 20:14:10 -06:00
if cmd . UID == "" {
cmd . UID = util . GenerateShortUID ( )
}
2022-06-28 07:32:25 -05:00
2022-12-07 10:03:22 -06:00
if _ , err = sess . Insert ( cmd ) ; err != nil {
2022-06-28 07:32:25 -05:00
return err
}
sess . PublishAfterCommit ( & events . UserCreated {
Timestamp : cmd . Created ,
Id : cmd . ID ,
Name : cmd . Name ,
Login : cmd . Login ,
Email : cmd . Email ,
} )
return nil
} )
if err != nil {
return 0 , err
}
2022-12-07 11:33:40 -06:00
2022-12-07 10:03:22 -06:00
return cmd . ID , nil
2022-06-28 07:32:25 -05:00
}
2022-07-19 09:01:05 -05:00
func ( ss * sqlStore ) Delete ( ctx context . Context , userID int64 ) error {
2022-10-19 08:02:15 -05:00
err := ss . db . WithDbSession ( ctx , func ( sess * db . Session ) error {
2022-07-19 09:01:05 -05:00
var rawSQL = "DELETE FROM " + ss . dialect . Quote ( "user" ) + " WHERE id = ?"
_ , err := sess . Exec ( rawSQL , userID )
return err
} )
if err != nil {
return err
}
return nil
}
2022-08-02 09:58:05 -05:00
func ( ss * sqlStore ) GetByID ( ctx context . Context , userID int64 ) ( * user . User , error ) {
var usr user . User
2022-10-19 08:02:15 -05:00
err := ss . db . WithDbSession ( ctx , func ( sess * db . Session ) error {
2022-08-02 09:58:05 -05:00
has , err := sess . ID ( & userID ) .
Where ( ss . notServiceAccountFilter ( ) ) .
Get ( & usr )
if err != nil {
return err
} else if ! has {
return user . ErrUserNotFound
}
return nil
} )
return & usr , err
}
2024-07-26 09:09:08 -05:00
func ( ss * sqlStore ) GetByUID ( ctx context . Context , orgId int64 , uid string ) ( * user . User , error ) {
var usr user . User
err := ss . db . WithDbSession ( ctx , func ( sess * db . Session ) error {
has , err := sess . Table ( "user" ) .
Where ( "org_id = ? AND uid = ?" , orgId , uid ) .
Get ( & usr )
if err != nil {
return err
} else if ! has {
return user . ErrUserNotFound
}
return nil
} )
return & usr , err
}
2022-07-19 09:01:05 -05:00
func ( ss * sqlStore ) notServiceAccountFilter ( ) string {
return fmt . Sprintf ( "%s.is_service_account = %s" ,
ss . dialect . Quote ( "user" ) ,
ss . dialect . BooleanStr ( false ) )
}
2022-08-02 09:58:05 -05:00
2022-09-28 06:18:19 -05:00
func ( ss * sqlStore ) GetByLogin ( ctx context . Context , query * user . GetUserByLoginQuery ) ( * user . User , error ) {
2024-04-25 11:31:17 -05:00
// enforcement of lowercase due to forcement of caseinsensitive login
query . LoginOrEmail = strings . ToLower ( query . LoginOrEmail )
2022-09-28 06:18:19 -05:00
usr := & user . User { }
2022-10-19 08:02:15 -05:00
err := ss . db . WithDbSession ( ctx , func ( sess * db . Session ) error {
2022-09-28 06:18:19 -05:00
if query . LoginOrEmail == "" {
return user . ErrUserNotFound
}
2022-10-21 08:21:21 -05:00
var where string
var has bool
var err error
2022-09-28 06:18:19 -05:00
2022-10-21 08:21:21 -05:00
// Since username can be an email address, attempt login with email address
// first if the login field has the "@" symbol.
if strings . Contains ( query . LoginOrEmail , "@" ) {
2024-04-25 11:31:17 -05:00
where = "email=?"
2022-10-21 08:21:21 -05:00
has , err = sess . Where ( ss . notServiceAccountFilter ( ) ) . Where ( where , query . LoginOrEmail ) . Get ( usr )
if err != nil {
return err
}
}
// Look for the login field instead of email
if ! has {
2024-04-25 11:31:17 -05:00
where = "login=?"
2022-09-28 06:18:19 -05:00
has , err = sess . Where ( ss . notServiceAccountFilter ( ) ) . Where ( where , query . LoginOrEmail ) . Get ( usr )
}
if err != nil {
return err
} else if ! has {
return user . ErrUserNotFound
}
return nil
} )
2022-10-21 08:21:21 -05:00
2023-01-10 08:08:52 -06:00
if err != nil {
return nil , err
}
return usr , nil
2022-09-28 06:18:19 -05:00
}
func ( ss * sqlStore ) GetByEmail ( ctx context . Context , query * user . GetUserByEmailQuery ) ( * user . User , error ) {
2024-04-25 11:31:17 -05:00
// enforcement of lowercase due to forcement of caseinsensitive login
query . Email = strings . ToLower ( query . Email )
2022-09-28 06:18:19 -05:00
usr := & user . User { }
2022-10-19 08:02:15 -05:00
err := ss . db . WithDbSession ( ctx , func ( sess * db . Session ) error {
2022-09-28 06:18:19 -05:00
if query . Email == "" {
return user . ErrUserNotFound
}
2024-04-25 11:31:17 -05:00
where := "email=?"
2022-09-28 06:18:19 -05:00
has , err := sess . Where ( ss . notServiceAccountFilter ( ) ) . Where ( where , query . Email ) . Get ( usr )
if err != nil {
return err
} else if ! has {
return user . ErrUserNotFound
}
return nil
} )
if err != nil {
return nil , err
}
return usr , nil
}
2022-12-07 10:03:22 -06:00
// LoginConflict returns an error if the provided email or login are already
2024-06-12 02:19:06 -05:00
// associated with a user.
2024-03-22 10:45:18 -05:00
func ( ss * sqlStore ) LoginConflict ( ctx context . Context , login , email string ) error {
2024-06-12 02:19:06 -05:00
// enforcement of lowercase due to forcement of caseinsensitive login
login = strings . ToLower ( login )
email = strings . ToLower ( email )
2022-12-07 10:03:22 -06:00
err := ss . db . WithDbSession ( ctx , func ( sess * db . Session ) error {
2024-04-29 06:24:14 -05:00
where := "email=? OR login=?"
2022-12-07 10:03:22 -06:00
2024-04-29 06:24:14 -05:00
exists , err := sess . Where ( where , email , login ) . Get ( & user . User { } )
if err != nil {
return err
}
if exists {
return user . ErrUserAlreadyExists
}
2022-12-07 10:03:22 -06:00
2024-04-29 06:24:14 -05:00
return nil
} )
return err
2022-12-07 10:03:22 -06:00
}
2022-09-28 09:17:09 -05:00
func ( ss * sqlStore ) Update ( ctx context . Context , cmd * user . UpdateUserCommand ) error {
2024-04-25 11:31:17 -05:00
// enforcement of lowercase due to forcement of caseinsensitive login
cmd . Login = strings . ToLower ( cmd . Login )
cmd . Email = strings . ToLower ( cmd . Email )
2022-10-19 08:02:15 -05:00
return ss . db . WithTransactionalDbSession ( ctx , func ( sess * db . Session ) error {
2024-04-29 01:53:05 -05:00
usr := user . User {
2022-09-28 09:17:09 -05:00
Name : cmd . Name ,
2024-04-29 01:53:05 -05:00
Theme : cmd . Theme ,
2024-04-17 08:24:36 -05:00
Email : strings . ToLower ( cmd . Email ) ,
Login : strings . ToLower ( cmd . Login ) ,
2022-09-28 09:17:09 -05:00
Updated : time . Now ( ) ,
}
2024-03-28 10:05:33 -05:00
q := sess . ID ( cmd . UserID ) . Where ( ss . notServiceAccountFilter ( ) )
2024-04-29 01:53:05 -05:00
setOptional ( cmd . OrgID , func ( v int64 ) { usr . OrgID = v } )
setOptional ( cmd . Password , func ( v user . Password ) { usr . Password = v } )
setOptional ( cmd . IsDisabled , func ( v bool ) {
q = q . UseBool ( "is_disabled" )
usr . IsDisabled = v
} )
setOptional ( cmd . EmailVerified , func ( v bool ) {
q = q . UseBool ( "email_verified" )
usr . EmailVerified = v
} )
setOptional ( cmd . IsGrafanaAdmin , func ( v bool ) {
q = q . UseBool ( "is_admin" )
usr . IsAdmin = v
} )
setOptional ( cmd . HelpFlags1 , func ( v user . HelpFlags1 ) { usr . HelpFlags1 = * cmd . HelpFlags1 } )
2024-04-16 09:33:50 -05:00
2024-04-29 01:53:05 -05:00
if _ , err := q . Update ( & usr ) ; err != nil {
2022-09-28 09:17:09 -05:00
return err
}
2024-04-16 09:33:50 -05:00
if cmd . IsGrafanaAdmin != nil && ! * cmd . IsGrafanaAdmin {
// validate that after update there is at least one server admin
2024-04-29 01:53:05 -05:00
if err := validateOneAdminLeft ( sess ) ; err != nil {
2024-04-16 09:33:50 -05:00
return err
}
}
2022-09-28 09:17:09 -05:00
sess . PublishAfterCommit ( & events . UserUpdated {
2024-04-29 01:53:05 -05:00
Timestamp : usr . Created ,
Id : usr . ID ,
Name : usr . Name ,
Login : usr . Login ,
Email : usr . Email ,
2022-09-28 09:17:09 -05:00
} )
return nil
} )
}
func ( ss * sqlStore ) UpdateLastSeenAt ( ctx context . Context , cmd * user . UpdateUserLastSeenAtCommand ) error {
2023-08-03 01:26:02 -05:00
if cmd . UserID <= 0 {
return user . ErrUpdateInvalidID
}
2024-05-29 10:13:04 -05:00
return ss . db . WithDbSession ( ctx , func ( sess * db . Session ) error {
2022-09-28 09:17:09 -05:00
user := user . User {
ID : cmd . UserID ,
LastSeenAt : time . Now ( ) ,
}
_ , err := sess . ID ( cmd . UserID ) . Update ( & user )
return err
} )
}
2022-10-04 05:17:55 -05:00
func ( ss * sqlStore ) GetSignedInUser ( ctx context . Context , query * user . GetSignedInUserQuery ) ( * user . SignedInUser , error ) {
var signedInUser user . SignedInUser
2022-10-19 08:02:15 -05:00
err := ss . db . WithDbSession ( ctx , func ( dbSess * db . Session ) error {
2022-10-04 05:17:55 -05:00
orgId := "u.org_id"
if query . OrgID > 0 {
orgId = strconv . FormatInt ( query . OrgID , 10 )
}
var rawSQL = ` SELECT
u . id as user_id ,
2024-02-01 20:14:10 -06:00
u . uid as user_uid ,
2022-10-04 05:17:55 -05:00
u . is_admin as is_grafana_admin ,
u . email as email ,
2024-04-05 05:05:46 -05:00
u . email_verified as email_verified ,
2022-10-04 05:17:55 -05:00
u . login as login ,
u . name as name ,
u . is_disabled as is_disabled ,
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 ,
2022-11-04 07:39:54 -05:00
org . id as org_id ,
u . is_service_account as is_service_account
2022-10-04 05:17:55 -05:00
FROM ` + ss.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 `
sess := dbSess . Table ( "user" )
sess = sess . Context ( ctx )
switch {
case query . UserID > 0 :
sess . SQL ( rawSQL + "WHERE u.id=?" , query . UserID )
case query . Login != "" :
2024-03-22 10:45:18 -05:00
sess . SQL ( rawSQL + "WHERE LOWER(u.login)=LOWER(?)" , query . Login )
2022-10-04 05:17:55 -05:00
case query . Email != "" :
2024-03-22 10:45:18 -05:00
sess . SQL ( rawSQL + "WHERE LOWER(u.email)=LOWER(?)" , query . Email )
2023-08-03 01:26:02 -05:00
default :
return user . ErrNoUniqueID
2022-10-04 05:17:55 -05:00
}
has , err := sess . Get ( & signedInUser )
if err != nil {
return err
} else if ! has {
return user . ErrUserNotFound
}
if signedInUser . OrgRole == "" {
signedInUser . OrgID = - 1
signedInUser . OrgName = "Org missing"
}
return nil
} )
return & signedInUser , err
}
2022-10-04 07:14:32 -05:00
func ( ss * sqlStore ) GetProfile ( ctx context . Context , query * user . GetUserProfileQuery ) ( * user . UserProfileDTO , error ) {
var usr user . User
var userProfile user . UserProfileDTO
2022-10-19 08:02:15 -05:00
err := ss . db . WithDbSession ( ctx , func ( sess * db . Session ) error {
2022-10-04 07:14:32 -05:00
has , err := sess . ID ( query . UserID ) . Where ( ss . notServiceAccountFilter ( ) ) . Get ( & usr )
if err != nil {
return err
} else if ! has {
return user . ErrUserNotFound
}
userProfile = user . UserProfileDTO {
ID : usr . ID ,
2024-02-01 20:14:10 -06:00
UID : usr . UID ,
2022-10-04 07:14:32 -05:00
Name : usr . Name ,
Email : usr . Email ,
Login : usr . Login ,
Theme : usr . Theme ,
IsGrafanaAdmin : usr . IsAdmin ,
IsDisabled : usr . IsDisabled ,
OrgID : usr . OrgID ,
UpdatedAt : usr . Updated ,
CreatedAt : usr . Created ,
}
return err
} )
return & userProfile , err
}
2022-11-14 13:08:10 -06:00
func ( ss * sqlStore ) Count ( ctx context . Context ) ( int64 , error ) {
type result struct {
Count int64
}
r := result { }
2022-12-07 10:03:22 -06:00
err := ss . db . WithDbSession ( ctx , func ( sess * db . Session ) error {
2022-11-14 13:08:10 -06:00
rawSQL := fmt . Sprintf ( "SELECT COUNT(*) as count from %s WHERE is_service_account=%s" , ss . db . GetDialect ( ) . Quote ( "user" ) , ss . db . GetDialect ( ) . BooleanStr ( false ) )
if _ , err := sess . SQL ( rawSQL ) . Get ( & r ) ; err != nil {
return err
}
return nil
} )
return r . Count , err
}
2023-08-16 03:56:47 -05:00
func ( ss * sqlStore ) CountUserAccountsWithEmptyRole ( ctx context . Context ) ( int64 , error ) {
sb := & db . SQLBuilder { }
sb . Write ( "SELECT " )
sb . Write ( ` (SELECT COUNT (*) from ` + ss . dialect . Quote ( "org_user" ) + ` AS ou ` +
` LEFT JOIN ` + ss . dialect . Quote ( "user" ) + ` AS u ON u.id = ou.user_id ` +
` WHERE ou.role =? ` +
` AND u.is_service_account = ` + ss . dialect . BooleanStr ( false ) + ` ` +
` AND u.is_disabled = ` + ss . dialect . BooleanStr ( false ) + ` ) AS user_accounts_with_no_role ` )
sb . AddParams ( "None" )
var countStats int64
if err := ss . db . WithDbSession ( ctx , func ( sess * db . Session ) error {
_ , err := sess . SQL ( sb . GetSQLString ( ) , sb . GetParams ( ) ... ) . Get ( & countStats )
return err
} ) ; err != nil {
return - 1 , err
}
return countStats , nil
}
2022-10-04 07:14:32 -05:00
// validateOneAdminLeft validate that there is an admin user left
2024-04-29 01:53:05 -05:00
func validateOneAdminLeft ( sess * db . Session ) error {
2022-10-04 07:14:32 -05:00
count , err := sess . Where ( "is_admin=?" , true ) . Count ( & user . User { } )
if err != nil {
return err
}
if count == 0 {
return user . ErrLastGrafanaAdmin
}
return nil
}
2022-10-05 02:34:36 -05:00
func ( ss * sqlStore ) BatchDisableUsers ( ctx context . Context , cmd * user . BatchDisableUsersCommand ) error {
2024-06-25 08:19:49 -05:00
return ss . db . WithDbSession ( ctx , func ( sess * db . Session ) error {
2022-10-05 02:34:36 -05:00
userIds := cmd . UserIDs
if len ( userIds ) == 0 {
return nil
}
user_id_params := strings . Repeat ( ",?" , len ( userIds ) - 1 )
disableSQL := "UPDATE " + ss . dialect . Quote ( "user" ) + " SET is_disabled=? WHERE Id IN (?" + user_id_params + ")"
2023-08-30 10:46:47 -05:00
disableParams := [ ] any { disableSQL , cmd . IsDisabled }
2022-10-05 02:34:36 -05:00
for _ , v := range userIds {
disableParams = append ( disableParams , v )
}
_ , err := sess . Where ( ss . notServiceAccountFilter ( ) ) . Exec ( disableParams ... )
return err
} )
}
func ( ss * sqlStore ) Search ( ctx context . Context , query * user . SearchUsersQuery ) ( * user . SearchUserQueryResult , error ) {
result := user . SearchUserQueryResult {
Users : make ( [ ] * user . UserSearchHitDTO , 0 ) ,
}
2022-10-19 08:02:15 -05:00
err := ss . db . WithDbSession ( ctx , func ( dbSess * db . Session ) error {
2022-10-05 02:34:36 -05:00
queryWithWildcards := "%" + query . Query + "%"
whereConditions := make ( [ ] string , 0 )
2023-08-30 10:46:47 -05:00
whereParams := make ( [ ] any , 0 )
2022-10-05 02:34:36 -05:00
sess := dbSess . Table ( "user" ) . Alias ( "u" )
whereConditions = append ( whereConditions , "u.is_service_account = ?" )
whereParams = append ( whereParams , ss . dialect . BooleanStr ( false ) )
// Join with only most recent auth module
joinCondition := ` (
SELECT id from user_auth
WHERE user_auth . user_id = u . id
ORDER BY user_auth . created DESC `
joinCondition = "user_auth.id=" + joinCondition + ss . dialect . Limit ( 1 ) + ")"
sess . Join ( "LEFT" , "user_auth" , joinCondition )
if query . OrgID > 0 {
whereConditions = append ( whereConditions , "org_id = ?" )
whereParams = append ( whereParams , query . OrgID )
}
// user only sees the users for which it has read permissions
2023-08-25 08:19:58 -05:00
acFilter , err := accesscontrol . Filter ( query . SignedInUser , "u.id" , "global.users:id:" , accesscontrol . ActionUsersRead )
if err != nil {
return err
2022-10-05 02:34:36 -05:00
}
2023-08-25 08:19:58 -05:00
whereConditions = append ( whereConditions , acFilter . Where )
whereParams = append ( whereParams , acFilter . Args ... )
2022-10-05 02:34:36 -05:00
if query . Query != "" {
whereConditions = append ( whereConditions , "(email " + ss . dialect . LikeStr ( ) + " ? OR name " + ss . dialect . LikeStr ( ) + " ? OR login " + ss . dialect . LikeStr ( ) + " ?)" )
whereParams = append ( whereParams , queryWithWildcards , queryWithWildcards , queryWithWildcards )
}
if query . IsDisabled != nil {
whereConditions = append ( whereConditions , "is_disabled = ?" )
whereParams = append ( whereParams , query . IsDisabled )
}
if query . AuthModule != "" {
whereConditions = append ( whereConditions , ` auth_module=? ` )
whereParams = append ( whereParams , query . AuthModule )
}
if len ( whereConditions ) > 0 {
sess . Where ( strings . Join ( whereConditions , " AND " ) , whereParams ... )
}
for _ , filter := range query . Filters {
if jc := filter . JoinCondition ( ) ; jc != nil {
sess . Join ( jc . Operator , jc . Table , jc . Params )
}
if ic := filter . InCondition ( ) ; ic != nil {
sess . In ( ic . Condition , ic . Params )
}
if wc := filter . WhereCondition ( ) ; wc != nil {
sess . Where ( wc . Condition , wc . Params )
}
}
if query . Limit > 0 {
offset := query . Limit * ( query . Page - 1 )
sess . Limit ( query . Limit , offset )
}
2024-07-26 09:09:08 -05:00
sess . Cols ( "u.id" , "u.uid" , "u.email" , "u.name" , "u.login" , "u.is_admin" , "u.is_disabled" , "u.last_seen_at" , "user_auth.auth_module" )
2023-09-28 03:16:18 -05:00
if len ( query . SortOpts ) > 0 {
for i := range query . SortOpts {
for j := range query . SortOpts [ i ] . Filter {
sess . OrderBy ( query . SortOpts [ i ] . Filter [ j ] . OrderBy ( ) )
}
}
} else {
sess . Asc ( "u.login" , "u.email" )
}
2022-10-05 02:34:36 -05:00
if err := sess . Find ( & result . Users ) ; err != nil {
return err
}
// get total
user := user . User { }
countSess := dbSess . Table ( "user" ) . Alias ( "u" )
// Join with user_auth table if users filtered by auth_module
if query . AuthModule != "" {
countSess . Join ( "LEFT" , "user_auth" , joinCondition )
}
if len ( whereConditions ) > 0 {
countSess . Where ( strings . Join ( whereConditions , " AND " ) , whereParams ... )
}
for _ , filter := range query . Filters {
if jc := filter . JoinCondition ( ) ; jc != nil {
countSess . Join ( jc . Operator , jc . Table , jc . Params )
}
if ic := filter . InCondition ( ) ; ic != nil {
countSess . In ( ic . Condition , ic . Params )
}
if wc := filter . WhereCondition ( ) ; wc != nil {
countSess . Where ( wc . Condition , wc . Params )
}
}
count , err := countSess . Count ( & user )
result . TotalCount = count
for _ , user := range result . Users {
user . LastSeenAtAge = util . GetAgeString ( user . LastSeenAt )
}
return err
} )
return & result , err
}
2022-12-07 11:33:40 -06:00
2024-04-29 01:53:05 -05:00
func setOptional [ T any ] ( v * T , add func ( v T ) ) {
if v != nil {
add ( * v )
}
}