diff --git a/api/funkwhale_api/common/authentication.py b/api/funkwhale_api/common/authentication.py index 1340aed91..75a33406f 100644 --- a/api/funkwhale_api/common/authentication.py +++ b/api/funkwhale_api/common/authentication.py @@ -1,4 +1,3 @@ -from django.conf import settings from django.utils.translation import ugettext as _ from django.core.cache import cache @@ -12,14 +11,6 @@ from rest_framework import exceptions from funkwhale_api.users import models as users_models -def should_verify_email(user): - if user.is_superuser: - return False - has_unverified_email = not user.has_verified_primary_email - mandatory_verification = settings.ACCOUNT_EMAIL_VERIFICATION != "optional" - return has_unverified_email and mandatory_verification - - class UnverifiedEmail(Exception): def __init__(self, user): self.user = user @@ -68,7 +59,7 @@ class ApplicationTokenAuthentication(object): msg = _("User account is disabled.") raise exceptions.AuthenticationFailed(msg) - if should_verify_email(user): + if user.should_verify_email(): raise UnverifiedEmail(user) request.scopes = application.scope.split() diff --git a/api/funkwhale_api/subsonic/authentication.py b/api/funkwhale_api/subsonic/authentication.py index 6289248e9..5e7fe9f78 100644 --- a/api/funkwhale_api/subsonic/authentication.py +++ b/api/funkwhale_api/subsonic/authentication.py @@ -27,7 +27,7 @@ def authenticate(username, password): except (User.DoesNotExist, binascii.Error): raise exceptions.AuthenticationFailed("Wrong username or password.") - if common_authentication.should_verify_email(user): + if user.should_verify_email(): raise exceptions.AuthenticationFailed("You need to verify your e-mail address.") return (user, None) @@ -46,7 +46,7 @@ def authenticate_salt(username, salt, token): if expected != token: raise exceptions.AuthenticationFailed("Wrong username or password.") - if common_authentication.should_verify_email(user): + if user.should_verify_email(): raise exceptions.AuthenticationFailed("You need to verify your e-mail address.") return (user, None) diff --git a/api/funkwhale_api/users/models.py b/api/funkwhale_api/users/models.py index d07d2ae1c..98a5ffa73 100644 --- a/api/funkwhale_api/users/models.py +++ b/api/funkwhale_api/users/models.py @@ -105,13 +105,7 @@ class UserQuerySet(models.QuerySet): def for_auth(self): """Optimization to avoid additional queries during authentication""" qs = self.select_related("actor__domain") - verified_emails = EmailAddress.objects.filter( - user=models.OuterRef("id"), primary=True - ).values("verified")[:1] - subquery = models.Subquery(verified_emails) - return qs.annotate(has_verified_primary_email=subquery).prefetch_related( - "plugins" - ) + return qs.prefetch_related("plugins", "emailaddress_set") class UserManager(BaseUserManager): @@ -315,6 +309,17 @@ class User(AbstractUser): return return self.actor.attachment_icon + @property + def has_verified_primary_email(self) -> bool: + return len(self.emailaddress_set.filter(primary=True, verified=True)) > 0 + + def should_verify_email(self): + if self.is_superuser: + return False + has_unverified_email = not self.has_verified_primary_email + mandatory_verification = settings.ACCOUNT_EMAIL_VERIFICATION != "optional" + return has_unverified_email and mandatory_verification + def generate_code(length=10): return "".join( diff --git a/api/funkwhale_api/users/oauth/server.py b/api/funkwhale_api/users/oauth/server.py index cf2454420..0bd59be58 100644 --- a/api/funkwhale_api/users/oauth/server.py +++ b/api/funkwhale_api/users/oauth/server.py @@ -7,7 +7,7 @@ from funkwhale_api.common import authentication def check(request): user = request.user request.user = user.__class__.objects.all().for_auth().get(pk=user.pk) - if authentication.should_verify_email(request.user): + if request.user.should_verify_email(): raise authentication.UnverifiedEmail(user) return True diff --git a/api/tests/common/test_authentication.py b/api/tests/common/test_authentication.py index ccd39fc5a..be3f7b99c 100644 --- a/api/tests/common/test_authentication.py +++ b/api/tests/common/test_authentication.py @@ -25,9 +25,10 @@ def test_should_verify_email( settings, ): settings.ACCOUNT_EMAIL_VERIFICATION = setting_value - user = factories["users.User"](is_superuser=is_superuser) - setattr(user, "has_verified_primary_email", has_verified_primary_email) - assert authentication.should_verify_email(user) is expected + user = factories["users.User"]( + is_superuser=is_superuser, verified_email=has_verified_primary_email + ) + assert user.should_verify_email() is expected def test_app_token_authentication(factories, api_request): diff --git a/api/tests/users/test_models.py b/api/tests/users/test_models.py index 497eedcec..badb8e8f8 100644 --- a/api/tests/users/test_models.py +++ b/api/tests/users/test_models.py @@ -244,7 +244,7 @@ def test_get_by_natural_key_annotates_primary_email_verified_no_email(factories) user = factories["users.User"]() user = models.User.objects.get_by_natural_key(user.username) - assert user.has_verified_primary_email is None + assert user.has_verified_primary_email is False def test_get_by_natural_key_annotates_primary_email_verified_true(factories):