Skip to content
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

feat: allow users update their account email address with proper validation. #4520

Draft
wants to merge 19 commits into
base: main
Choose a base branch
from

Conversation

apsinghdev
Copy link
Contributor

fixes: #4237

This PR implements the feature to allow users to update their email. (Draft)

Copy link

vercel bot commented Nov 22, 2024

@apsinghdev is attempting to deploy a commit to the polar-sh Team on Vercel.

A member of the Team first needs to authorize it.

@apsinghdev apsinghdev changed the title Feat/allow email update feat: allow users update their account email address with proper validation. Nov 22, 2024
@apsinghdev
Copy link
Contributor Author

apsinghdev commented Nov 23, 2024

@frankie567 I've raised this draft PR that contains backend code. please have a look and let me know if it make sense.

(There are further improvements like tags that I'll make this week)

Copy link
Member

@frankie567 frankie567 left a comment

Choose a reason for hiding this comment

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

That's great work @apsinghdev 👍 Let's change a few things to make it really tailored for email verification :)

Be sure also to run linters:

uv run task lint && uv run task lint_types

from polar.models.user import User

def get_expires_at() -> datetime:
return utc_now() + timedelta(seconds=settings.MAGIC_LINK_TTL_SECONDS)
Copy link
Member

Choose a reason for hiding this comment

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

Let's have a dedicated setting for that (keep the same default as magic link)

from .schemas import EmailUpdateCreate


TOKEN_PREFIX = "polar_ml_"
Copy link
Member

Choose a reason for hiding this comment

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

The prefix needs to be changed. Let's say polar_ev_.

email_update_record = EmailVerification(**email_update_create.model_dump(exclude_unset=True))

session.add(email_update_record)
await session.commit()
Copy link
Member

Choose a reason for hiding this comment

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

Use await session.flush() instead of committing here. The difference is here:

  • With flush, the changes are sent to the DB (so we have integrity checks triggered and default values generated) but the transaction is not committed. It means that if something goes wrong after that in the request, the changes won't be saved to the database, ensuring it's consistent.
  • With commit, all of the above is done but the transaction is committed, meaning the changes are definitely written to the DB. If something goes wrong after that, it's over, there is no going back.

PS: I see we do that in the magic link service, but that's bad and we should fix it 😜

user.email = email_update_record.email

await session.delete(email_update_record)
await session.commit()
Copy link
Member

Choose a reason for hiding this comment

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

Same comment as above regarding commit. In this case, we can even have just await session.delete(...) and nothing else: commit is called automatically by a middleware after the response is sent to the client.

to_email_addr=email_update_record.email, subject=subject, html_content=body
)

async def authenticate(
Copy link
Member

Choose a reason for hiding this comment

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

We should call the method differently, let's say verify.

from polar.routing import APIRouter

from .schemas import EmailUpdateRequest
from .service import email_update as email_upate_service
Copy link
Member

Choose a reason for hiding this comment

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

Typo: email_update_service

email_update_record, token = await email_upate_service.request_email_update(
email_update_request.email,
session,
user_id,
Copy link
Member

Choose a reason for hiding this comment

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

A bit of a nitpick, but let's pass the auth_subject directly to the method.

e.message, e.status_code, return_to=return_to
) from e

await loops_service.user_update(session, user, emailLogin=True)
Copy link
Member

Choose a reason for hiding this comment

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

emailLogin property is not relevant here (it's not a login). We just need to update the user email.

await loops_service.user_update(session, user)


{% block body %}
<h1>Hi,</h1>
<p>Here is the magic link to update your email. Click the button below to complete the update process. <strong>This link
Copy link
Member

Choose a reason for hiding this comment

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

Let's write:

Here is the verification link to update your email. Click the button below to complete the update process.

<table width="100%" border="0" cellspacing="0" cellpadding="0" role="presentation">
<tr>
<td align="center">
<a href="{{ url | safe }}" class="f-fallback button">Sign in to Polar</a>
Copy link
Member

Choose a reason for hiding this comment

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

Update my email

@apsinghdev
Copy link
Contributor Author

That's great work @apsinghdev 👍 Let's change a few things to make it really tailored for email verification :)

Be sure also to run linters:

uv run task lint && uv run task lint_types

@frankie567 Thanks for the reviews. I'll fix these very soon.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Allow to update account email address
2 participants