Fix group filter for users

The following could be used as an optimisation when we are filtering
just by user, but decided to omit as of now.

```
usrs, err = dao.ListFilteredUsersWithGroup(ctx, s.db,
    []uuid.UUID{}, groupId, queryOptions.Q, queryOptions.Type,
    queryOptions.OrderBy, queryOptions.Order,
    int(queryOptions.Limit), int(queryOptions.Offset))
```
This commit is contained in:
Abin Simon
2022-05-19 19:17:21 +05:30
parent 6d3aef400a
commit aabf2e600e
3 changed files with 101 additions and 34 deletions

View File

@@ -91,33 +91,50 @@ func GetQueryFilteredUsers(ctx context.Context, db bun.IDB, partner, org, group,
q.Where("partner_id = ?", partner).
Where("organization_id = ?", org)
if group != uuid.Nil {
q.Where("group_id = ?", group)
}
if role != uuid.Nil {
q.Where("role_id = ?", role)
}
if len(projects) != 0 {
q.Where("project_id IN (?)", bun.In(projects))
}
if group != uuid.Nil {
// If the group is not mapped to a project, we won't be able
// to pick it from sentry table and that is why we have to do
// this.
gaccs := []models.GroupAccount{}
subq := db.NewSelect().
Model(&gaccs).
ColumnExpr("DISTINCT account_id").
Where("group_id = ?", group).
Where("trash = ?", false)
q = q.Where("account_id IN (?)", subq)
}
err := q.Scan(ctx)
if err != nil {
return nil, err
}
acc := []uuid.UUID{}
for _, a := range p {
acc = append(acc, a.AccountId)
}
return acc, nil
}
// ListFilteredUsers will return the list of users fileterd by query
func ListFilteredUsers(ctx context.Context, db bun.IDB, users *[]models.KratosIdentities, fusers []uuid.UUID, query string, utype string, orderBy string, order string, limit int, offset int) (*[]models.KratosIdentities, error) {
q := db.NewSelect().Model(users)
func listFilteredUsersQuery(
q *bun.SelectQuery,
fusers []uuid.UUID,
query string,
utype string,
orderBy string,
order string,
limit int,
offset int,
) *bun.SelectQuery {
if utype != "" {
q.Relation("IdentityCredential").
q = q.Relation("IdentityCredential").
Relation("IdentityCredential.IdentityCredentialType", func(q *bun.SelectQuery) *bun.SelectQuery {
return q.Where("name = ?", utype)
})
@@ -125,22 +142,43 @@ func ListFilteredUsers(ctx context.Context, db bun.IDB, users *[]models.KratosId
if len(fusers) > 0 {
// filter with precomputed users if we have any
q.Where("identities.id IN (?)", bun.In(fusers))
q = q.Where("identities.id IN (?)", bun.In(fusers))
}
if query != "" {
q.Where("traits ->> 'email' ILIKE ?", "%"+query+"%") // XXX: ILIKE is not-standard sql
q.WhereOr("traits ->> 'first_name' ILIKE ?", "%"+query+"%")
q.WhereOr("traits ->> 'last_name' ILIKE ?", "%"+query+"%")
q = q.WhereGroup(" AND ", func(q *bun.SelectQuery) *bun.SelectQuery {
q = q.Where("traits ->> 'email' ILIKE ?", "%"+query+"%") // XXX: ILIKE is not-standard sql
q = q.WhereOr("traits ->> 'first_name' ILIKE ?", "%"+query+"%")
q = q.WhereOr("traits ->> 'last_name' ILIKE ?", "%"+query+"%")
return q
})
}
if orderBy != "" && order != "" {
q.Order("traits ->> '" + orderBy + "' " + order)
q = q.Order("traits ->> '" + orderBy + "' " + order)
}
if limit > 0 {
q.Limit(limit)
q = q.Limit(limit)
}
if offset > 0 {
q.Offset(offset)
q = q.Offset(offset)
}
return q
}
// ListFilteredUsers will return the list of users fileterd by query
func ListFilteredUsers(
ctx context.Context,
db bun.IDB,
fusers []uuid.UUID,
query string,
utype string,
orderBy string,
order string,
limit int,
offset int,
) ([]models.KratosIdentities, error) {
var users []models.KratosIdentities
q := db.NewSelect().Model(&users)
listFilteredUsersQuery(q, fusers, query, utype, orderBy, order, limit, offset)
err := q.Scan(ctx)
if err != nil {
return nil, err
@@ -148,6 +186,37 @@ func ListFilteredUsers(ctx context.Context, db bun.IDB, users *[]models.KratosId
return users, nil
}
// ListFilteredUsersWithGroup is ListFilteredUsers but with Group fileter as well
func ListFilteredUsersWithGroup(
ctx context.Context,
db bun.IDB,
fusers []uuid.UUID,
group uuid.UUID,
query string,
utype string,
orderBy string,
order string,
limit int,
offset int,
) ([]models.KratosIdentities, error) {
var users []models.KratosIdentities
var gaccs []models.GroupAccount
q := db.NewSelect().Model(&gaccs)
q.Where("group_id = ?", group).Where("groupaccount.trash = ?", false)
q = q.Relation("Account", func(q *bun.SelectQuery) *bun.SelectQuery {
return listFilteredUsersQuery(q, fusers, query, utype, orderBy, order, limit, offset)
})
err := q.Scan(ctx)
if err != nil {
return nil, err
}
for _, ga := range gaccs {
users = append(users, *ga.Account)
}
return users, nil
}
func GetUserNamesByIds(ctx context.Context, db bun.IDB, id []uuid.UUID, entity interface{}) ([]string, error) {
names := []string{}
if len(id) == 0 {

View File

@@ -16,9 +16,10 @@ type GroupAccount struct {
CreatedAt time.Time `bun:"created_at,notnull,default:current_timestamp"`
ModifiedAt time.Time `bun:"modified_at,notnull,default:current_timestamp"`
Trash bool `bun:"trash,notnull,default:false"`
// OrganizationId uuid.UUID `bun:"organization_id,type:uuid"`
// PartnerId uuid.UUID `bun:"partner_id,type:uuid"`
AccountId uuid.UUID `bun:"account_id,type:uuid"`
GroupId uuid.UUID `bun:"group_id,type:uuid"`
Active bool `bun:"active,notnull"`
AccountId uuid.UUID `bun:"account_id,type:uuid"`
GroupId uuid.UUID `bun:"group_id,type:uuid"`
Active bool `bun:"active,notnull"`
Account *KratosIdentities `bun:"rel:has-one,join:account_id=id"`
Group *Group `bun:"rel:has-one,join:group_id=id"`
}

View File

@@ -810,8 +810,7 @@ func (s *userService) List(ctx context.Context, opts ...query.Option) (*userv3.U
}
}
var usrs *[]models.KratosIdentities
var accs []models.KratosIdentities
var usrs []models.KratosIdentities
if len(projectIds) != 0 || groupId != uuid.Nil || roleId != uuid.Nil {
uids, err := dao.GetQueryFilteredUsers(ctx, s.db, partnerId, orgId, groupId, roleId, projectIds)
if err != nil {
@@ -819,8 +818,8 @@ func (s *userService) List(ctx context.Context, opts ...query.Option) (*userv3.U
}
if len(uids) != 0 {
// TODO: maybe merge this with the previous one into single sql
usrs, err = dao.ListFilteredUsers(ctx, s.db, &accs,
// TODO: merge this with the previous one into single sql
usrs, err = dao.ListFilteredUsers(ctx, s.db,
uids, queryOptions.Q, queryOptions.Type,
queryOptions.OrderBy, queryOptions.Order,
int(queryOptions.Limit), int(queryOptions.Offset))
@@ -830,7 +829,7 @@ func (s *userService) List(ctx context.Context, opts ...query.Option) (*userv3.U
}
} else {
// If no filters are available we have to list just using identities table
usrs, err = dao.ListFilteredUsers(ctx, s.db, &accs,
usrs, err = dao.ListFilteredUsers(ctx, s.db,
[]uuid.UUID{}, queryOptions.Q, queryOptions.Type,
queryOptions.OrderBy, queryOptions.Order,
int(queryOptions.Limit), int(queryOptions.Offset))
@@ -839,15 +838,13 @@ func (s *userService) List(ctx context.Context, opts ...query.Option) (*userv3.U
}
}
if usrs != nil {
for _, usr := range *usrs {
user := &userv3.User{}
user, err := s.identitiesModelToUser(ctx, s.db, user, &usr)
if err != nil {
return userList, err
}
users = append(users, user)
for _, usr := range usrs {
user := &userv3.User{}
user, err := s.identitiesModelToUser(ctx, s.db, user, &usr)
if err != nil {
return userList, err
}
users = append(users, user)
}
// update the list metadata and items response