Skip to content

Commit 0248eda

Browse files
authored
Merge pull request #383 from supertokens/fix/ev-sendemail
fix: Emailverification send email functions with multitenancy
2 parents 90846ef + 3d47c46 commit 0248eda

File tree

4 files changed

+142
-44
lines changed

4 files changed

+142
-44
lines changed

supertokens_python/recipe/dashboard/api/userdetails/user_email_verify_token_post.py

Lines changed: 5 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -2,28 +2,15 @@
22

33
from supertokens_python.exceptions import raise_bad_input_exception
44
from supertokens_python.recipe.emailverification.asyncio import (
5-
create_email_verification_token,
6-
send_email,
5+
send_email_verification_email,
6+
SendEmailVerificationEmailAlreadyVerifiedError,
77
)
8-
from supertokens_python.recipe.emailverification.interfaces import (
9-
CreateEmailVerificationTokenEmailAlreadyVerifiedError,
10-
CreateEmailVerificationTokenOkResult,
11-
)
12-
from supertokens_python.recipe.emailverification.recipe import (
13-
EmailVerificationRecipe,
14-
GetEmailForUserIdOkResult,
15-
)
16-
from supertokens_python.recipe.emailverification.types import (
17-
VerificationEmailTemplateVars,
18-
VerificationEmailTemplateVarsUser,
19-
)
20-
from supertokens_python.recipe.emailverification.utils import get_email_verify_link
218

229
from ...interfaces import (
2310
APIInterface,
2411
APIOptions,
25-
UserEmailVerifyTokenPostAPIEmailAlreadyVerifiedErrorResponse,
2612
UserEmailVerifyTokenPostAPIOkResponse,
13+
UserEmailVerifyTokenPostAPIEmailAlreadyVerifiedErrorResponse,
2714
)
2815

2916

@@ -44,34 +31,9 @@ async def handle_email_verify_token_post(
4431
"Required parameter 'userId' is missing or has an invalid type"
4532
)
4633

47-
email_response = await EmailVerificationRecipe.get_instance().get_email_for_user_id(
48-
user_id, user_context
49-
)
50-
51-
if not isinstance(email_response, GetEmailForUserIdOkResult):
52-
raise Exception("Should not come here")
34+
res = await send_email_verification_email(user_id, None, tenant_id, user_context)
5335

54-
email_verification_token = await create_email_verification_token(
55-
user_id, tenant_id=tenant_id, user_context=user_context
56-
)
57-
58-
if isinstance(
59-
email_verification_token, CreateEmailVerificationTokenEmailAlreadyVerifiedError
60-
):
36+
if isinstance(res, SendEmailVerificationEmailAlreadyVerifiedError):
6137
return UserEmailVerifyTokenPostAPIEmailAlreadyVerifiedErrorResponse()
6238

63-
assert isinstance(email_verification_token, CreateEmailVerificationTokenOkResult)
64-
65-
email_verify_link = get_email_verify_link(
66-
api_options.app_info, email_verification_token.token, user_id, tenant_id
67-
)
68-
69-
await send_email(
70-
VerificationEmailTemplateVars(
71-
user=VerificationEmailTemplateVarsUser(user_id, email_response.email),
72-
email_verify_link=email_verify_link,
73-
tenant_id=tenant_id,
74-
)
75-
)
76-
7739
return UserEmailVerifyTokenPostAPIOkResponse()

supertokens_python/recipe/emailverification/asyncio/__init__.py

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@
1616
GetEmailForUserIdOkResult,
1717
EmailDoesNotExistError,
1818
CreateEmailVerificationTokenEmailAlreadyVerifiedError,
19+
CreateEmailVerificationLinkOkResult,
20+
CreateEmailVerificationLinkEmailAlreadyVerifiedError,
21+
SendEmailVerificationEmailOkResult,
22+
SendEmailVerificationEmailAlreadyVerifiedError,
1923
UnverifyEmailOkResult,
2024
CreateEmailVerificationTokenOkResult,
2125
RevokeEmailVerificationTokensOkResult,
@@ -25,6 +29,12 @@
2529

2630
from supertokens_python.recipe.multitenancy.constants import DEFAULT_TENANT_ID
2731

32+
from supertokens_python.recipe.emailverification.utils import get_email_verify_link
33+
from supertokens_python.recipe.emailverification.types import (
34+
VerificationEmailTemplateVars,
35+
VerificationEmailTemplateVarsUser,
36+
)
37+
2838

