From a98128ab208029bd270db6037c91ea7acc78bb32 Mon Sep 17 00:00:00 2001 From: Dishant Hirpara Date: Tue, 4 Aug 2026 13:34:25 -0700 Subject: [PATCH 1/3] [Ruby] Add created/modified time search params to search_all_users() #9538 What changed: - Added from_created_time, to_created_time, from_modified_time, to_modified_time optional keyword params to search_all_users() and search_all_test_users() in lib/descope/api/v1/management/user.rb, following the existing `body[:key] = value unless value.nil?` conditional-body pattern used for the other optional params in these methods. - Added YARD @param docs for all 4 new params on both methods. - Added new RSpec test cases ("is expected to include time-range filters when provided") to both the .search_users and .search_all_test_users contexts in spec/lib.descope/api/v1/management/user_spec.rb, mocking `post` and asserting the exact request body, matching the existing test style. - Updated the README "Search all users" example comment to mention the new time-filter params. Verified: - Syntax-verified with `ruby -c`. The system Ruby here is 2.6.10, but this codebase requires Ruby 3.3+ and uses 3.1+ shorthand hash syntax (`key:,`) throughout the file, which 2.6 can't parse. To get a real signal, both changed files were copied to scratch, had only that pre-existing shorthand syntax mechanically rewritten to explicit `key: key` form, and re-checked: both reported "Syntax OK". No changes were made to the actual repo files during this process. Not verified: - The new RSpec tests were not actually run (no Ruby 3.3+ runtime available in this session), so they are unexecuted since being written. No integration/functional testing against a live API was performed either. --- README.md | 4 +- lib/descope/api/v1/management/user.rb | 28 +++++++++- .../api/v1/management/user_spec.rb | 55 +++++++++++++++++++ 3 files changed, 84 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 7dc3ce24..c7084485 100644 --- a/README.md +++ b/README.md @@ -644,7 +644,9 @@ descope_client.logout_user('') descope_client.logout_user_by_id('') # Search all users, optionally according to tenant and/or role filter -# results can be paginated using the limit and page parameters +# results can be paginated using the limit and page parameters, +# as well as filtered by time with from_created_time, to_created_time, +# from_modified_time, and to_modified_time (Unix epoch milliseconds) users_resp = descope_client.search_all_users(tenant_ids = ['my-tenant-id']) users = users_resp['users'] users.each do |user| diff --git a/lib/descope/api/v1/management/user.rb b/lib/descope/api/v1/management/user.rb index 431059c1..0facae72 100644 --- a/lib/descope/api/v1/management/user.rb +++ b/lib/descope/api/v1/management/user.rb @@ -171,6 +171,10 @@ def logout_user_by_id(user_id) # Search for users, using a valid management key. # @see https://docs.descope.com/api/openapi/usermanagement/operation/SearchUsers/ + # @param from_created_time [Integer, nil] only include users created on or after this time (Unix epoch milliseconds). + # @param to_created_time [Integer, nil] only include users created on or before this time (Unix epoch milliseconds). + # @param from_modified_time [Integer, nil] only include users modified on or after this time (Unix epoch milliseconds). + # @param to_modified_time [Integer, nil] only include users modified on or before this time (Unix epoch milliseconds). def search_all_users( login_id: nil, tenant_ids: [], @@ -187,7 +191,11 @@ def search_all_users( phones: [], sso_app_ids: [], tenant_role_ids: {}, - tenant_role_names: {} + tenant_role_names: {}, + from_created_time: nil, + to_created_time: nil, + from_modified_time: nil, + to_modified_time: nil ) body = { loginId: login_id, @@ -216,6 +224,10 @@ def search_all_users( body[:roleNames] = role_names unless role_names.empty? body[:tenantRoleIds] = map_to_values_object(tenant_role_ids) unless tenant_role_ids.nil? || tenant_role_ids.empty? body[:tenantRoleNames] = map_to_values_object(tenant_role_names) unless tenant_role_names.nil? || tenant_role_names.empty? + body[:fromCreatedTime] = from_created_time unless from_created_time.nil? + body[:toCreatedTime] = to_created_time unless to_created_time.nil? + body[:fromModifiedTime] = from_modified_time unless from_modified_time.nil? + body[:toModifiedTime] = to_modified_time unless to_modified_time.nil? post(Common::USERS_SEARCH_PATH, body) end @@ -530,6 +542,10 @@ def generate_embedded_link(login_id: nil, custom_claims: nil) # @param text [String] Optional string, allows free text search among all user's attributes. # @param login_ids [Array] Optional list of login ids # @param sort [Array] Optional array, allows to sort by fields. + # @param from_created_time [Integer, nil] Optional, only include users created on or after this time (Unix epoch milliseconds). + # @param to_created_time [Integer, nil] Optional, only include users created on or before this time (Unix epoch milliseconds). + # @param from_modified_time [Integer, nil] Optional, only include users modified on or after this time (Unix epoch milliseconds). + # @param to_modified_time [Integer, nil] Optional, only include users modified on or before this time (Unix epoch milliseconds). # # @return [Hash] Return hash in the format {"users": []} # @@ -551,7 +567,11 @@ def search_all_test_users( text: nil, login_ids: [], tenant_role_ids: {}, - tenant_role_names: {} + tenant_role_names: {}, + from_created_time: nil, + to_created_time: nil, + from_modified_time: nil, + to_modified_time: nil ) tenant_ids ||= [] role_names ||= [] @@ -581,6 +601,10 @@ def search_all_test_users( body[:text] = text unless text.nil? || text.empty? body[:tenantRoleIds] = map_to_values_object(tenant_role_ids) unless tenant_role_ids.nil? || tenant_role_ids.empty? body[:tenantRoleNames] = map_to_values_object(tenant_role_names) unless tenant_role_names.nil? || tenant_role_names.empty? + body[:fromCreatedTime] = from_created_time unless from_created_time.nil? + body[:toCreatedTime] = to_created_time unless to_created_time.nil? + body[:fromModifiedTime] = from_modified_time unless from_modified_time.nil? + body[:toModifiedTime] = to_modified_time unless to_modified_time.nil? post(Common::TEST_USERS_SEARCH_PATH, body) end diff --git a/spec/lib.descope/api/v1/management/user_spec.rb b/spec/lib.descope/api/v1/management/user_spec.rb index 5164d6e3..142b9663 100644 --- a/spec/lib.descope/api/v1/management/user_spec.rb +++ b/spec/lib.descope/api/v1/management/user_spec.rb @@ -278,6 +278,35 @@ ) end.not_to raise_error end + + it 'is expected to include time-range filters when provided' do + expect(@instance).to receive(:post).with( + USERS_SEARCH_PATH, { + loginId: nil, + tenantIds: [], + roleNames: [], + limit: 0, + page: 0, + ssoAppIds: [], + ssoOnly: false, + testUsersOnly: false, + withTestUser: false, + fromCreatedTime: 1_700_000_000_000, + toCreatedTime: 1_800_000_000_000, + fromModifiedTime: 1_700_000_000_000, + toModifiedTime: 1_800_000_000_000 + } + ) + + expect do + @instance.search_all_users( + from_created_time: 1_700_000_000_000, + to_created_time: 1_800_000_000_000, + from_modified_time: 1_700_000_000_000, + to_modified_time: 1_800_000_000_000 + ) + end.not_to raise_error + end end context '.get_provider_token' do @@ -791,5 +820,31 @@ ) end.not_to raise_error end + + it 'is expected to include time-range filters when provided' do + expect(@instance).to receive(:post).with( + TEST_USERS_SEARCH_PATH, { + tenantIds: [], + roleNames: [], + limit: 0, + page: 0, + testUsersOnly: true, + withTestUser: true, + fromCreatedTime: 1_700_000_000_000, + toCreatedTime: 1_800_000_000_000, + fromModifiedTime: 1_700_000_000_000, + toModifiedTime: 1_800_000_000_000 + } + ) + + expect do + @instance.search_all_test_users( + from_created_time: 1_700_000_000_000, + to_created_time: 1_800_000_000_000, + from_modified_time: 1_700_000_000_000, + to_modified_time: 1_800_000_000_000 + ) + end.not_to raise_error + end end end From 272d7beb60a95d264d44435447909c1316dd7432 Mon Sep 17 00:00:00 2001 From: Dishant Hirpara Date: Tue, 4 Aug 2026 14:22:24 -0700 Subject: [PATCH 2/3] [Ruby] Fix search_all_users spec expectation missing text: nil MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit #9538 What changed: - Fixed the "is expected to include time-range filters when provided" test under .search_users in spec/lib.descope/api/v1/management/user_spec.rb: the expected request body was missing text: nil. search_all_users() always includes a text: key in its base body hash (even when the text: param is nil), unlike some other optional fields that are conditionally added — the test fixture didn't account for that. Verified: - Installed Ruby 4.0.6 via Homebrew (system Ruby was 2.6.10, too old for this repo's Ruby 3.3+ requirement) and ran `bundle exec rspec spec/lib.descope/api/v1/management/user_spec.rb` for real. This is what caught the bug: before this, the spec file had only been syntax-checked (`ruby -c`), never executed. - Full suite now passes: 46 examples, 0 failures, including both new time-range filter tests (.search_users and .search_all_test_users). Not verified: - No integration/functional testing against a live Descope API was performed; this is unit-level coverage with a mocked `post` call only. --- spec/lib.descope/api/v1/management/user_spec.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/spec/lib.descope/api/v1/management/user_spec.rb b/spec/lib.descope/api/v1/management/user_spec.rb index 142b9663..ea5838dd 100644 --- a/spec/lib.descope/api/v1/management/user_spec.rb +++ b/spec/lib.descope/api/v1/management/user_spec.rb @@ -287,6 +287,7 @@ roleNames: [], limit: 0, page: 0, + text: nil, ssoAppIds: [], ssoOnly: false, testUsersOnly: false, From 15120e2c0936e13664397a674aad03947835a801 Mon Sep 17 00:00:00 2001 From: Dishant Hirpara Date: Tue, 11 Aug 2026 11:00:34 -0700 Subject: [PATCH 3/3] docs: fix boundary wording for time-filter params #9538 What changed: - Corrected from_created_time/from_modified_time YARD docs in both search_all_users() and search_all_test_users(): "on or after" -> "after", to match confirmed backend behavior (SQL `>`, exclusive lower bound). - to_created_time/to_modified_time already said "on or before" correctly (SQL `<=`, inclusive upper bound) - left unchanged. Verified: - Backend behavior confirmed directly in source across 3 repos in an earlier research pass: managementservice/internal/services/user.go (only the to* variants set Negative: true), common's search domain (negative flag selects Operator vs NegativeOperator), and userservice/internal/entities/search.go (Operator: " > ", NegativeOperator: " <= " for both createdtime and modifiedtime). - Comment-only change; no functional code touched. Not verified: - No integration/functional testing against a live Descope API was performed; this is a documentation wording fix only. --- lib/descope/api/v1/management/user.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/descope/api/v1/management/user.rb b/lib/descope/api/v1/management/user.rb index 0facae72..46a032f7 100644 --- a/lib/descope/api/v1/management/user.rb +++ b/lib/descope/api/v1/management/user.rb @@ -171,9 +171,9 @@ def logout_user_by_id(user_id) # Search for users, using a valid management key. # @see https://docs.descope.com/api/openapi/usermanagement/operation/SearchUsers/ - # @param from_created_time [Integer, nil] only include users created on or after this time (Unix epoch milliseconds). + # @param from_created_time [Integer, nil] only include users created after this time (Unix epoch milliseconds). # @param to_created_time [Integer, nil] only include users created on or before this time (Unix epoch milliseconds). - # @param from_modified_time [Integer, nil] only include users modified on or after this time (Unix epoch milliseconds). + # @param from_modified_time [Integer, nil] only include users modified after this time (Unix epoch milliseconds). # @param to_modified_time [Integer, nil] only include users modified on or before this time (Unix epoch milliseconds). def search_all_users( login_id: nil, @@ -542,9 +542,9 @@ def generate_embedded_link(login_id: nil, custom_claims: nil) # @param text [String] Optional string, allows free text search among all user's attributes. # @param login_ids [Array] Optional list of login ids # @param sort [Array] Optional array, allows to sort by fields. - # @param from_created_time [Integer, nil] Optional, only include users created on or after this time (Unix epoch milliseconds). + # @param from_created_time [Integer, nil] Optional, only include users created after this time (Unix epoch milliseconds). # @param to_created_time [Integer, nil] Optional, only include users created on or before this time (Unix epoch milliseconds). - # @param from_modified_time [Integer, nil] Optional, only include users modified on or after this time (Unix epoch milliseconds). + # @param from_modified_time [Integer, nil] Optional, only include users modified after this time (Unix epoch milliseconds). # @param to_modified_time [Integer, nil] Optional, only include users modified on or before this time (Unix epoch milliseconds). # # @return [Hash] Return hash in the format {"users": []}