from django.contrib.auth import get_user_model
from django.contrib.auth.backends import ModelBackend


class EmailOrUsernameBackend(ModelBackend):
    """Let people sign in with either their username or their email address."""

    def authenticate(self, request, username=None, password=None, **kwargs):
        User = get_user_model()
        if username is None:
            username = kwargs.get(User.USERNAME_FIELD)
        if username is None or password is None:
            return None

        user = User.objects.filter(username__iexact=username).first()
        if user is None:
            matches = list(User.objects.filter(email__iexact=username)[:2])
            if len(matches) != 1:
                # no match, or an ambiguous email shared by several accounts
                User().set_password(password)  # equalise timing
                return None
            user = matches[0]

        if user.check_password(password) and self.user_can_authenticate(user):
            return user
        return None
