Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to find user's patreon pledge tier using django-allauth for authentication

I’m using django-allauth to authenticate users (uses Patreon's API v1), which adds a json to the database with the info below. I would like to show extra content on the site if the user's pledge matches a particular tier (or is above one).

{
  "attributes": {
    "about": null,
    "can_see_nsfw": true,
    "created": "2019-05-20T20:29:02.000+00:00",
    "default_country_code": null,
    "discord_id": null,
    "email": "[email protected]",
    "facebook": null,
    "facebook_id": null,
    "first_name": "Adm",
    "full_name": "Adm Nsm",
    "gender": 0,
    "has_password": true,
    "image_url": "https://c8.patreon.com/2/200/21383296",
    "is_deleted": false,
    "is_email_verified": false,
    "is_nuked": false,
    "is_suspended": false,
    "last_name": "Nsm",
    "social_connections": {
      "deviantart": null,
      "discord": null,
      "facebook": null,
      "instagram": null,
      "reddit": null,
      "spotify": null,
      "twitch": null,
      "twitter": null,
      "youtube": null
    },
    "thumb_url": "https://c8.patreon.com/2/200/21383296",
    "twitch": null,
    "twitter": null,
    "url": "https://www.patreon.com/user?u=21383296",
    "vanity": null,
    "youtube": null
  },
  "id": "21383296",
  "relationships": {
    "pledges": {
      "data": [
        {
          "id": "24461189",
          "type": "pledge"
        }
      ]
    }
  },
  "type": "user"
}

At first I though relationships.pledges.data.id would have the ID of the current tier and with that I managed to add an extra block of content for a specific user, but apparently that was only wishful thinking; after testing with a second account the ID that I though was the pledge level seems to differ each time. I imagine I might need to request more info from Patreon's API, but am unsure how to get what I need back.

EDIT:

From what I can gather, I would need to request the currently_entitled_tiers from /api/oauth2/v2/members/{id}

The problem is that the ID required there is not the same ID I get after a user logs in. So I would first need to use the oauth access token that's been generated and GET /api/oauth2/v2/identity for the long ID number.

My current problem is that when I try to get the ID from /api/oauth2/v2/identity I receive a 401 error code:

<Response [401]>
{'errors': [{'code': 1, 'code_name': 'Unauthorized', 'detail': "The server could not verify that you are authorized to access the URL requested.  You either supplied the wrong credentia
ls (e.g. a bad password), or your browser doesn't understand how to supply the credentials required.", 'id': 'b298d8b1-73db-46ab-b3f4-545e6f934599', 'status': '401', 'title': 'Unauthori
zed'}]}

What I'm sending is:

headers = {"authorization": "Bearer " + str(access_token)}  # User's Access Token
req = requests.get("https://patreon.com/api/oauth2/v2/identity?include=memberships", headers=headers)

If I get the proper ID through /api/oauth2/v2/campaigns/{campaign_id}/members I can request from /api/oauth2/v2/members/{id} and get what I need, but that middle step using the currently logged in user to get their ID eludes me.

Thank you.

like image 720
Nick S Avatar asked May 21 '19 00:05

Nick S


2 Answers

I managed to get the pledge by changing django-allauth directly. Since it uses API v1 you need to change the scopes in order to get info from the API v2 endpoints. To do this I had to modify the patreon provider and views from allauth.

This is only my second project in python, so excuse the possibly messy or not ideal code:

provider.py

    # Change
    def get_default_scope(self):
        return ['pledges-to-me', 'users', 'my-campaign']

    # to
    def get_default_scope(self):
        return ['identity', 'identity[email]', 'campaigns', 'campaigns.members']

views.py

"""
Views for PatreonProvider
https://www.patreon.com/platform/documentation/oauth
"""

import requests

from allauth.socialaccount.providers.oauth2.views import (
    OAuth2Adapter,
    OAuth2CallbackView,
    OAuth2LoginView,
)

from .provider import PatreonProvider


class PatreonOAuth2Adapter(OAuth2Adapter):
    provider_id = PatreonProvider.id
    access_token_url = 'https://www.patreon.com/api/oauth2/token'
    authorize_url = 'https://www.patreon.com/oauth2/authorize'
    profile_url = 'https://www.patreon.com/api/oauth2/v2/identity?include=memberships&fields[user]=email,first_name,full_name,image_url,last_name,social_connections,thumb_url,url,vanity'


    def complete_login(self, request, app, token, **kwargs):
        resp = requests.get(self.profile_url,
                            headers={'Authorization': 'Bearer ' + token.token})
        extra_data = resp.json().get('data')

        try:
            member_id = extra_data['relationships']['memberships']['data'][0]['id']
            member_url = f'https://www.patreon.com/api/oauth2/v2/members/{member_id}?include=currently_entitled_tiers&fields%5Btier%5D=title'
            resp_member = requests.get(member_url,
                                headers={'Authorization': 'Bearer ' + token.token})
            pledge_title = resp_member.json()['included'][0]['attributes']['title']
            extra_data["pledge_level"] = pledge_title

        except (KeyError, IndexError):
            extra_data["pledge_level"] = None
            pass


        return self.get_provider().sociallogin_from_response(request,
                                                             extra_data)


oauth2_login = OAuth2LoginView.adapter_view(PatreonOAuth2Adapter)
oauth2_callback = OAuth2CallbackView.adapter_view(PatreonOAuth2Adapter)

With that you can request from the API v2 endpoints (still using the APIv1 client, haven't yet tested if it works with API v2 client), and it will add the pledge title to the extra_data field on the social account.

like image 197
Nick S Avatar answered Nov 10 '22 07:11

Nick S


I’ve updated django-allauth, using parts of Nick S’s answer, to enable Patreon API v2 (as of django-allauth 0.40.0).

To use API v2, you can now just change the patreon entry for SOCIALACCOUNT_PROVIDERS in settings.py:

settings.py (add this towards the end)

SOCIALACCOUNT_PROVIDERS = {
    'patreon': {
        'VERSION': 'v2',
    }
}

By default, this will also add the pledge tier to each user’s social account, storing it in extra_data['pledge_level'].

like image 37
Rick Westera Avatar answered Nov 10 '22 08:11

Rick Westera