Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions fxsharing/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@
] # SOCIALACCOUNT_ONLY=True; normal signup/login never used
ACCOUNT_SIGNUP_FIELDS = ["email"]
SOCIALACCOUNT_ADAPTER = "fxsharing.users.adapter.FxASocialAccountAdapter"
ACCOUNT_USER_DISPLAY = "fxsharing.users.adapter.user_display"
SOCIALACCOUNT_STORE_TOKENS = False
SOCIALACCOUNT_PROVIDERS = {
"fxa": {
Expand Down
18 changes: 18 additions & 0 deletions fxsharing/users/adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,21 @@ def populate_user(self, request, sociallogin, _data):
user = super().populate_user(request, sociallogin, _data)
user.fxa_id = sociallogin.account.uid
return user


def user_display(user):
"""Resolve how a user is shown to themselves, e.g. the post-login banner.

Wired up via the ``ACCOUNT_USER_DISPLAY`` setting and used by allauth's
``{% user_display %}`` template tag. The email lives in the social account's
stored profile (``extra_data``); fall back to ``fxa_id`` when it is
unavailable (e.g. dev seed users with no social account). Users only ever
have a single social account (``SOCIALACCOUNT_ONLY``): FxA in production, or
the dummy provider in local development.
"""
account = user.socialaccount_set.first()
if account:
email = account.extra_data.get("email")
if email:
return email
return user.fxa_id
42 changes: 41 additions & 1 deletion fxsharing/users/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
from django.test import TestCase
from django.urls import NoReverseMatch, reverse

from fxsharing.users.adapter import FxASocialAccountAdapter
from allauth.socialaccount.models import SocialAccount

from fxsharing.users.adapter import FxASocialAccountAdapter, user_display
from fxsharing.users.models import User


Expand All @@ -23,6 +25,44 @@ def test_populate_user_sets_fxa_id(self):
assert result.fxa_id == "a1b2c3d4e5f6789abc"


class TestUserDisplay(TestCase):
def test_returns_email_from_social_account(self):
user = User.objects.create_user(fxa_id="a1b2c3d4e5f6789abc")
SocialAccount.objects.create(
user=user,
provider="fxa",
uid=user.fxa_id,
extra_data={"email": "jane@example.com"},
)
assert user_display(user) == "jane@example.com"

def test_returns_email_for_non_fxa_provider(self):
# user_display is provider-agnostic: it reads the email from whichever
# social account the user has, not specifically the fxa one.
user = User.objects.create_user(fxa_id="42")
SocialAccount.objects.create(
user=user,
provider="dummy",
uid=user.fxa_id,
extra_data={"email": "dev@example.com"},
)
assert user_display(user) == "dev@example.com"

def test_falls_back_to_fxa_id_without_social_account(self):
user = User.objects.create_user(fxa_id="a1b2c3d4e5f6789abc")
assert user_display(user) == "a1b2c3d4e5f6789abc"

def test_falls_back_to_fxa_id_when_email_missing(self):
user = User.objects.create_user(fxa_id="a1b2c3d4e5f6789abc")
SocialAccount.objects.create(
user=user,
provider="fxa",
uid=user.fxa_id,
extra_data={},
)
assert user_display(user) == "a1b2c3d4e5f6789abc"


class TestAllauthUrlConfig(TestCase):
"""Only the FxA OAuth endpoints should be reachable; the rest
of django-allauth's endpoints must 404 (while keeping their names
Expand Down
Loading