feat: email and password login

This commit is contained in:
3252a8
2026-05-19 15:21:02 +03:00
parent 3152631911
commit f5006af6c0
26 changed files with 1273 additions and 90 deletions
+10 -1
View File
@@ -196,7 +196,11 @@ class EmailAuthService:
code = f"{secrets.randbelow(1_000_000):06d}"
magic_token = secrets.token_urlsafe(32)
magic_link = self._build_magic_link(token=magic_token, purpose=purpose)
magic_link = (
self._build_magic_link(token=magic_token, purpose=purpose)
if purpose == "login"
else None
)
code_model = EmailVerificationCode(
email=normalized_email,
code_hash=self._hash_code(normalized_email, purpose, code),
@@ -214,6 +218,7 @@ class EmailAuthService:
code=code,
language_code=language_code,
magic_link=magic_link,
purpose=purpose,
)
return EmailCodeRequestResult(ok=True)
@@ -405,6 +410,7 @@ class EmailAuthService:
code: str,
language_code: str,
magic_link: Optional[str] = None,
purpose: str = "login",
) -> None:
await asyncio.to_thread(
self._send_code_email_sync,
@@ -412,6 +418,7 @@ class EmailAuthService:
code=code,
language_code=language_code,
magic_link=magic_link,
purpose=purpose,
)
async def send_custom_email(
@@ -450,12 +457,14 @@ class EmailAuthService:
code: str,
language_code: str,
magic_link: Optional[str] = None,
purpose: str = "login",
) -> None:
content = render_login_code(
self.settings,
code=code,
language_code=language_code,
magic_link=magic_link,
purpose=purpose,
)
message = EmailMessage()
+10 -8
View File
@@ -209,6 +209,7 @@ def render_login_code(
code: str,
language_code: Optional[str],
magic_link: Optional[str] = None,
purpose: str = "login",
i18n: Optional[JsonI18n] = None,
) -> EmailContent:
i18n = _resolve_i18n(i18n)
@@ -216,16 +217,17 @@ def render_login_code(
minutes = _format_minutes(settings.EMAIL_CODE_TTL_SECONDS)
accent = _safe_color(settings.WEBAPP_PRIMARY_COLOR)
brand = _brand_title(settings)
safe_magic_link = (magic_link or "").strip()
template_prefix = "email_set_password_code" if purpose == "set_password" else "email_login_code"
safe_magic_link = (magic_link or "").strip() if template_prefix == "email_login_code" else ""
subject = _t_text(i18n, lang, "email_login_code_subject", code=code)
preheader = _t_text(i18n, lang, "email_login_code_preheader", minutes=minutes)
heading = _t_text(i18n, lang, "email_login_code_heading")
intro = _t_text(i18n, lang, "email_login_code_intro")
expiry_html = _t_html(i18n, lang, "email_login_code_expiry_html", minutes=minutes)
security = _t_text(i18n, lang, "email_login_code_security")
subject = _t_text(i18n, lang, f"{template_prefix}_subject", code=code)
preheader = _t_text(i18n, lang, f"{template_prefix}_preheader", minutes=minutes)
heading = _t_text(i18n, lang, f"{template_prefix}_heading")
intro = _t_text(i18n, lang, f"{template_prefix}_intro")
expiry_html = _t_html(i18n, lang, f"{template_prefix}_expiry_html", minutes=minutes)
security = _t_text(i18n, lang, f"{template_prefix}_security")
footer = _t_html(i18n, lang, "email_footer_auto", brand=brand)
text_lines = [_t_text(i18n, lang, "email_login_code_text", code=code, minutes=minutes)]
text_lines = [_t_text(i18n, lang, f"{template_prefix}_text", code=code, minutes=minutes)]
if safe_magic_link:
text_lines.append(_t_text(i18n, lang, "email_login_code_text_magic", url=safe_magic_link))