from allauth.socialaccount.providers.base import ProviderAccount
from allauth.socialaccount.providers.oauth2.provider import OAuth2Provider


class DataportenAccount(ProviderAccount):
    def get_avatar_url(self):
        '''
        Returns a valid URL to an 128x128 .png photo of the user
        '''
        # Documentation for user profile photos can be found here:
        # https://docs.dataporten.no/docs/oauth-authentication/
        base_url = 'https://api.dataporten.no/userinfo/v1/user/media/'
        return base_url + self.account.extra_data['profilephoto']

    def to_str(self):
        '''
        Returns string representation of a social account. Includes the name
        of the user.
        '''
        dflt = super(DataportenAccount, self).to_str()
        return '%s (%s)' % (
            self.account.extra_data.get('name', ''),
            dflt,
        )


class DataportenProvider(OAuth2Provider):
    id = 'dataporten'
    name = 'Dataporten'
    account_class = DataportenAccount

    def extract_uid(self, data):
        '''
        Returns the primary user identifier, an UUID string
        See: https://docs.dataporten.no/docs/userid/
        '''
        return data['userid']

    def extract_extra_data(self, data):
        '''
        Extracts fields from `data` that will be stored in
        `SocialAccount`'s `extra_data` JSONField.

        All the necessary data extraction has already been done in the
        complete_login()-view, so we can just return the data.
        PS: This is default behaviour, so we did not really need to define
            this function, but it is included for documentation purposes.

        Typical return dict:
        {
            "userid": "76a7a061-3c55-430d-8ee0-6f82ec42501f",
            "userid_sec": ["feide:andreas@uninett.no"],
            "name": "Andreas \u00c5kre Solberg",
            "email": "andreas.solberg@uninett.no",
            "profilephoto": "p:a3019954-902f-45a3-b4ee-bca7b48ab507",
            "groups": [{...}, {...}, ...],
        }
        '''
        return data

    def extract_common_fields(self, data):
        '''
        This function extracts information from the /userinfo endpoint which
        will be consumed by allauth.socialaccount.adapter.populate_user().
        Look there to find which key-value pairs that should be saved in the
        returned dict.

        Typical return dict:
        {
            "userid": "76a7a061-3c55-430d-8ee0-6f82ec42501f",
            "userid_sec": ["feide:andreas@uninett.no"],
            "name": "Andreas \u00c5kre Solberg",
            "email": "andreas.solberg@uninett.no",
            "profilephoto": "p:a3019954-902f-45a3-b4ee-bca7b48ab507",
            "username": "andreas",
        }
        '''
        # Make shallow copy to prevent possible mutability issues
        data = dict(data)

        # If a Feide username is available, use it. If not, use the "username"
        # of the email-address
        username_set = False
        for userid in data['userid_sec']:
            usertype, username = userid.split(':')
            if usertype == 'feide':
                data['username'] = username.split('@')[0]
                username_set = True
                break
        if not username_set:
            data['username'] = data['email'].split('@')[0]

        # We do not bother with removing the unused "userid_sec" and
        # "profilephoto" keys from the data-dictionary, as it doesn't make a
        # difference anyway
        return data


provider_classes = [DataportenProvider]

@@ -3009,25 +3009,29 @@
 erid in data
-%5B
+.get(
 'userid_sec'
@@ -3030,17 +3030,17 @@
 rid_sec'
-%5D
+)
 :%0A      
@@ -3304,17 +3304,21 @@
 data
-%5B
+.get(
 'email'
-%5D
+)
 .spl

Support lacking email scope