Skip to content

feat: Add and use email verification claim #215

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

Merged
merged 19 commits into from
Sep 5, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
a7e4b6a
feat: Add and use email verification claim
KShivendu Aug 7, 2022
918e15f
feat: Add and use email verification claim
KShivendu Aug 7, 2022
07fe952
fix: Fix lint errors and make email verification claims usable
KShivendu Aug 8, 2022
29d7cee
refactor: Use email veriifcation claim in thirdparty recipe
KShivendu Aug 9, 2022
6957000
refactor: Run black on tp recipe and use ev claim in pless recipe
KShivendu Aug 9, 2022
44d0f3a
refactor: Remove email verification features from thirdpartyemailpass…
KShivendu Aug 9, 2022
720f593
refactor: Remove email verification features from thirdpartypasswordl…
KShivendu Aug 9, 2022
e31b60d
refactor: Clean up usages of email verification in other recipes in f…
KShivendu Aug 10, 2022
0834fe5
refactor: Fix circular dependency error in emailverification recipe a…
KShivendu Aug 10, 2022
34e492a
test: Fix test failures related to tpep recipe
KShivendu Aug 10, 2022
1586251
refactor: Allow emailverification init without directly using ParentR…
KShivendu Aug 10, 2022
10395c4
tests: Fix test failures in tppless email delivery
KShivendu Aug 10, 2022
27282d4
changes based on feedback
KShivendu Aug 17, 2022
3df9f16
Remove get_link_domain_and_path function and ev logic from other recipes
KShivendu Aug 17, 2022
63eb59b
Merge branch 'feat/session-grants' into feat/ev-claim
KShivendu Sep 1, 2022
619ac25
feat: Changes suggested in feedback
KShivendu Sep 1, 2022
5b36b16
refactor: Remove ParentRecipeEmailVerificationConfig
KShivendu Sep 1, 2022
01c2609
test: Fix failing tests
KShivendu Sep 1, 2022
6fc90c6
refactor: Remove irrelevant comment
KShivendu Sep 1, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions supertokens_python/post_init_callbacks.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
from typing import Callable, List


class PostSTInitCallbacks:
"""Callbacks that are called after the SuperTokens instance is initialized."""

callbacks: List[Callable[[], None]] = []

@staticmethod
def add_post_init_callback(cb: Callable[[], None]) -> None:
PostSTInitCallbacks.callbacks.append(cb)

@staticmethod
def run_post_init_callbacks() -> None:
for cb in PostSTInitCallbacks.callbacks:
cb()