2939
async def create_email_verification_token(
3040
user_id: str,
@@ -145,3 +155,80 @@ async def send_email(
145155
return await EmailVerificationRecipe.get_instance().email_delivery.ingredient_interface_impl.send_email(
146156
input_, user_context
147157
)
158+
159+
160+
async def create_email_verification_link(
161+
user_id: str,
162+
email: Optional[str],
163+
tenant_id: Optional[str] = None,
164+
user_context: Optional[Dict[str, Any]] = None,
165+
) -> Union[
166+
CreateEmailVerificationLinkOkResult,
167+
CreateEmailVerificationLinkEmailAlreadyVerifiedError,
168+
]:
169+
if user_context is None:
170+
user_context = {}
171+
172+
recipe_instance = EmailVerificationRecipe.get_instance()
173+
app_info = recipe_instance.get_app_info()
174+
175+
email_verification_token = await create_email_verification_token(
176+
user_id, email, tenant_id, user_context
177+
)
178+
if isinstance(
179+
email_verification_token, CreateEmailVerificationTokenEmailAlreadyVerifiedError
180+
):
181+
return CreateEmailVerificationLinkEmailAlreadyVerifiedError()
182+
183+
return CreateEmailVerificationLinkOkResult(
184+
link=get_email_verify_link(
185+
app_info,
186+
email_verification_token.token,
187+
recipe_instance.get_recipe_id(),
188+
tenant_id or DEFAULT_TENANT_ID,
189+
)
190+
)
191+
192+
193+
async def send_email_verification_email(
194+
user_id: str,
195+
email: Optional[str],
196+
tenant_id: Optional[str] = None,
197+
user_context: Optional[Dict[str, Any]] = None,
198+
) -> Union[
199+
SendEmailVerificationEmailOkResult,
200+
SendEmailVerificationEmailAlreadyVerifiedError,
201+
]:
202+
if user_context is None:
203+
user_context = {}
204+
205+
if email is None:
206+
recipe_instance = EmailVerificationRecipe.get_instance()
207+
208+
email_info = await recipe_instance.get_email_for_user_id(user_id, user_context)
209+
if isinstance(email_info, GetEmailForUserIdOkResult):
210+
email = email_info.email
211+
elif isinstance(email_info, EmailDoesNotExistError):
212+
return SendEmailVerificationEmailAlreadyVerifiedError()
213+
else:
214+
raise Exception("Unknown User ID provided without email")
215+
216+
email_verification_link = await create_email_verification_link(
217+
user_id, email, tenant_id, user_context
218+
)
219+
220+
if isinstance(
221+
email_verification_link, CreateEmailVerificationLinkEmailAlreadyVerifiedError
222+
):
223+
return SendEmailVerificationEmailAlreadyVerifiedError()
224+
225+
await send_email(
226+
VerificationEmailTemplateVars(
227+
user=VerificationEmailTemplateVarsUser(user_id, email),
228+
email_verify_link=email_verification_link.link,
229+
tenant_id=tenant_id,
230+
),
231+
user_context,
232+
)
233+
234+
return SendEmailVerificationEmailOkResult()

supertokens_python/recipe/emailverification/interfaces.py

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,15 +30,38 @@
3030

3131

3232
class CreateEmailVerificationTokenOkResult:
33+
status = "OK"
34+
3335
def __init__(self, token: str):
3436
self.token = token
3537

3638

3739
class CreateEmailVerificationTokenEmailAlreadyVerifiedError:
38-
pass
40+
status = "EMAIL_ALREADY_VERIFIED_ERROR"
41+
42+
43+
class CreateEmailVerificationLinkEmailAlreadyVerifiedError:
44+
status = "EMAIL_ALREADY_VERIFIED_ERROR"
45+
46+
47+
class CreateEmailVerificationLinkOkResult:
48+
status = "OK"
49+
50+
def __init__(self, link: str):
51+
self.link = link
52+
53+
54+
class SendEmailVerificationEmailAlreadyVerifiedError:
55+
status = "EMAIL_ALREADY_VERIFIED_ERROR"
56+
57+
58+
class SendEmailVerificationEmailOkResult:
59+
status = "OK"
3960

4061

4162
class VerifyEmailUsingTokenOkResult:
63+
status = "OK"
64+
4265
def __init__(self, user: User):
4366
self.user = user
4467

supertokens_python/recipe/emailverification/syncio/__init__.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,3 +87,29 @@ def send_email(
8787
from supertokens_python.recipe.emailverification.asyncio import send_email
8888

8989
return sync(send_email(input_, user_context))
90+
91+
92+
def create_email_verification_link(
93+
user_id: str,
94+
email: Optional[str],
95+
tenant_id: Optional[str] = None,
96+
user_context: Optional[Dict[str, Any]] = None,
97+
):
98+
from supertokens_python.recipe.emailverification.asyncio import (
99+
create_email_verification_link,
100+
)
101+
102+
return sync(create_email_verification_link(user_id, email, tenant_id, user_context))
103+
104+
105+
def send_email_verification_email(
106+
user_id: str,
107+
email: Optional[str],
108+
tenant_id: Optional[str] = None,
109+
user_context: Optional[Dict[str, Any]] = None,
110+
):
111+
from supertokens_python.recipe.emailverification.asyncio import (
112+
send_email_verification_email,
113+
)
114+
115+
return sync(send_email_verification_email(user_id, email, tenant_id, user_context))

0 commit comments

Comments
 (0)