diff --git a/fiesta/apps/accounts/social.py b/fiesta/apps/accounts/social.py new file mode 100644 index 00000000..42ae1aac --- /dev/null +++ b/fiesta/apps/accounts/social.py @@ -0,0 +1,13 @@ +from allauth.socialaccount.models import SocialAccount, SocialLogin +from django.http import HttpRequest +from allauth.socialaccount.adapter import DefaultSocialAccountAdapter + +from apps.esnaccounts.provider import ESNAccountsProvider + + +class SocialAccountAdapter(DefaultSocialAccountAdapter): + def pre_social_login(self, request: HttpRequest, login: SocialLogin): + + sa: SocialAccount = login.account + if sa.provider == ESNAccountsProvider.id: + ESNAccountsProvider.pre_social_login(request, login) diff --git a/fiesta/apps/esnaccounts/provider.py b/fiesta/apps/esnaccounts/provider.py index a2ca4d1a..94a01bfa 100644 --- a/fiesta/apps/esnaccounts/provider.py +++ b/fiesta/apps/esnaccounts/provider.py @@ -1,9 +1,20 @@ +import typing + from allauth.socialaccount.providers.base import ProviderAccount from allauth_cas.providers import CASProvider +from django.http import HttpRequest + +from apps.accounts.models import User +from apps.sections.models import Section, SectionMembership + +if typing.TYPE_CHECKING: + from allauth.socialaccount.models import SocialAccount, SocialLogin class ESNAccountsAccount(ProviderAccount): - pass + def get_avatar_url(self): + sa: 'SocialAccount' = self.account + return sa.extra_data.get('picture') class ESNAccountsProvider(CASProvider): @@ -11,7 +22,51 @@ class ESNAccountsProvider(CASProvider): name = "ESN Accounts" account_class = ESNAccountsAccount - # TODO: fix extract_common_fields to load data from extra_data + def extract_common_fields(self, data): + uid, extra = data + return { + 'username': extra.get('username', uid), + 'email': extra.get('mail'), + 'first_name': extra.get('first'), + 'last_name': extra.get('last'), + } + + MEMBER_ROLE = 'Local.activeMember' + EDITOR_ROLE = 'Local.regularBoardMember' + + @classmethod + def pre_social_login( + cls, + request: HttpRequest, + login: 'SocialLogin', + ): + user: User = login.user + sa: SocialAccount = login.account + roles = sa.extra_data.get('roles', []) + section_code = sa.extra_data.get('sc') + section_name = sa.extra_data.get('section') + user_nationality = sa.extra_data.get('nationality') + national_section = sa.extra_data.get('country') + + user.save() + SectionMembership.objects.update_or_create( + user=user, + section=Section.objects.get_or_create( + name=section_name, + defaults=dict( + code=section_code, + # TODO: definitely not, user nationality != section assignment + country=user_nationality, + ) + )[0], + defaults=dict( + # TODO: check all possible for ESN Accounts roles + state=SectionMembership.State.ACTIVE, + role=SectionMembership.Role.EDITOR if cls.EDITOR_ROLE in roles + else SectionMembership.Role.MEMBER if cls.MEMBER_ROLE in roles + else SectionMembership.Role.INTERNATIONAL + ) + ) provider_classes = [ESNAccountsProvider] diff --git a/fiesta/apps/sections/models/membership.py b/fiesta/apps/sections/models/membership.py index 434628f8..488af1f1 100644 --- a/fiesta/apps/sections/models/membership.py +++ b/fiesta/apps/sections/models/membership.py @@ -43,6 +43,8 @@ class State(models.TextChoices): verbose_name=_("membership state"), ) + # TODO: add flag to signalize, if membership has been added from ESN Accounts + class Meta: verbose_name = _("section membership") verbose_name_plural = _("section memberships") diff --git a/fiesta/apps/sections/models/section.py b/fiesta/apps/sections/models/section.py index e5840c3a..54e68c7d 100644 --- a/fiesta/apps/sections/models/section.py +++ b/fiesta/apps/sections/models/section.py @@ -23,6 +23,13 @@ class Section(BaseTimestampedModel): help_text=_("Universities, for whose this section offers services."), ) + code = models.SlugField( + verbose_name=_('code'), + help_text=_('Official code used in ESN world, especially in ESN Accounts database.'), + # TODO: remove blankness after proper migration from ESN accounts + null=True, blank=True, + ) + class Meta: verbose_name = _("ESN section") verbose_name_plural = _("ESN sections") diff --git a/fiesta/fiesta/settings.py b/fiesta/fiesta/settings.py index a8469c87..f14552a2 100644 --- a/fiesta/fiesta/settings.py +++ b/fiesta/fiesta/settings.py @@ -200,6 +200,7 @@ ACCOUNT_USERNAME_MIN_LENGTH = 4 # a personal preference ACCOUNT_SESSION_REMEMBER = True # None by default (to ask 'Remember me?'). I want the user to be always logged in ACCOUNT_DEFAULT_HTTP_PROTOCOL = "https" +SOCIALACCOUNT_ADAPTER = 'apps.accounts.social.SocialAccountAdapter' LOGIN_URL = "/accounts/auth/login" LOGIN_REDIRECT_URL = "/accounts/profile"