From 8dee0de2379de40e598e35daa514d1abfdf380ba Mon Sep 17 00:00:00 2001 From: Gil Shapira Date: Mon, 25 Nov 2024 14:09:13 +0200 Subject: [PATCH] Add support for overriding messaging template in magic link, enchanted link, and OTP messages (#462) --- descope/authmethod/enchantedlink.py | 1 + descope/authmethod/magiclink.py | 1 + descope/authmethod/otp.py | 1 + descope/common.py | 25 ++++++++++++++++++------- tests/test_enchantedlink.py | 7 ++++++- tests/test_magiclink.py | 17 ++++++++++++----- tests/test_otp.py | 15 +++++++++++---- 7 files changed, 50 insertions(+), 17 deletions(-) diff --git a/descope/authmethod/enchantedlink.py b/descope/authmethod/enchantedlink.py index a9419ef0..28d133c3 100644 --- a/descope/authmethod/enchantedlink.py +++ b/descope/authmethod/enchantedlink.py @@ -71,6 +71,7 @@ def sign_up_or_in( login_options = LoginOptions( custom_claims=signup_options.customClaims, template_options=signup_options.templateOptions, + template_id=signup_options.templateId, ) body = EnchantedLink._compose_signin_body( diff --git a/descope/authmethod/magiclink.py b/descope/authmethod/magiclink.py index a8688d25..5d1d7ed5 100644 --- a/descope/authmethod/magiclink.py +++ b/descope/authmethod/magiclink.py @@ -77,6 +77,7 @@ def sign_up_or_in( login_options = LoginOptions( custom_claims=signup_options.customClaims, template_options=signup_options.templateOptions, + template_id=signup_options.templateId, ) body = MagicLink._compose_signin_body( login_id, diff --git a/descope/authmethod/otp.py b/descope/authmethod/otp.py index d5a0862b..421d8a58 100644 --- a/descope/authmethod/otp.py +++ b/descope/authmethod/otp.py @@ -118,6 +118,7 @@ def sign_up_or_in( login_options = LoginOptions( custom_claims=signup_options.customClaims, template_options=signup_options.templateOptions, + template_id=signup_options.templateId, ) body = OTP._compose_signin_body( login_id, diff --git a/descope/common.py b/descope/common.py index c8501363..0926894c 100644 --- a/descope/common.py +++ b/descope/common.py @@ -1,5 +1,5 @@ from enum import Enum -from typing import Optional +from typing import Any, Optional from descope.exceptions import ERROR_TYPE_INVALID_ARGUMENT, AuthException @@ -111,11 +111,14 @@ def __init__( self, stepup: bool = False, mfa: bool = False, - revoke_other_sessions: Optional[None] = None, + revoke_other_sessions: Optional[bool] = None, custom_claims: Optional[dict] = None, template_options: Optional[ dict ] = None, # for providing messaging template options (templates that are being sent via email / text message) + template_id: Optional[ + str + ] = None, # for overriding the default template (templates that are being sent via email / text message) ): self.stepup = stepup self.customClaims = custom_claims @@ -124,6 +127,8 @@ def __init__( self.revokeOtherSessions = revoke_other_sessions if template_options is not None: self.templateOptions = template_options + if template_id is not None: + self.templateId = template_id class AccessKeyLoginOptions: @@ -152,24 +157,30 @@ def validate_refresh_token_provided( class SignUpOptions: def __init__( self, - revoke_other_sessions: Optional[None] = None, + revoke_other_sessions: Optional[bool] = None, custom_claims: Optional[dict] = None, template_options: Optional[ dict ] = None, # for providing messaging template options (templates that are being sent via email / text message) + template_id: Optional[ + str + ] = None, # for overriding the default template (templates that are being sent via email / text message) ): - self.revoke_other_sessions = revoke_other_sessions + self.revokeOtherSessions = revoke_other_sessions self.customClaims = custom_claims self.templateOptions = template_options + self.templateId = template_id def signup_options_to_dict(signup_options: Optional[SignUpOptions] = None) -> dict: - res = {} + res: dict[str, Any] = {} if signup_options is not None: if signup_options.customClaims is not None: res["customClaims"] = signup_options.customClaims + if signup_options.templateId is not None: + res["templateId"] = signup_options.templateId if signup_options.templateOptions is not None: res["templateOptions"] = signup_options.templateOptions - if signup_options.revoke_other_sessions is not None: - res["revokeOtherSessions"] = signup_options.revoke_other_sessions + if signup_options.revokeOtherSessions is not None: + res["revokeOtherSessions"] = signup_options.revokeOtherSessions return res diff --git a/tests/test_enchantedlink.py b/tests/test_enchantedlink.py index 8f5757c2..fdc1e96e 100644 --- a/tests/test_enchantedlink.py +++ b/tests/test_enchantedlink.py @@ -165,6 +165,7 @@ def test_sign_in(self): LoginOptions( stepup=True, template_options={"blue": "bla"}, + template_id="foo", revoke_other_sessions=True, ), refresh_token=refresh_token, @@ -183,6 +184,7 @@ def test_sign_in(self): "stepup": True, "customClaims": None, "templateOptions": {"blue": "bla"}, + "templateId": "foo", "revokeOtherSessions": True, "mfa": False, }, @@ -304,7 +306,9 @@ def test_sign_up(self): "http://test.me", None, SignUpOptions( - template_options={"bla": "blue"}, revoke_other_sessions=True + template_options={"bla": "blue"}, + template_id="foo", + revoke_other_sessions=True, ), ) mock_post.assert_called_with( @@ -321,6 +325,7 @@ def test_sign_up(self): "email": "dummy@dummy.com", "loginOptions": { "templateOptions": {"bla": "blue"}, + "templateId": "foo", "revokeOtherSessions": True, }, }, diff --git a/tests/test_magiclink.py b/tests/test_magiclink.py index c754072e..a9775cb3 100644 --- a/tests/test_magiclink.py +++ b/tests/test_magiclink.py @@ -60,7 +60,7 @@ def test_compose_body(self): }, ) - lo = LoginOptions(stepup=True, custom_claims={"k1": "v1"}) + lo = LoginOptions(stepup=True, custom_claims={"k1": "v1"}, template_id="foo") self.assertEqual( MagicLink._compose_signin_body("id1", "uri1", lo), { @@ -70,6 +70,7 @@ def test_compose_body(self): "stepup": True, "mfa": False, "customClaims": {"k1": "v1"}, + "templateId": "foo", }, }, ) @@ -193,7 +194,9 @@ def test_sign_in(self): DeliveryMethod.EMAIL, "dummy@dummy.com", "http://test.me", - LoginOptions(stepup=True, template_options={"blue": "bla"}), + LoginOptions( + stepup=True, template_options={"blue": "bla"}, template_id=None + ), refresh_token=refresh_token, ) mock_post.assert_called_with( @@ -274,7 +277,7 @@ def test_sign_up(self): "dummy@dummy.com", "http://test.me", signup_user_details, - SignUpOptions(template_options={"bla": "blue"}), + SignUpOptions(template_options={"bla": "blue"}, template_id="foo"), ) self.assertEqual("t***@example.com", resp) @@ -294,7 +297,10 @@ def test_sign_up(self): "email": "dummy@dummy.com", }, "email": "dummy@dummy.com", - "loginOptions": {"templateOptions": {"bla": "blue"}}, + "loginOptions": { + "templateOptions": {"bla": "blue"}, + "templateId": "foo", + }, }, allow_redirects=False, verify=True, @@ -420,7 +426,7 @@ def test_sign_up_or_in(self): DeliveryMethod.EMAIL, "dummy@dummy.com", "http://test.me", - SignUpOptions(template_options={"bla": "blue"}), + SignUpOptions(template_options={"bla": "blue"}, template_id="foo"), ), ) mock_post.assert_called_with( @@ -437,6 +443,7 @@ def test_sign_up_or_in(self): "customClaims": None, "mfa": False, "templateOptions": {"bla": "blue"}, + "templateId": "foo", }, }, allow_redirects=False, diff --git a/tests/test_otp.py b/tests/test_otp.py index 0d0b62da..3608f4f6 100644 --- a/tests/test_otp.py +++ b/tests/test_otp.py @@ -258,7 +258,7 @@ def test_sign_up(self): DeliveryMethod.EMAIL, "dummy@dummy.com", signup_user_details, - SignUpOptions(template_options={"bla": "blue"}), + SignUpOptions(template_options={"bla": "blue"}, template_id="foo"), ), ) mock_post.assert_called_with( @@ -277,7 +277,10 @@ def test_sign_up(self): "email": "dummy@dummy.com", }, "email": "dummy@dummy.com", - "loginOptions": {"templateOptions": {"bla": "blue"}}, + "loginOptions": { + "templateOptions": {"bla": "blue"}, + "templateId": "foo", + }, }, allow_redirects=False, verify=True, @@ -386,7 +389,9 @@ def test_sign_in(self): client.otp.sign_in( DeliveryMethod.EMAIL, "dummy@dummy.com", - LoginOptions(stepup=True, template_options={"blue": "bla"}), + LoginOptions( + stepup=True, template_options={"blue": "bla"}, template_id="foo" + ), refresh_token=refresh_token, ) mock_post.assert_called_with( @@ -402,6 +407,7 @@ def test_sign_in(self): "stepup": True, "customClaims": None, "templateOptions": {"blue": "bla"}, + "templateId": "foo", "mfa": False, }, }, @@ -449,7 +455,7 @@ def test_sign_up_or_in(self): client.otp.sign_up_or_in( DeliveryMethod.EMAIL, "dummy@dummy.com", - SignUpOptions(template_options={"bla": "blue"}), + SignUpOptions(template_options={"bla": "blue"}, template_id="foo"), ), ) mock_post.assert_called_with( @@ -465,6 +471,7 @@ def test_sign_up_or_in(self): "customClaims": None, "mfa": False, "templateOptions": {"bla": "blue"}, + "templateId": "foo", }, }, allow_redirects=False,