diff --git a/internal/dao/user.go b/internal/dao/user.go index 4e6ad8e..c0b7833 100644 --- a/internal/dao/user.go +++ b/internal/dao/user.go @@ -71,7 +71,6 @@ type userProjectnamesaceRole struct { Project *string `bun:"project,type:string"` } -// TODO: find a better name for the function func GetQueryFilteredUsers(ctx context.Context, db bun.IDB, partner, org, group, role uuid.UUID, projects []uuid.UUID) ([]uuid.UUID, error) { p := []models.AccountPermission{} q := db.NewSelect().Model(&p).ColumnExpr("DISTINCT account_id") @@ -100,7 +99,10 @@ func GetQueryFilteredUsers(ctx context.Context, db bun.IDB, partner, org, group, // 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, orderBy string, order string, limit int, offset int) (*[]models.KratosIdentities, error) { q := db.NewSelect().Model(users) - q.Where("id IN (?)", bun.In(fusers)) + if len(fusers) > 0 { + // filter with precomputed users if we have any + q.Where("id IN (?)", bun.In(fusers)) + } if query != "" { q.Where("traits ->> 'email' ILIKE ?", "%"+query+"%") // XXX: ILIKE is not-standard q.WhereOr("traits ->> 'first_name' ILIKE ?", "%"+query+"%") diff --git a/pkg/service/user.go b/pkg/service/user.go index c72dd46..f584151 100644 --- a/pkg/service/user.go +++ b/pkg/service/user.go @@ -707,21 +707,36 @@ func (s *userService) List(ctx context.Context, opts ...query.Option) (*userv3.U } } - uids, err := dao.GetQueryFilteredUsers(ctx, s.db, partnerId, orgId, groupId, roleId, projectIds) - if err != nil { - return &userv3.UserList{}, err - } + var usrs *[]models.KratosIdentities + var accs []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 { + return &userv3.UserList{}, err + } - if len(uids) != 0 { - var accs []models.KratosIdentities - // TODO: maybe merge this with the previous one into single sql - usrs, err := dao.ListFilteredUsers(ctx, s.db, &accs, - uids, queryOptions.Q, + if len(uids) != 0 { + // TODO: maybe merge this with the previous one into single sql + usrs, err = dao.ListFilteredUsers(ctx, s.db, &accs, + uids, queryOptions.Q, + queryOptions.OrderBy, queryOptions.Order, + int(queryOptions.Limit), int(queryOptions.Offset)) + if err != nil { + return userList, err + } + } + } else { + // If no filters are available we have to list just using identities table + usrs, err = dao.ListFilteredUsers(ctx, s.db, &accs, + []uuid.UUID{}, queryOptions.Q, queryOptions.OrderBy, queryOptions.Order, int(queryOptions.Limit), int(queryOptions.Offset)) if err != nil { return userList, err } + } + + if usrs != nil { for _, usr := range *usrs { user := &userv3.User{} user, err := s.identitiesModelToUser(ctx, s.db, user, &usr) diff --git a/pkg/service/user_test.go b/pkg/service/user_test.go index 5262c0d..5bc4b4c 100644 --- a/pkg/service/user_test.go +++ b/pkg/service/user_test.go @@ -429,9 +429,7 @@ func TestUserList(t *testing.T) { WithArgs().WillReturnRows(sqlmock.NewRows([]string{"id"}).AddRow(puuid)) mock.ExpectQuery(`SELECT "organization"."id" FROM "authsrv_organization" AS "organization"`). WithArgs().WillReturnRows(sqlmock.NewRows([]string{"id"}).AddRow(ouuid)) - mock.ExpectQuery(`SELECT DISTINCT account_id FROM "sentry_account_permission" AS "sap" WHERE .partner_id = '` + puuid + `'. AND .organization_id = '` + ouuid + `'`). - WithArgs().WillReturnRows(sqlmock.NewRows([]string{"account_id"}).AddRow(uuuid1).AddRow(uuuid2)) - mock.ExpectQuery(`SELECT "identities"."id", .*WHERE .id IN .'` + uuuid1 + `', '` + uuuid2 + `'.. LIMIT 10`). + mock.ExpectQuery(`SELECT "identities"."id", .*FROM "identities" LIMIT 10`). WithArgs().WillReturnRows(sqlmock.NewRows([]string{"id", "traits"}). AddRow(uuuid1, []byte(`{"email":"johndoe@provider.com", "first_name": "John", "last_name": "Doe", "organization_id": "`+ouuid+`", "partner_id": "`+puuid+`", "description": "My awesome user"}`)). AddRow(uuuid2, []byte(`{"email":"johndoe@provider.com", "first_name": "John", "last_name": "Doe", "organization_id": "`+ouuid+`", "partner_id": "`+puuid+`", "description": "My awesome user"}`))) @@ -492,7 +490,7 @@ func TestUserList(t *testing.T) { performBasicAuthProviderChecks(t, *ap, 0, 0, 0, 0) } -func TestUserFiletered(t *testing.T) { +func TestUserFiltered(t *testing.T) { db, mock := getDB(t) defer db.Close() @@ -512,6 +510,8 @@ func TestUserFiletered(t *testing.T) { WithArgs().WillReturnRows(sqlmock.NewRows([]string{"id"}).AddRow(puuid)) mock.ExpectQuery(`SELECT "organization"."id" FROM "authsrv_organization" AS "organization"`). WithArgs().WillReturnRows(sqlmock.NewRows([]string{"id"}).AddRow(ouuid)) + mock.ExpectQuery(`SELECT "group"."id" FROM "authsrv_group" AS "group" WHERE .name = 'group-name'. AND .trash = FALSE.`). + WithArgs().WillReturnRows(sqlmock.NewRows([]string{"id"}).AddRow(guuid)) mock.ExpectQuery(`SELECT DISTINCT account_id FROM "sentry_account_permission" AS "sap" WHERE .partner_id = '` + puuid + `'. AND .organization_id = '` + ouuid + `'`). WithArgs().WillReturnRows(sqlmock.NewRows([]string{"account_id"}).AddRow(uuuid1).AddRow(uuuid2)) mock.ExpectQuery(`SELECT "identities"."id", .*WHERE .id IN .'` + uuuid1 + `', '` + uuuid2 + `'.. AND .traits ->> 'email' ILIKE '%filter-query%'. OR .traits ->> 'first_name' ILIKE '%filter-query%'. OR .traits ->> 'last_name' ILIKE '%filter-query%'. ORDER BY "traits ->> 'email' asc" LIMIT 50 OFFSET 20`). @@ -563,7 +563,7 @@ func TestUserFiletered(t *testing.T) { mock.ExpectQuery(`SELECT authsrv_resourcerole.name as role, authsrv_project.name as project, namespace_id as namespace FROM "authsrv_projectaccountnamespacerole" JOIN authsrv_resourcerole ON authsrv_resourcerole.id=authsrv_projectaccountnamespacerole.role_id JOIN authsrv_project ON authsrv_project.id=authsrv_projectaccountnamespacerole.project_id WHERE .authsrv_projectaccountnamespacerole.account_id = '` + uuuid2 + `'`). WithArgs().WillReturnRows(sqlmock.NewRows([]string{"role", "project", "namespace"}).AddRow("role-"+ruuid, "project-"+pruuid, 9)) - qo := &commonv3.QueryOptions{Q: "filter-query", Limit: 50, Offset: 20, OrderBy: "email", Order: "asc", Organization: ouuid, Partner: puuid} + qo := &commonv3.QueryOptions{Q: "filter-query", Limit: 50, Offset: 20, OrderBy: "email", Order: "asc", Organization: ouuid, Partner: puuid, Group: "group-name"} userlist, err := us.List(context.Background(), query.WithOptions(qo)) if err != nil { t.Fatal("could not list users:", err)