This commit is contained in:
Iliyan Angelov
2025-09-14 23:24:25 +03:00
commit c67067a2a4
71311 changed files with 6800714 additions and 0 deletions

View File

@@ -0,0 +1,91 @@
import requests
from urllib.parse import urlencode
from django.http import HttpResponseRedirect
from django.utils.translation import gettext as _
from allauth.socialaccount.providers.oauth.client import (
OAuthClient,
OAuthError,
get_token_prefix,
)
from allauth.utils import build_absolute_uri
class PocketOAuthClient(OAuthClient):
def _get_request_token(self):
"""
Obtain a temporary request token to authorize an access token and to
sign the request to obtain the access token
"""
if self.request_token is None:
redirect_url = build_absolute_uri(self.request, self.callback_url)
headers = {
"X-Accept": "application/json",
}
data = {
"consumer_key": self.consumer_key,
"redirect_uri": redirect_url,
}
response = requests.post(
url=self.request_token_url,
json=data,
headers=headers,
)
if response.status_code != 200:
raise OAuthError(
_("Invalid response while obtaining request token" ' from "%s".')
% get_token_prefix(self.request_token_url)
)
self.request_token = response.json()["code"]
self.request.session[
"oauth_%s_request_token" % get_token_prefix(self.request_token_url)
] = self.request_token
return self.request_token
def get_redirect(self, authorization_url, extra_params):
"""
Returns a ``HttpResponseRedirect`` object to redirect the user
to the Pocket authorization URL.
"""
request_token = self._get_request_token()
params = {
"request_token": request_token,
"redirect_uri": self.request.build_absolute_uri(self.callback_url),
}
params.update(extra_params)
url = authorization_url + "?" + urlencode(params)
return HttpResponseRedirect(url)
def get_access_token(self):
"""
Obtain the access token to access private resources at the API
endpoint.
"""
if self.access_token is None:
request_token = self._get_rt_from_session()
url = self.access_token_url
headers = {
"X-Accept": "application/json",
}
data = {
"consumer_key": self.consumer_key,
"code": request_token,
}
response = requests.post(url=url, headers=headers, json=data)
if response.status_code != 200:
raise OAuthError(
_("Invalid response while obtaining access token" ' from "%s".')
% get_token_prefix(self.request_token_url)
)
r = response.json()
self.access_token = {
"oauth_token": request_token,
"oauth_token_secret": r["access_token"],
"username": r["username"],
}
self.request.session[
"oauth_%s_access_token" % get_token_prefix(self.request_token_url)
] = self.access_token
return self.access_token

View File

@@ -0,0 +1,35 @@
from allauth.account.models import EmailAddress
from allauth.socialaccount.providers.base import ProviderAccount
from allauth.socialaccount.providers.oauth.provider import OAuthProvider
class PocketAccount(ProviderAccount):
def to_str(self):
dflt = super(PocketAccount, self).to_str()
return self.account.extra_data.get("Display_Name", dflt)
class PocketProvider(OAuthProvider):
id = "pocket"
name = "Pocket"
account_class = PocketAccount
def extract_uid(self, data):
return data["username"]
def extract_common_fields(self, data):
return dict(
email=data["username"],
)
def extract_email_addresses(self, data):
return [
EmailAddress(
email=data["username"],
verified=True,
primary=True,
)
]
provider_classes = [PocketProvider]

View File

@@ -0,0 +1,47 @@
from urllib.parse import parse_qs, urlencode, urlparse
from django.urls import reverse
from allauth.socialaccount.tests import OAuthTestsMixin
from allauth.tests import MockedResponse, TestCase, mocked_response
from .provider import PocketProvider
class PocketOAuthTests(OAuthTestsMixin, TestCase):
provider_id = PocketProvider.id
def get_mocked_response(self):
return []
def get_access_token_response(self):
return MockedResponse(
200,
"""
{"access_token":"5678defg-5678-defg-5678-defg56",
"username":"name@example.com"}
""",
)
def login(self, resp_mocks, process="login"):
with mocked_response(
MockedResponse(
200,
"""
{"code": "dcba4321-dcba-4321-dcba-4321dc"}
""",
{"content-type": "application/json"},
)
):
resp = self.client.post(
reverse(self.provider.id + "_login")
+ "?"
+ urlencode(dict(process=process))
)
p = urlparse(resp["location"])
q = parse_qs(p.query)
complete_url = reverse(self.provider.id + "_callback")
self.assertGreater(q["redirect_uri"][0].find(complete_url), 0)
with mocked_response(self.get_access_token_response(), *resp_mocks):
resp = self.client.get(complete_url)
return resp

View File

@@ -0,0 +1,6 @@
from allauth.socialaccount.providers.oauth.urls import default_urlpatterns
from .provider import PocketProvider
urlpatterns = default_urlpatterns(PocketProvider)

View File

@@ -0,0 +1,59 @@
from ..oauth.views import OAuthAdapter, OAuthCallbackView, OAuthLoginView
from .client import PocketOAuthClient
from .provider import PocketProvider
class PocketOAuthAdapter(OAuthAdapter):
provider_id = PocketProvider.id
request_token_url = "https://getpocket.com/v3/oauth/request"
access_token_url = "https://getpocket.com/v3/oauth/authorize"
authorize_url = "https://getpocket.com/auth/authorize"
def complete_login(self, request, app, token, response):
return self.get_provider().sociallogin_from_response(request, response)
class PocketOAuthLoginView(OAuthLoginView):
def _get_client(self, request, callback_url):
provider = self.adapter.get_provider()
app = provider.app
scope = " ".join(provider.get_scope(request))
parameters = {}
if scope:
parameters["scope"] = scope
client = PocketOAuthClient(
request,
app.client_id,
app.secret,
self.adapter.request_token_url,
self.adapter.access_token_url,
callback_url,
parameters=parameters,
provider=provider,
)
return client
class PocketOAuthCallbackView(OAuthCallbackView):
def _get_client(self, request, callback_url):
provider = self.adapter.get_provider()
app = provider.app
scope = " ".join(provider.get_scope(request))
parameters = {}
if scope:
parameters["scope"] = scope
client = PocketOAuthClient(
request,
app.client_id,
app.secret,
self.adapter.request_token_url,
self.adapter.access_token_url,
callback_url,
parameters=parameters,
provider=provider,
)
return client
oauth_login = PocketOAuthLoginView.adapter_view(PocketOAuthAdapter)
oauth_callback = PocketOAuthCallbackView.adapter_view(PocketOAuthAdapter)