PostSTInitCallbacks.callbacks = []
3 changes: 0 additions & 3 deletions supertokens_python/recipe/emailpassword/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@
exceptions = ex
InputOverrideConfig = utils.InputOverrideConfig
InputResetPasswordUsingTokenFeature = utils.InputResetPasswordUsingTokenFeature
InputEmailVerificationConfig = utils.InputEmailVerificationConfig
InputSignUpFeature = utils.InputSignUpFeature
InputFormField = utils.InputFormField
SMTPService = emaildelivery_services.SMTPService
Expand All @@ -42,14 +41,12 @@ def init(
reset_password_using_token_feature: Union[
utils.InputResetPasswordUsingTokenFeature, None
] = None,
email_verification_feature: Union[utils.InputEmailVerificationConfig, None] = None,
override: Union[utils.InputOverrideConfig, None] = None,
email_delivery: Union[EmailDeliveryConfig[EmailTemplateVars], None] = None,
) -> Callable[[AppInfo], RecipeModule]:
return EmailPasswordRecipe.init(
sign_up_feature,
reset_password_using_token_feature,
email_verification_feature,
override,
email_delivery,
)
7 changes: 3 additions & 4 deletions supertokens_python/recipe/emailpassword/api/implementation.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,10 +92,9 @@ async def generate_password_reset_token_post(

token = token_result.token
password_reset_link = (
await api_options.config.reset_password_using_token_feature.get_reset_password_url(
user, user_context
)
+ "?token="
api_options.app_info.website_domain.get_as_string_dangerous()
+ api_options.app_info.website_base_path.get_as_string_dangerous()
+ "/reset-password?token="
+ token
+ "&rid="
+ api_options.recipe_id
Expand Down
62 changes: 0 additions & 62 deletions supertokens_python/recipe/emailpassword/asyncio/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,55 +18,6 @@
from ..types import EmailTemplateVars, User


async def create_email_verification_token(
user_id: str, user_context: Union[None, Dict[str, Any]] = None
):
if user_context is None:
user_context = {}
email = await EmailPasswordRecipe.get_instance().get_email_for_user_id(
user_id, user_context
)
return await EmailPasswordRecipe.get_instance().email_verification_recipe.recipe_implementation.create_email_verification_token(
user_id, email, user_context
)


async def verify_email_using_token(
token: str, user_context: Union[None, Dict[str, Any]] = None
):
if user_context is None:
user_context = {}
return await EmailPasswordRecipe.get_instance().email_verification_recipe.recipe_implementation.verify_email_using_token(
token, user_context
)


async def unverify_email(
user_id: str, user_context: Union[None, Dict[str, Any]] = None
):
if user_context is None:
user_context = {}
email = await EmailPasswordRecipe.get_instance().get_email_for_user_id(
user_id, user_context
)
return await EmailPasswordRecipe.get_instance().email_verification_recipe.recipe_implementation.unverify_email(
user_id, email, user_context
)


async def is_email_verified(
user_id: str, user_context: Union[None, Dict[str, Any]] = None
):
if user_context is None:
user_context = {}
email = await EmailPasswordRecipe.get_instance().get_email_for_user_id(
user_id, user_context
)
return await EmailPasswordRecipe.get_instance().email_verification_recipe.recipe_implementation.is_email_verified(
user_id, email, user_context
)


async def update_email_or_password(
user_id: str,
email: Union[str, None] = None,
Expand Down Expand Up @@ -142,19 +93,6 @@ async def sign_up(
)


async def revoke_email_verification_token(
user_id: str, user_context: Union[None, Dict[str, Any]] = None
):
if user_context is None:
user_context = {}
email = await EmailPasswordRecipe.get_instance().get_email_for_user_id(
user_id, user_context
)
return await EmailPasswordRecipe.get_instance().email_verification_recipe.recipe_implementation.revoke_email_verification_tokens(
user_id, email, user_context
)


async def send_email(
input_: EmailTemplateVars, user_context: Union[None, Dict[str, Any]] = None
):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,20 +25,12 @@
)
from supertokens_python.recipe.emailpassword.types import (
User,
VerificationEmailTemplateVars,
)
from supertokens_python.recipe.emailverification.emaildelivery.services.backward_compatibility import (
BackwardCompatibilityService as EmailVerificationBackwardCompatibilityService,
)
from supertokens_python.recipe.emailverification.types import (
User as EmailVerificationUser,
)
from supertokens_python.supertokens import AppInfo
from supertokens_python.utils import handle_httpx_client_exceptions

if TYPE_CHECKING:
from supertokens_python.recipe.emailpassword.utils import (
InputEmailVerificationConfig,
InputResetPasswordUsingTokenFeature,
)

Expand Down Expand Up @@ -68,7 +60,6 @@ async def func(user: User, password_reset_url_with_token: str, _: Dict[str, Any]

class BackwardCompatibilityService(EmailDeliveryInterface[EmailTemplateVars]):
app_info: AppInfo
ev_backward_compatibility_service: EmailVerificationBackwardCompatibilityService

def __init__(
self,
Expand All @@ -77,7 +68,6 @@ def __init__(
reset_password_using_token_feature: Union[
InputResetPasswordUsingTokenFeature, None
] = None,
email_verification_feature: Union[InputEmailVerificationConfig, None] = None,
) -> None:
self.recipe_interface_impl = recipe_interface_impl

Expand All @@ -97,55 +87,18 @@ def __init__(
reset_password_feature_send_email_func
)

create_and_send_custom_email: Union[
Callable[[EmailVerificationUser, str, Dict[str, Any]], Awaitable[None]],
None,
] = None
if email_verification_feature:
if email_verification_feature.create_and_send_custom_email is not None:
ev_create_and_send_custom_email = (
email_verification_feature.create_and_send_custom_email
)

async def create_and_send_custom_email_wrapper(
user: EmailVerificationUser, link: str, user_context: Dict[str, Any]
):
user_info = await recipe_interface_impl.get_user_by_id(
user.user_id, user_context
)
if user_info is None:
raise Exception("Unknown User ID provided")

return await ev_create_and_send_custom_email(
user_info, link, user_context
)

create_and_send_custom_email = create_and_send_custom_email_wrapper

self.ev_backward_compatibility_service = (
EmailVerificationBackwardCompatibilityService(
app_info, create_and_send_custom_email=create_and_send_custom_email
)
)

async def send_email(
self, template_vars: EmailTemplateVars, user_context: Dict[str, Any]
) -> None:
if isinstance(template_vars, VerificationEmailTemplateVars):
await self.ev_backward_compatibility_service.send_email(
template_vars, user_context
)
else:
user = await self.recipe_interface_impl.get_user_by_id(
user_id=template_vars.user.id, user_context=user_context
)

if user is None:
raise Exception("Should never come here")
user = await self.recipe_interface_impl.get_user_by_id(
user_id=template_vars.user.id, user_context=user_context
)
if user is None:
raise Exception("Should never come here")

try:
await self.reset_password_feature_send_email_func(
user, template_vars.password_reset_link, user_context
)
except Exception:
pass
try:
await self.reset_password_feature_send_email_func(
user, template_vars.password_reset_link, user_context
)
except Exception:
pass
Original file line number Diff line number Diff line change
Expand Up @@ -24,17 +24,8 @@
EmailTemplateVars,
SMTPOverrideInput,
)
from supertokens_python.recipe.emailverification.emaildelivery.services.smtp import (
SMTPService as EmailVerificationSMTPService,
)
from supertokens_python.recipe.emailverification.types import (
VerificationEmailTemplateVars,
)

from .service_implementation import ServiceImplementation
from .service_implementation.email_verification_implementation import (
ServiceImplementation as EmailVerificationServiceImpl,
)


class SMTPService(EmailDeliveryInterface[EmailTemplateVars]):
Expand All @@ -50,21 +41,9 @@ def __init__(
oi = ServiceImplementation(transporter)
self.service_implementation = oi if override is None else override(oi)

self.email_verification_smtp_service = EmailVerificationSMTPService(
smtp_settings=smtp_settings,
override=lambda _: EmailVerificationServiceImpl(
self.service_implementation
),
)

async def send_email(
self, template_vars: EmailTemplateVars, user_context: Dict[str, Any]
) -> None:
if isinstance(template_vars, VerificationEmailTemplateVars):
return await self.email_verification_smtp_service.send_email(
template_vars, user_context
)

content = await self.service_implementation.get_content(
template_vars, user_context
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,6 @@
from supertokens_python.recipe.emailverification.emaildelivery.services.smtp.service_implementation import (
ServiceImplementation as EVServiceImplementation,
)
from supertokens_python.recipe.emailverification.types import (
VerificationEmailTemplateVars,
)

from .email_verification_implementation import (
ServiceImplementation as DerivedEVServiceImplementation,
)


class ServiceImplementation(SMTPServiceInterface[EmailTemplateVars]):
Expand All @@ -45,14 +38,6 @@ def __init__(self, transporter: Transporter) -> None:
)
self.ev_get_content = email_verification_service_implementation.get_content

derived_ev_service_implementation = DerivedEVServiceImplementation(self)
email_verification_service_implementation.send_raw_email = (
derived_ev_service_implementation.send_raw_email
)
email_verification_service_implementation.get_content = (
derived_ev_service_implementation.get_content
)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need to also modify the get_content function below -> how come pyright did not complain about the unnecessary check of if isinstance(template_vars, VerificationEmailTemplateVars):?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

async def send_raw_email(
self, content: EmailContent, user_context: Dict[str, Any]
) -> None:
Expand All @@ -61,6 +46,4 @@ async def send_raw_email(
async def get_content(
self, template_vars: EmailTemplateVars, user_context: Dict[str, Any]
) -> EmailContent:
if isinstance(template_vars, VerificationEmailTemplateVars):
return await self.ev_get_content(template_vars, user_context)
return get_password_reset_email_content(template_vars)

This file was deleted.

Loading