From 8e12576f403a27b87c657daee73f58f421c81571 Mon Sep 17 00:00:00 2001 From: Daniel DeGroff Date: Sat, 12 Oct 2024 00:29:33 -0600 Subject: [PATCH 1/9] Updated version for fusionauth-python-client to 1.55.0 --- build.savant | 2 +- setup.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build.savant b/build.savant index 11542ac..ebd9e9e 100644 --- a/build.savant +++ b/build.savant @@ -14,7 +14,7 @@ * language governing permissions and limitations under the License. */ -project(group: "io.fusionauth", name: "fusionauth-python-client", version: "1.54.0", licenses: ["ApacheV2_0"]) { +project(group: "io.fusionauth", name: "fusionauth-python-client", version: "1.55.0", licenses: ["ApacheV2_0"]) { workflow { fetch { cache() diff --git a/setup.py b/setup.py index d5d382d..8370715 100644 --- a/setup.py +++ b/setup.py @@ -5,7 +5,7 @@ setup( name="fusionauth-client", - version="1.54.0", + version="1.55.0", author="FusionAuth", author_email="dev@fusionauth.io", description="A client library for FusionAuth", From 072caa595430c31fda0635b64e2ef4df43b0b9af Mon Sep 17 00:00:00 2001 From: Daniel DeGroff Date: Fri, 22 Nov 2024 15:57:05 -0700 Subject: [PATCH 2/9] Updated version for fusionauth-python-client to 1.56.0 --- build.savant | 2 +- setup.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build.savant b/build.savant index ebd9e9e..84b6c4c 100644 --- a/build.savant +++ b/build.savant @@ -14,7 +14,7 @@ * language governing permissions and limitations under the License. */ -project(group: "io.fusionauth", name: "fusionauth-python-client", version: "1.55.0", licenses: ["ApacheV2_0"]) { +project(group: "io.fusionauth", name: "fusionauth-python-client", version: "1.56.0", licenses: ["ApacheV2_0"]) { workflow { fetch { cache() diff --git a/setup.py b/setup.py index 8370715..0d665fb 100644 --- a/setup.py +++ b/setup.py @@ -5,7 +5,7 @@ setup( name="fusionauth-client", - version="1.55.0", + version="1.56.0", author="FusionAuth", author_email="dev@fusionauth.io", description="A client library for FusionAuth", From c0af6c97e3d937df6dc5082e9761cfd4fd7a80b8 Mon Sep 17 00:00:00 2001 From: Brady Wied Date: Thu, 23 Jan 2025 15:33:06 -0700 Subject: [PATCH 3/9] client builder regen (#35) --- .../python/fusionauth/fusionauth_client.py | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/src/main/python/fusionauth/fusionauth_client.py b/src/main/python/fusionauth/fusionauth_client.py index 4bb2782..3214d32 100644 --- a/src/main/python/fusionauth/fusionauth_client.py +++ b/src/main/python/fusionauth/fusionauth_client.py @@ -225,6 +225,18 @@ def comment_on_user(self, request): .post() \ .go() + def complete_verify_identity(self, request): + """ + Completes verification of an identity using verification codes from the Verify Start API. + + Attributes: + request: The identity verify complete request that contains all the information used to verify the identity. + """ + return self.start().uri('/api/identity/verify/complete') \ + .body_handler(JSONBodyHandler(request)) \ + .post() \ + .go() + def complete_web_authn_assertion(self, request): """ Complete a WebAuthn authentication ceremony by validating the signature against the previously generated challenge without logging the user in @@ -4088,6 +4100,18 @@ def send_two_factor_code_for_login_using_method(self, two_factor_id, request): .post() \ .go() + def send_verify_identity(self, request): + """ + Send a verification code using the appropriate transport for the identity type being verified. + + Attributes: + request: The identity verify send request that contains all the information used send the code. + """ + return self.start().uri('/api/identity/verify/send') \ + .body_handler(JSONBodyHandler(request)) \ + .post() \ + .go() + def start_identity_provider_login(self, request): """ Begins a login request for a 3rd party login that requires user interaction such as HYPR. @@ -4131,6 +4155,19 @@ def start_two_factor_login(self, request): .post() \ .go() + def start_verify_identity(self, request): + """ + Start a verification of an identity by generating a code. This code can be sent to the User using the Verify Send API + Verification Code API or using a mechanism outside of FusionAuth. The verification is completed by using the Verify Complete API with this code. + + Attributes: + request: The identity verify start request that contains all the information used to begin the request. + """ + return self.start().uri('/api/identity/verify/start') \ + .body_handler(JSONBodyHandler(request)) \ + .post() \ + .go() + def start_web_authn_login(self, request): """ Start a WebAuthn authentication ceremony by generating a new challenge for the user From ee73b8f6221ed8d3fa1d6e49ab1056db174f0f55 Mon Sep 17 00:00:00 2001 From: Brady Wied Date: Wed, 7 May 2025 14:36:48 -0600 Subject: [PATCH 4/9] ENG-2608 - New APIs/method overloads (#41) * run on all PRs * Python updates * add report method * revert overloads * test fixes * client correct/optional * now that this overload does not have opt params, remove defaults --- .github/workflows/test.yaml | 3 -- .../python/fusionauth/fusionauth_client.py | 35 ++++++++++++++++++ .../fusionauth/fusionauth_client_test.py | 36 +++++++++++++++++-- 3 files changed, 68 insertions(+), 6 deletions(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 1df2db1..ba67e3e 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -10,9 +10,6 @@ on: - main - develop pull_request: - branches: - - main - - develop workflow_dispatch: jobs: diff --git a/src/main/python/fusionauth/fusionauth_client.py b/src/main/python/fusionauth/fusionauth_client.py index 264dc80..041efaf 100644 --- a/src/main/python/fusionauth/fusionauth_client.py +++ b/src/main/python/fusionauth/fusionauth_client.py @@ -3377,6 +3377,20 @@ def retrieve_user_by_login_id(self, login_id): .get() \ .go() + def retrieve_user_by_login_id_with_login_id_types(self, login_id, login_id_types): + """ + Retrieves the user for the loginId, using specific loginIdTypes. + + Attributes: + login_id: The email or username of the user. + login_id_types: the identity types that FusionAuth will compare the loginId to. + """ + return self.start().uri('/api/user') \ + .url_parameter('loginId', self.convert_true_false(login_id)) \ + .url_parameter('loginIdTypes', self.convert_true_false(login_id_types)) \ + .get() \ + .go() + def retrieve_user_by_username(self, username): """ Retrieves the user for the given username. @@ -3558,6 +3572,27 @@ def retrieve_user_login_report_by_login_id(self, login_id, start, end, applicati .get() \ .go() + def retrieve_user_login_report_by_login_id_and_login_id_types(self, login_id, start, end, login_id_types, application_id=None): + """ + Retrieves the login report between the two instants for a particular user by login Id, using specific loginIdTypes. If you specify an application id, it will only return the + login counts for that application. + + Attributes: + application_id: (Optional) The application id. + login_id: The userId id. + start: The start instant as UTC milliseconds since Epoch. + end: The end instant as UTC milliseconds since Epoch. + login_id_types: the identity types that FusionAuth will compare the loginId to. + """ + return self.start().uri('/api/report/login') \ + .url_parameter('applicationId', self.convert_true_false(application_id)) \ + .url_parameter('loginId', self.convert_true_false(login_id)) \ + .url_parameter('start', self.convert_true_false(start)) \ + .url_parameter('end', self.convert_true_false(end)) \ + .url_parameter('loginIdTypes', self.convert_true_false(login_id_types)) \ + .get() \ + .go() + def retrieve_user_recent_logins(self, user_id, offset, limit): """ Retrieves the last number of login records for a user. diff --git a/src/test/python/fusionauth/fusionauth_client_test.py b/src/test/python/fusionauth/fusionauth_client_test.py index dd72caf..8f7545c 100644 --- a/src/test/python/fusionauth/fusionauth_client_test.py +++ b/src/test/python/fusionauth/fusionauth_client_test.py @@ -1,4 +1,16 @@ -# Copyright (c) 2024, FusionAuth, All Rights Reserved +# Copyright (c) 2024-2025, FusionAuth, All Rights Reserved +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +# either express or implied. See the License for the specific +# language governing permissions and limitations under the License. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -26,9 +38,8 @@ import json import os -import uuid - import unittest +import uuid from fusionauth.fusionauth_client import FusionAuthClient @@ -84,6 +95,25 @@ def test_create_user_retrieve_user(self): self.assertFalse('password' in get_user_response.success_response['user']) self.assertFalse('salt' in get_user_response.success_response['user']) + # Retrieve the user via loginId + get_user_response = self.client.retrieve_user_by_login_id('user@example.com') + self.assertEqual(get_user_response.status, 200) + self.assertIsNotNone(get_user_response.success_response) + self.assertIsNone(get_user_response.error_response) + self.assertEqual(get_user_response.success_response['user']['email'], 'user@example.com') + + # Explicit loginIdType + get_user_response = self.client.retrieve_user_by_login_id_with_login_id_types('user@example.com', ['email']) + self.assertEqual(get_user_response.status, 200) + self.assertIsNotNone(get_user_response.success_response) + self.assertIsNone(get_user_response.error_response) + self.assertEqual(get_user_response.success_response['user']['email'], 'user@example.com') + + # TODO: Once issue 1 is released, this test should pass + # # wrong loginIdType + # get_user_response = self.client.retrieve_user_by_login_id_with_login_id_types('user@example.com', ['phoneNumber']) + # self.assertEqual(get_user_response.status, 404) + def test_retrieve_user_missing(self): user_id = uuid.uuid4() client_response = self.client.retrieve_user(user_id) From 9eb38b5dad3218a36a6a6acd55767a9ae55a00a7 Mon Sep 17 00:00:00 2001 From: Brady Wied Date: Tue, 13 May 2025 19:52:29 -0600 Subject: [PATCH 5/9] fail builds if compiles fail (#42) --- build.savant | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/build.savant b/build.savant index 4d27c06..4e01c1b 100644 --- a/build.savant +++ b/build.savant @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018-2024, FusionAuth, All Rights Reserved + * Copyright (c) 2018-2025, FusionAuth, All Rights Reserved * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -50,7 +50,7 @@ target(name: "clean", description: "Cleans the build directory") { target(name: "compile", description: "Builds archives of the source and compiled versions of the code.", dependsOn: ["setup-python"]) { def proc = "python3 setup.py sdist bdist_wheel".execute() proc.consumeProcessOutput(System.out, System.err) - proc.waitFor() + assert proc.waitFor() == 0 } target(name: "int", description: "Releases a local integration build of the project", dependsOn: ["compile"]) { @@ -78,11 +78,11 @@ target(name: "test", description: "Runs the project's tests", dependsOn: ["compi target(name: "setup-python", description: "Gets the python dependencies") { def proc1 = "python3 -m pip install --user --upgrade setuptools".execute() proc1.consumeProcessOutput(System.out, System.err) - proc1.waitFor() + assert proc1.waitFor() == 0 def proc2 = "python3 -m pip install --user --upgrade wheel twine requests deprecated".execute() proc2.consumeProcessOutput(System.out, System.err) - proc2.waitFor() + assert proc2.waitFor() == 0 } /** @@ -104,8 +104,7 @@ target(name: "publish", description: "Publishes source and built versions of the def process = pb.start() process.consumeProcessOutput(System.out, System.err) - process.waitFor() - return process.exitValue() == 0 + assert process.waitFor() == 0 } target(name: "release", description: "Releases a full version of the project", dependsOn: ["int"]) { From ba71cccc5936f6394c8defc323d487b49a516843 Mon Sep 17 00:00:00 2001 From: Brady Wied Date: Thu, 12 Jun 2025 11:48:22 -0600 Subject: [PATCH 6/9] client builder sb build --- src/main/python/fusionauth/fusionauth_client.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/main/python/fusionauth/fusionauth_client.py b/src/main/python/fusionauth/fusionauth_client.py index 041efaf..1e7670a 100644 --- a/src/main/python/fusionauth/fusionauth_client.py +++ b/src/main/python/fusionauth/fusionauth_client.py @@ -129,6 +129,23 @@ def change_password(self, change_password_id, request): .post() \ .go() + def change_password_by_jwt(self, encoded_jwt, request): + """ + Changes a user's password using their access token (JWT) instead of the changePasswordId + A common use case for this method will be if you want to allow the user to change their own password. + + Remember to send refreshToken in the request body if you want to get a new refresh token when login using the returned oneTimePassword. + + Attributes: + encoded_jwt: The encoded JWT (access token). + request: The change password request that contains all the information used to change the password. + """ + return self.start_anonymous().uri('/api/user/change-password') \ + .authorization("Bearer " + encoded_jwt) \ + .body_handler(JSONBodyHandler(request)) \ + .post() \ + .go() + def change_password_by_identity(self, request): """ Changes a user's password using their identity (loginId and password). Using a loginId instead of the changePasswordId From c9ca41dca445f74311da1291fdb2ba69e2f35c67 Mon Sep 17 00:00:00 2001 From: Spencer Witt <3409780+spwitt@users.noreply.github.com> Date: Mon, 16 Jun 2025 09:09:01 -0500 Subject: [PATCH 7/9] add /api/user/verify and request to clients (#44) --- src/main/python/fusionauth/fusionauth_client.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/main/python/fusionauth/fusionauth_client.py b/src/main/python/fusionauth/fusionauth_client.py index 1e7670a..4f34833 100644 --- a/src/main/python/fusionauth/fusionauth_client.py +++ b/src/main/python/fusionauth/fusionauth_client.py @@ -4889,6 +4889,18 @@ def verify_email_address_by_user_id(self, request): .post() \ .go() + def verify_identity(self, request): + """ + Administratively verify a user identity. + + Attributes: + request: The identity verify request that contains information to verify the identity. + """ + return self.start().uri('/api/identity/verify') \ + .body_handler(JSONBodyHandler(request)) \ + .post() \ + .go() + @deprecated("This method has been renamed to verify_user_registration and changed to take a JSON request body, use that method instead.") def verify_registration(self, verification_id): """ From ab29fdb513de639e5a0f9286aa115177db2ba72b Mon Sep 17 00:00:00 2001 From: Brady Wied Date: Thu, 24 Jul 2025 11:45:28 -0600 Subject: [PATCH 8/9] sb build follow up --- .../python/fusionauth/fusionauth_client.py | 114 ++++++++++-------- 1 file changed, 66 insertions(+), 48 deletions(-) diff --git a/src/main/python/fusionauth/fusionauth_client.py b/src/main/python/fusionauth/fusionauth_client.py index 4f34833..a8ad73f 100644 --- a/src/main/python/fusionauth/fusionauth_client.py +++ b/src/main/python/fusionauth/fusionauth_client.py @@ -1,5 +1,5 @@ # -# Copyright (c) 2018-2023, FusionAuth, All Rights Reserved +# Copyright (c) 2018-2025, FusionAuth, All Rights Reserved # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -129,6 +129,7 @@ def change_password(self, change_password_id, request): .post() \ .go() + @deprecated("This method has been renamed to change_password_using_jwt, use that method instead.") def change_password_by_jwt(self, encoded_jwt, request): """ Changes a user's password using their access token (JWT) instead of the changePasswordId @@ -160,6 +161,23 @@ def change_password_by_identity(self, request): .post() \ .go() + def change_password_using_jwt(self, encoded_jwt, request): + """ + Changes a user's password using their access token (JWT) instead of the changePasswordId + A common use case for this method will be if you want to allow the user to change their own password. + + Remember to send refreshToken in the request body if you want to get a new refresh token when login using the returned oneTimePassword. + + Attributes: + encoded_jwt: The encoded JWT (access token). + request: The change password request that contains all the information used to change the password. + """ + return self.start_anonymous().uri('/api/user/change-password') \ + .authorization("Bearer " + encoded_jwt) \ + .body_handler(JSONBodyHandler(request)) \ + .post() \ + .go() + def check_change_password_using_id(self, change_password_id): """ Check to see if the user must obtain a Trust Token Id in order to complete a change password request. @@ -760,7 +778,7 @@ def deactivate_user_action(self, user_action_id): @deprecated("This method has been renamed to deactivate_users_by_ids, use that method instead.") def deactivate_users(self, user_ids): """ - Deactivates the users with the given ids. + Deactivates the users with the given Ids. Attributes: user_ids: The ids of the users to deactivate. @@ -774,7 +792,7 @@ def deactivate_users(self, user_ids): def deactivate_users_by_ids(self, user_ids): """ - Deactivates the users with the given ids. + Deactivates the users with the given Ids. Attributes: user_ids: The ids of the users to deactivate. @@ -1217,8 +1235,8 @@ def delete_user_with_request(self, user_id, request): @deprecated("This method has been renamed to delete_users_by_query, use that method instead.") def delete_users(self, request): """ - Deletes the users with the given ids, or users matching the provided JSON query or queryString. - The order of preference is ids, query and then queryString, it is recommended to only provide one of the three for the request. + Deletes the users with the given Ids, or users matching the provided JSON query or queryString. + The order of preference is Ids, query and then queryString, it is recommended to only provide one of the three for the request. This method can be used to deactivate or permanently delete (hard-delete) users based upon the hardDelete boolean in the request body. Using the dryRun parameter you may also request the result of the action without actually deleting or deactivating any users. @@ -1233,8 +1251,8 @@ def delete_users(self, request): def delete_users_by_query(self, request): """ - Deletes the users with the given ids, or users matching the provided JSON query or queryString. - The order of preference is ids, query and then queryString, it is recommended to only provide one of the three for the request. + Deletes the users with the given Ids, or users matching the provided JSON query or queryString. + The order of preference is Ids, query and then queryString, it is recommended to only provide one of the three for the request. This method can be used to deactivate or permanently delete (hard-delete) users based upon the hardDelete boolean in the request body. Using the dryRun parameter you may also request the result of the action without actually deleting or deactivating any users. @@ -1756,7 +1774,7 @@ def modify_action(self, action_id, request): action. Attributes: - action_id: The Id of the action to modify. This is technically the user action log id. + action_id: The Id of the action to modify. This is technically the user action log Id. request: The request that contains all the information about the modification. """ return self.start().uri('/api/user/action') \ @@ -1779,16 +1797,16 @@ def passwordless_login(self, request): def patch_api_key(self, key_id, request): """ - Updates an authentication API key by given id + Updates an API key with the given Id. Attributes: - key_id: The Id of the authentication key. If not provided a secure random api key will be generated. - request: The request object that contains all the information needed to create the APIKey. + key_id: The Id of the API key. If not provided a secure random api key will be generated. + request: The request object that contains all the information needed to create the API key. """ return self.start().uri('/api/api-key') \ .url_segment(key_id) \ .body_handler(JSONBodyHandler(request)) \ - .post() \ + .patch() \ .go() def patch_application(self, application_id, request): @@ -2297,7 +2315,7 @@ def reindex(self, request): def remove_user_from_family(self, family_id, user_id): """ - Removes a user from the family with the given id. + Removes a user from the family with the given Id. Attributes: family_id: The Id of the family to remove the user from. @@ -2352,7 +2370,7 @@ def resend_registration_verification(self, email, application_id): def retrieve_api_key(self, key_id): """ - Retrieves an authentication API key for the given id + Retrieves an authentication API key for the given Id. Attributes: key_id: The Id of the API key to retrieve. @@ -2419,7 +2437,7 @@ def retrieve_application(self, application_id=None): Retrieves the application for the given Id or all the applications if the Id is null. Attributes: - application_id: (Optional) The application id. + application_id: (Optional) The application Id. """ return self.start().uri('/api/application') \ .url_segment(application_id) \ @@ -2494,11 +2512,11 @@ def retrieve_consents(self): def retrieve_daily_active_report(self, start, end, application_id=None): """ - Retrieves the daily active user report between the two instants. If you specify an application id, it will only + Retrieves the daily active user report between the two instants. If you specify an application Id, it will only return the daily active counts for that application. Attributes: - application_id: (Optional) The application id. + application_id: (Optional) The application Id. start: The start instant as UTC milliseconds since Epoch. end: The end instant as UTC milliseconds since Epoch. """ @@ -2511,7 +2529,7 @@ def retrieve_daily_active_report(self, start, end, application_id=None): def retrieve_email_template(self, email_template_id=None): """ - Retrieves the email template for the given Id. If you don't specify the id, this will return all the email templates. + Retrieves the email template for the given Id. If you don't specify the Id, this will return all the email templates. Attributes: email_template_id: (Optional) The Id of the email template. @@ -2894,11 +2912,11 @@ def retrieve_lambdas_by_type(self, _type): def retrieve_login_report(self, start, end, application_id=None): """ - Retrieves the login report between the two instants. If you specify an application id, it will only return the + Retrieves the login report between the two instants. If you specify an application Id, it will only return the login counts for that application. Attributes: - application_id: (Optional) The application id. + application_id: (Optional) The application Id. start: The start instant as UTC milliseconds since Epoch. end: The end instant as UTC milliseconds since Epoch. """ @@ -2911,7 +2929,7 @@ def retrieve_login_report(self, start, end, application_id=None): def retrieve_message_template(self, message_template_id=None): """ - Retrieves the message template for the given Id. If you don't specify the id, this will return all the message templates. + Retrieves the message template for the given Id. If you don't specify the Id, this will return all the message templates. Attributes: message_template_id: (Optional) The Id of the message template. @@ -2967,11 +2985,11 @@ def retrieve_messengers(self): def retrieve_monthly_active_report(self, start, end, application_id=None): """ - Retrieves the monthly active user report between the two instants. If you specify an application id, it will only + Retrieves the monthly active user report between the two instants. If you specify an application Id, it will only return the monthly active counts for that application. Attributes: - application_id: (Optional) The application id. + application_id: (Optional) The application Id. start: The start instant as UTC milliseconds since Epoch. end: The end instant as UTC milliseconds since Epoch. """ @@ -3133,7 +3151,7 @@ def retrieve_refresh_tokens(self, user_id): def retrieve_registration(self, user_id, application_id): """ - Retrieves the user registration for the user with the given Id and the given application id. + Retrieves the user registration for the user with the given Id and the given application Id. Attributes: user_id: The Id of the user. @@ -3147,11 +3165,11 @@ def retrieve_registration(self, user_id, application_id): def retrieve_registration_report(self, start, end, application_id=None): """ - Retrieves the registration report between the two instants. If you specify an application id, it will only return + Retrieves the registration report between the two instants. If you specify an application Id, it will only return the registration counts for that application. Attributes: - application_id: (Optional) The application id. + application_id: (Optional) The application Id. start: The start instant as UTC milliseconds since Epoch. end: The end instant as UTC milliseconds since Epoch. """ @@ -3313,7 +3331,7 @@ def retrieve_user(self, user_id): def retrieve_user_action(self, user_action_id=None): """ - Retrieves the user action for the given Id. If you pass in null for the id, this will return all the user + Retrieves the user action for the given Id. If you pass in null for the Id, this will return all the user actions. Attributes: @@ -3326,7 +3344,7 @@ def retrieve_user_action(self, user_action_id=None): def retrieve_user_action_reason(self, user_action_reason_id=None): """ - Retrieves the user action reason for the given Id. If you pass in null for the id, this will return all the user + Retrieves the user action reason for the given Id. If you pass in null for the Id, this will return all the user action reasons. Attributes: @@ -3440,8 +3458,8 @@ def retrieve_user_code(self, client_id, client_secret, user_code): This API is useful if you want to build your own login workflow to complete a device grant. Attributes: - client_id: The client id. - client_secret: The client id. + client_id: The client Id. + client_secret: The client Id. user_code: The end-user verification code. """ body = { @@ -3553,12 +3571,12 @@ def retrieve_user_links_by_user_id(self, user_id, identity_provider_id=None): def retrieve_user_login_report(self, user_id, start, end, application_id=None): """ - Retrieves the login report between the two instants for a particular user by Id. If you specify an application id, it will only return the + Retrieves the login report between the two instants for a particular user by Id. If you specify an application Id, it will only return the login counts for that application. Attributes: - application_id: (Optional) The application id. - user_id: The userId id. + application_id: (Optional) The application Id. + user_id: The userId Id. start: The start instant as UTC milliseconds since Epoch. end: The end instant as UTC milliseconds since Epoch. """ @@ -3572,12 +3590,12 @@ def retrieve_user_login_report(self, user_id, start, end, application_id=None): def retrieve_user_login_report_by_login_id(self, login_id, start, end, application_id=None): """ - Retrieves the login report between the two instants for a particular user by login Id. If you specify an application id, it will only return the + Retrieves the login report between the two instants for a particular user by login Id. If you specify an application Id, it will only return the login counts for that application. Attributes: - application_id: (Optional) The application id. - login_id: The userId id. + application_id: (Optional) The application Id. + login_id: The userId Id. start: The start instant as UTC milliseconds since Epoch. end: The end instant as UTC milliseconds since Epoch. """ @@ -3674,7 +3692,7 @@ def retrieve_web_authn_credentials_for_user(self, user_id): def retrieve_webhook(self, webhook_id=None): """ - Retrieves the webhook for the given Id. If you pass in null for the id, this will return all the webhooks. + Retrieves the webhook for the given Id. If you pass in null for the Id, this will return all the webhooks. Attributes: webhook_id: (Optional) The Id of the webhook. @@ -3906,7 +3924,7 @@ def search_entities(self, request): def search_entities_by_ids(self, ids): """ - Retrieves the entities for the given ids. If any Id is invalid, it is ignored. + Retrieves the entities for the given Ids. If any Id is invalid, it is ignored. Attributes: ids: The entity ids to search for. @@ -4075,7 +4093,7 @@ def search_user_comments(self, request): @deprecated("This method has been renamed to search_users_by_ids, use that method instead.") def search_users(self, ids): """ - Retrieves the users for the given ids. If any Id is invalid, it is ignored. + Retrieves the users for the given Ids. If any Id is invalid, it is ignored. Attributes: ids: The user ids to search for. @@ -4087,10 +4105,10 @@ def search_users(self, ids): def search_users_by_ids(self, ids): """ - Retrieves the users for the given ids. If any Id is invalid, it is ignored. + Retrieves the users for the given Ids. If any Id is invalid, it is ignored. Attributes: - ids: The user ids to search for. + ids: The user Ids to search for. """ return self.start().uri('/api/user/search') \ .url_parameter('ids', self.convert_true_false(ids)) \ @@ -4150,7 +4168,7 @@ def search_webhooks(self, request): def send_email(self, email_template_id, request): """ - Send an email using an email template id. You can optionally provide requestData to access key value + Send an email using an email template Id. You can optionally provide requestData to access key value pairs in the email template. Attributes: @@ -4343,16 +4361,16 @@ def two_factor_login(self, request): .post() \ .go() - def update_api_key(self, api_key_id, request): + def update_api_key(self, key_id, request): """ - Updates an API key by given id + Updates an API key with the given Id. Attributes: - api_key_id: The Id of the API key to update. - request: The request object that contains all the information used to create the API Key. + key_id: The Id of the API key to update. + request: The request that contains all the new API key information. """ return self.start().uri('/api/api-key') \ - .url_segment(api_key_id) \ + .url_segment(key_id) \ .body_handler(JSONBodyHandler(request)) \ .put() \ .go() @@ -4802,7 +4820,7 @@ def validate_device(self, user_code, client_id): Attributes: user_code: The end-user verification code. - client_id: The client id. + client_id: The client Id. """ return self.start_anonymous().uri('/oauth2/device/validate') \ .url_parameter('user_code', self.convert_true_false(user_code)) \ From f13449536eb9cf7bf4ecac2e0de999c836adc611 Mon Sep 17 00:00:00 2001 From: Brady Wied Date: Wed, 13 Aug 2025 11:33:40 -0600 Subject: [PATCH 9/9] tenant manager test --- .../python/fusionauth/fusionauth_client_test.py | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/test/python/fusionauth/fusionauth_client_test.py b/src/test/python/fusionauth/fusionauth_client_test.py index 8f7545c..0700681 100644 --- a/src/test/python/fusionauth/fusionauth_client_test.py +++ b/src/test/python/fusionauth/fusionauth_client_test.py @@ -35,6 +35,18 @@ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, # either express or implied. See the License for the specific # language governing permissions and limitations under the License. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +# either express or implied. See the License for the specific +# language governing permissions and limitations under the License. import json import os @@ -62,7 +74,8 @@ def runTest(self): def test_retrieve_applications(self): client_response = self.client.retrieve_applications() self.assertEqual(client_response.status, 200) - self.assertEqual(len(client_response.success_response['applications']), 2) + # tnent manager is 1 application, admin is another, Pied piper in the kickstart is the 3rd. + self.assertEqual(len(client_response.success_response['applications']), 3) def test_create_user_retrieve_user(self): # Check if the user already exists.