-
Notifications
You must be signed in to change notification settings - Fork 875
feat: support created_at filter for the GET /users endpoint #15633
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
Conversation
@ericpaulsen @matifali could you please take a look at this? |
Thanks for the PR! Whilst this technically addresses the linked issue, I'm not sure how useful it is if it doesn't support date ranges. I think it'd make more sense to implement it in terms of Although not mentioned in the issue, we'll also want to support this filter on the frontend (a separate PR for that is fine), on the |
@ethanndickson sure! will update the PR |
@ethanndickson I've updated the PR to support date ranges. Also I don't think we need to make any changes in the frontend as the params are directly passed on to the backend and is working fine as shown below. Please do have a look at the PR. ![]() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, just one comment on naming, sorry for misleading you there!
docs/admin/users/index.md
Outdated
platform (e.g. logging in, any API requests, connecting to workspaces). Uses | ||
the RFC3339Nano format. | ||
- `created_at_before` and `created_at_after` - The time a user was created. Uses |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think created_at_{after|before}
reads very well. I didn't really think about the phrasing when I wrote it earlier. Let's just go with created_before
and created_after
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
updated the PR!
Name: "CreatedAtRange", | ||
Filter: codersdk.UsersRequest{ | ||
SearchQuery: `created_after:"2023-01-01T00:00:00Z" created_before:"2023-01-31T23:59:59Z"`, | ||
}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All the users created in the setup of this test have the same creation date. We should add some users created within the range, and before the CreatedBefore
testcase timestamp. Right now those testcases are just comparing empty slices.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've updated the PR with the tests, please do have a look
coderd/users_test.go
Outdated
Status: codersdk.UserStatusSuspended + "," + codersdk.UserStatusActive, | ||
}, | ||
Name: "All", | ||
Filter: codersdk.UsersRequest{}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
updated this since "All" filter should include all the users
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Given this is done twice, I assume this was intentional. Just a sanity check that all users are either suspended or active. I think we should just keep the original.
coderd/users_test.go
Outdated
@@ -1602,7 +1639,7 @@ func TestUsersFilter(t *testing.T) { | |||
Status: codersdk.UserStatusSuspended + "," + codersdk.UserStatusActive, | |||
}, | |||
FilterF: func(_ codersdk.UsersRequest, u codersdk.User) bool { | |||
return true | |||
return u.Status == codersdk.UserStatusSuspended || u.Status == codersdk.UserStatusActive |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the request, status is filtered with UserStatusSuspended
and UserStatusActive
, handling the same here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here, let's keep the original as it was almost certainly purposeful.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Few comments then I'm happy to approve!
coderd/users_test.go
Outdated
Status: codersdk.UserStatusSuspended + "," + codersdk.UserStatusActive, | ||
}, | ||
Name: "All", | ||
Filter: codersdk.UsersRequest{}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Given this is done twice, I assume this was intentional. Just a sanity check that all users are either suspended or active. I think we should just keep the original.
coderd/users_test.go
Outdated
@@ -1602,7 +1639,7 @@ func TestUsersFilter(t *testing.T) { | |||
Status: codersdk.UserStatusSuspended + "," + codersdk.UserStatusActive, | |||
}, | |||
FilterF: func(_ codersdk.UsersRequest, u codersdk.User) bool { | |||
return true | |||
return u.Status == codersdk.UserStatusSuspended || u.Status == codersdk.UserStatusActive |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here, let's keep the original as it was almost certainly purposeful.
coderd/users_test.go
Outdated
@@ -1513,6 +1513,45 @@ func TestUsersFilter(t *testing.T) { | |||
users = append(users, user) | |||
} | |||
|
|||
// Add users with different creation dates for testing date filters | |||
for i := 0; i < 3; i++ { | |||
// nolint:gocritic |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Each of these nolint
should mention that the system context is necessary here. (Also to make it clear which specific rule this is nolint
ing)
@ethanndickson addressed the comments! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Last comment, thanks for your patience!
coderd/users_test.go
Outdated
@@ -2273,6 +2346,28 @@ func onlyUsernames[U codersdk.User | database.User](users []U) []string { | |||
return out | |||
} | |||
|
|||
// dbUserToSDKUser converts database.User to codersdk.User | |||
func dbUserToSDKUser(dbUser database.User) codersdk.User { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We fortunately already have this function, db2sdk.User
. It takes a database.User
and a slice of organization IDs. In this case that slice should just be []uuid.UUID{first.OrganizationID})
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thanks for pointing this out!
@ethanndickson Done! |
coderd/users_test.go
Outdated
fmt.Printf("expexp: %+v\n", exp) | ||
fmt.Printf("matched.Usersmatched.Users: %+v\n", matched.Users) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fmt.Printf("expexp: %+v\n", exp) | |
fmt.Printf("matched.Usersmatched.Users: %+v\n", matched.Users) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
my bad, fixed it!
Looks like the test is failing on Postgres. The expected list of users have timestamps with time zones, while the actual list of users retrieved via the API has timestamps parsed from strings, which don’t have timezones. I’m not sure of the best way to fix that.. |
@ethanndickson put together a little hack to fix this. Instead of using the db object, call an API to update the status and used that user object to be added to the list of expected users. Please do have a look. |
coderd/users_test.go
Outdated
}) | ||
require.NoError(t, err) | ||
|
||
// hack: Call UpdateUserStatus to get API-formatted timestamps (without timezones) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's avoid all this extra work & extra DB queries if we can.
For each of these, we can round-trip just the timestamps.
sdkUser1 := db2sdk.User(user1, nil)
sdkUser1.CreatedAt, err = time.Parse(time.RFC3339, sdkUser1.CreatedAt.Format(time.RFC3339))
require.NoError(t, err)
sdkUser1.UpdatedAt, err = time.Parse(time.RFC3339, sdkUser1.UpdatedAt.Format(time.RFC3339))
require.NoError(t, err)
sdkUser1.LastSeenAt, err = time.Parse(time.RFC3339, sdkUser1.LastSeenAt.Format(time.RFC3339))
require.NoError(t, err)
users = append(users, sdkUser1)
I don't think we'll find a better way. I wish the API just let you manually enter this timezoneless state.
Yep, definitely unrelated. Will fix. |
Should be fixed after a merge from main! |
@@ -1677,6 +1777,17 @@ func TestUsersFilter(t *testing.T) { | |||
exp = append(exp, made) | |||
} | |||
} | |||
|
|||
// TODO: This can be removed with dbmem | |||
if !dbtestutil.WillUsePostgres() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The plan is to eventually get rid of dbmem
entirely, so I'm not too worried about cluttering up this test. I've used dbtestutil.WillUsePostgres
as it's more likely to found and removed when that happens.
This is to handle a disparity between organization-less members in Postgres and dbmem. For dbmem, the API returns an empty slice. For postgres it returns nil. (FWIW it's not possible to have organization-less members on a real Coder deployment.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for your contribution and your patience through the review cycle! Greatly appreciated!
Closes #12747
We support these filters currently: https://coder.com/docs/v2/latest/admin/users#user-filtering, adding
created_at
filter as well.