Coverage for baibu/users/adapters.py: 100%
40 statements
« prev ^ index » next coverage.py v7.10.7, created at 2026-10-06 13:07 +0000
« prev ^ index » next coverage.py v7.10.7, created at 2026-10-06 13:07 +0000
1from allauth.account.adapter import DefaultAccountAdapter
2from django.conf import settings
3from django.contrib import messages
4from django.db import transaction
5from django.http import HttpRequest
6from django.template.loader import render_to_string
7from django.utils.translation import gettext
9from . import messaging
10from .models import User
11from .phone import normalize_phone
14class AccountAdapter(DefaultAccountAdapter):
15 def is_open_for_signup(self, request: HttpRequest) -> bool:
16 return settings.ACCOUNT_ALLOW_REGISTRATION
18 # Phone sign-in. allauth only calls these when PHONE_SIGN_IN_ENABLED puts
19 # "phone" in ACCOUNT_LOGIN_METHODS and ACCOUNT_SIGNUP_FIELDS.
21 def phone_form_field(self, **kwargs):
22 from .forms import PhoneNumberField
24 return PhoneNumberField(**kwargs)
26 def get_phone(self, user: User) -> tuple[str, bool] | None:
27 return (user.phone, user.phone_verified) if user.phone else None
29 def set_phone(self, user: User, phone: str, verified: bool) -> None: # noqa: FBT001
30 if verified:
31 self.set_phone_verified(user, phone)
32 return
33 user.phone = phone
34 user.phone_verified = False
35 user.save(update_fields=["phone", "phone_verified"])
37 def set_phone_verified(self, user: User, phone: str) -> None:
38 with transaction.atomic():
39 # Someone else may have typed this number without verifying it.
40 User.objects.filter(phone=phone, phone_verified=False).exclude(pk=user.pk).update(phone=None)
41 user.phone = phone
42 user.phone_verified = True
43 user.save(update_fields=["phone", "phone_verified"])
45 def get_user_by_phone(self, phone: str) -> User | None:
46 # Only a verified number identifies an account. Sign-in with a password
47 # passes the number as typed, so normalise it here too.
48 return User.objects.filter(phone=normalize_phone(phone), phone_verified=True).first()
50 def send_verification_code_sms(self, user: User, phone: str, code: str, **kwargs) -> None:
51 text = render_to_string(
52 "users/messages/verification_code.txt",
53 {"code": code, "user": user, "platform_name": settings.PLATFORM_NAME},
54 request=self.request,
55 ).strip()
56 try:
57 messaging.send_text(phone, text)
58 except messaging.MessagingError:
59 if self.request is not None:
60 messages.error(
61 self.request,
62 gettext("We could not send a text message to that number. Please try again later."),
63 )