Skip to content

feat: support filtering users table by login type #17238

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 15 commits into from
Apr 9, 2025
Merged
Prev Previous commit
Next Next commit
add tests
  • Loading branch information
utsavll0 committed Apr 3, 2025
commit de02f49b9ee88ca6c0b53cf26bf63f039f186a49
88 changes: 67 additions & 21 deletions coderd/searchquery/search_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -386,72 +386,118 @@ func TestSearchUsers(t *testing.T) {
Name: "Empty",
Query: "",
Expected: database.GetUsersParams{
Status: []database.UserStatus{},
RbacRole: []string{},
Status: []database.UserStatus{},
RbacRole: []string{},
LoginType: []database.LoginType{},
},
},
{
Name: "Username",
Query: "user-name",
Expected: database.GetUsersParams{
Search: "user-name",
Status: []database.UserStatus{},
RbacRole: []string{},
Search: "user-name",
Status: []database.UserStatus{},
RbacRole: []string{},
LoginType: []database.LoginType{},
},
},
{
Name: "UsernameWithSpaces",
Query: " user-name ",
Expected: database.GetUsersParams{
Search: "user-name",
Status: []database.UserStatus{},
RbacRole: []string{},
Search: "user-name",
Status: []database.UserStatus{},
RbacRole: []string{},
LoginType: []database.LoginType{},
},
},
{
Name: "Username+Param",
Query: "usEr-name stAtus:actiVe",
Expected: database.GetUsersParams{
Search: "user-name",
Status: []database.UserStatus{database.UserStatusActive},
RbacRole: []string{},
Search: "user-name",
Status: []database.UserStatus{database.UserStatusActive},
RbacRole: []string{},
LoginType: []database.LoginType{},
},
},
{
Name: "OnlyParams",
Query: "status:acTIve sEArch:User-Name role:Owner",
Expected: database.GetUsersParams{
Search: "user-name",
Status: []database.UserStatus{database.UserStatusActive},
RbacRole: []string{codersdk.RoleOwner},
Search: "user-name",
Status: []database.UserStatus{database.UserStatusActive},
RbacRole: []string{codersdk.RoleOwner},
LoginType: []database.LoginType{},
},
},
{
Name: "QuotedParam",
Query: `status:SuSpenDeD sEArch:"User Name" role:meMber`,
Expected: database.GetUsersParams{
Search: "user name",
Status: []database.UserStatus{database.UserStatusSuspended},
RbacRole: []string{codersdk.RoleMember},
Search: "user name",
Status: []database.UserStatus{database.UserStatusSuspended},
RbacRole: []string{codersdk.RoleMember},
LoginType: []database.LoginType{},
},
},
{
Name: "QuotedKey",
Query: `"status":acTIve "sEArch":User-Name "role":Owner`,
Expected: database.GetUsersParams{
Search: "user-name",
Status: []database.UserStatus{database.UserStatusActive},
RbacRole: []string{codersdk.RoleOwner},
Search: "user-name",
Status: []database.UserStatus{database.UserStatusActive},
RbacRole: []string{codersdk.RoleOwner},
LoginType: []database.LoginType{},
},
},
{
// Quotes keep elements together
Name: "QuotedSpecial",
Query: `search:"user:name"`,
Expected: database.GetUsersParams{
Search: "user:name",
Search: "user:name",
Status: []database.UserStatus{},
RbacRole: []string{},
LoginType: []database.LoginType{},
},
},
{
Name: "LoginType",
Query: "login_type:github",
Expected: database.GetUsersParams{
Search: "",
Status: []database.UserStatus{},
RbacRole: []string{},
LoginType: []database.LoginType{database.LoginTypeGithub},
},
},
{
Name: "MultipleLoginTypesWithSpaces",
Query: "login_type:github login_type:password",
Expected: database.GetUsersParams{
Search: "",
Status: []database.UserStatus{},
RbacRole: []string{},
LoginType: []database.LoginType{
database.LoginTypeGithub,
database.LoginTypePassword,
},
},
},
{
Name: "MultipleLoginTypesWithCommas",
Query: "login_type:github,password,none,oidc",
Expected: database.GetUsersParams{
Search: "",
Status: []database.UserStatus{},
RbacRole: []string{},
LoginType: []database.LoginType{
database.LoginTypeGithub,
database.LoginTypePassword,
database.LoginTypeNone,
database.LoginTypeOIDC,
},
},
},

Expand Down
2 changes: 1 addition & 1 deletion coderd/users.go
Original file line number Diff line number Diff line change
Expand Up @@ -306,7 +306,7 @@ func (api *API) GetUsers(rw http.ResponseWriter, r *http.Request) ([]database.Us
CreatedAfter: params.CreatedAfter,
CreatedBefore: params.CreatedBefore,
GithubComUserID: params.GithubComUserID,
LoginType: params.LoginType,
LoginType: params.LoginType,
// #nosec G115 - Pagination offsets are small and fit in int32
OffsetOpt: int32(paginationParams.Offset),
// #nosec G115 - Pagination limits are small and fit in int32
Expand Down
25 changes: 25 additions & 0 deletions coderd/users_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1902,6 +1902,31 @@ func TestGetUsers(t *testing.T) {
require.Len(t, res.Users, 1)
require.Equal(t, res.Users[0].ID, first.UserID)
})
t.Run("LoginType", func(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
defer cancel()

client, db := coderdtest.NewWithDatabase(t, nil)
first := coderdtest.CreateFirstUser(t, client)
_ = dbgen.User(t, db, database.User{
Email: "test2@coder.com",
Username: "test2",
})
// nolint:gocritic // Unit test
_, err := db.UpdateUserLoginType(dbauthz.AsSystemRestricted(ctx), database.UpdateUserLoginTypeParams{
UserID: first.UserID,
NewLoginType: database.LoginTypeNone,
})
require.NoError(t, err)
res, err := client.Users(ctx, codersdk.UsersRequest{
LoginType: codersdk.LoginTypeNone,
})
require.NoError(t, err)
require.Len(t, res.Users, 1)
require.Equal(t, res.Users[0].ID, first.UserID)
require.Equal(t, res.Users[0].LoginType, codersdk.LoginTypeGithub)
})
}

func TestGetUsersPagination(t *testing.T) {
Expand Down
6 changes: 5 additions & 1 deletion codersdk/users.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ type UsersRequest struct {
// Filter users by status.
Status UserStatus `json:"status,omitempty" typescript:"-"`
// Filter users that have the given role.
Role string `json:"role,omitempty" typescript:"-"`
Role string `json:"role,omitempty" typescript:"-"`
LoginType LoginType `json:"login_type,omitempty" typescript:"-"`

SearchQuery string `json:"q,omitempty"`
Pagination
Expand Down Expand Up @@ -723,6 +724,9 @@ func (c *Client) Users(ctx context.Context, req UsersRequest) (GetUsersResponse,
if req.SearchQuery != "" {
params = append(params, req.SearchQuery)
}
if req.LoginType != "" {
params = append(params, "login_type:"+string(req.LoginType))
}
q.Set("q", strings.Join(params, " "))
r.URL.RawQuery = q.Encode()
},
Expand Down