Add initial twitter authorization views
This commit is contained in:
parent
b498354cb6
commit
52d8c14abe
3 changed files with 145 additions and 0 deletions
|
|
@ -0,0 +1,20 @@
|
||||||
|
{% extends "base.html" %}
|
||||||
|
{% load i18n %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<main id="twitter--page" class="main">
|
||||||
|
<section class="section text-section">
|
||||||
|
{% if error %}
|
||||||
|
<h1 class="h1">{% trans "Twitter authorization failed" %}</h1>
|
||||||
|
<p>{{ error }}</p>
|
||||||
|
{% elif authorized %}
|
||||||
|
<h1 class="h1">{% trans "Twitter account is linked" %}</h1>
|
||||||
|
<p>{% trans "Your Twitter account was successfully linked." %}</p>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<a class="link" href="{% url 'accounts:integrations' %}">{% trans "Return to integrations page" %}</a>
|
||||||
|
</p>
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
|
{% endblock %}
|
||||||
|
|
@ -1,11 +1,17 @@
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
from urllib.parse import parse_qs, urlencode
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.core.cache import cache
|
from django.core.cache import cache
|
||||||
|
from django.shortcuts import redirect
|
||||||
from django.urls import reverse_lazy
|
from django.urls import reverse_lazy
|
||||||
from django.utils.translation import gettext as _
|
from django.utils.translation import gettext as _
|
||||||
from django.views.generic import RedirectView, TemplateView
|
from django.views.generic import RedirectView, TemplateView
|
||||||
|
|
||||||
|
from requests_oauthlib import OAuth1 as OAuth
|
||||||
|
|
||||||
from newsreader.news.collection.exceptions import StreamException
|
from newsreader.news.collection.exceptions import StreamException
|
||||||
from newsreader.news.collection.reddit import (
|
from newsreader.news.collection.reddit import (
|
||||||
get_reddit_access_token,
|
get_reddit_access_token,
|
||||||
|
|
@ -13,6 +19,12 @@ from newsreader.news.collection.reddit import (
|
||||||
revoke_reddit_token,
|
revoke_reddit_token,
|
||||||
)
|
)
|
||||||
from newsreader.news.collection.tasks import RedditTokenTask
|
from newsreader.news.collection.tasks import RedditTokenTask
|
||||||
|
from newsreader.news.collection.twitter import (
|
||||||
|
TWITTER_ACCESS_TOKEN_URL,
|
||||||
|
TWITTER_AUTH_URL,
|
||||||
|
TWITTER_REQUEST_TOKEN_URL,
|
||||||
|
)
|
||||||
|
from newsreader.news.collection.utils import post
|
||||||
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
@ -148,3 +160,113 @@ class RedditRevokeRedirectView(RedirectView):
|
||||||
|
|
||||||
messages.success(request, _("Reddit account deathorized"))
|
messages.success(request, _("Reddit account deathorized"))
|
||||||
return response
|
return response
|
||||||
|
|
||||||
|
|
||||||
|
# TODO hookup url to urlconf
|
||||||
|
# TODO hookup url to integrations button
|
||||||
|
class TwitterAuthRedirectView(RedirectView):
|
||||||
|
url = reverse_lazy("accounts:integrations")
|
||||||
|
|
||||||
|
def get(self, request, *args, **kwargs):
|
||||||
|
oauth = OAuth(
|
||||||
|
settings.TWITTER_CONSUMER_ID,
|
||||||
|
client_secret=settings.TWITTER_CONSUMER_SECRET,
|
||||||
|
callback_uri=settings.TWITTER_REDIRECT_URL,
|
||||||
|
)
|
||||||
|
|
||||||
|
try:
|
||||||
|
response = post(TWITTER_REQUEST_TOKEN_URL, auth=oauth)
|
||||||
|
except StreamException:
|
||||||
|
logger.exception("Failed requesting Twitter authentication token")
|
||||||
|
|
||||||
|
messages.error(request, _("Unable to retrieve initial Twitter token"))
|
||||||
|
return super().get(request, *args, **kwargs)
|
||||||
|
|
||||||
|
params = parse_qs(response.content)
|
||||||
|
|
||||||
|
request_oauth_token = params.get("oauth_token")[0]
|
||||||
|
request_oauth_secret = params.get("oauth_token_secret")[0]
|
||||||
|
|
||||||
|
cache.set_many(
|
||||||
|
{
|
||||||
|
f"twitter-{request.user.email}-token": request_oauth_token,
|
||||||
|
f"twitter-{request.user.email}-secret": request_oauth_secret,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
request_params = urlencode({"oauth_token": request_oauth_secret})
|
||||||
|
return redirect(f"{TWITTER_AUTH_URL}/?{request_params}")
|
||||||
|
|
||||||
|
|
||||||
|
# TODO hookup url
|
||||||
|
class TwitterTemplateView(TemplateView):
|
||||||
|
template_name = "accounts/views/twitter.html"
|
||||||
|
|
||||||
|
def get(self, request, *args, **kwargs):
|
||||||
|
context = self.get_context_data(**kwargs)
|
||||||
|
|
||||||
|
denied = request.GET.get("denied", True)
|
||||||
|
oauth_token = request.GET.get("oauth_token")
|
||||||
|
request.GET.get("oauth_verifier")
|
||||||
|
|
||||||
|
if denied:
|
||||||
|
return self.render_to_response(
|
||||||
|
{
|
||||||
|
**context,
|
||||||
|
"error": "Twitter authorization failed",
|
||||||
|
"authorized": False,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
cached_token = cache.get(f"twitter-{request.user.email}-token")
|
||||||
|
|
||||||
|
if oauth_token != cached_token:
|
||||||
|
return self.render_to_response(
|
||||||
|
{
|
||||||
|
**context,
|
||||||
|
"error": "OAuth tokens failed to match",
|
||||||
|
"authorized": False,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
cached_secret = cache.get(f"twitter-{request.user.email}-secret")
|
||||||
|
|
||||||
|
if not cached_token or not cached_token_secret:
|
||||||
|
return self.render_to_response(
|
||||||
|
{
|
||||||
|
**context,
|
||||||
|
"error": "No matching tokens found for this user",
|
||||||
|
"authorized": False,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
oauth = OAuth(
|
||||||
|
settings.TWITTER_CONSUMER_ID,
|
||||||
|
client_secret=settings.TWITTER_CONSUMER_SECRET,
|
||||||
|
resource_owner_key=cached_token,
|
||||||
|
resource_owner_secret=cached_secret,
|
||||||
|
verifier=oauth_token_secret,
|
||||||
|
)
|
||||||
|
|
||||||
|
try:
|
||||||
|
response = post(TWITTER_ACCESS_TOKEN_URL, auth=oauth)
|
||||||
|
except StreamException:
|
||||||
|
logger.exception("Failed requesting Twitter access token")
|
||||||
|
|
||||||
|
return self.render_to_response(
|
||||||
|
{
|
||||||
|
**context,
|
||||||
|
"error": "Failed requesting access token",
|
||||||
|
"authorized": False,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
params = parse_qs(response.content)
|
||||||
|
oauth_token = params.get("oauth_token")[0]
|
||||||
|
oauth_secret = params.get("oauth_token_secret")[0]
|
||||||
|
|
||||||
|
request.user.twitter_oauth_token = oauth_token
|
||||||
|
request.user.twitter_oauth_token_secret = oauth_secret
|
||||||
|
request.user.save()
|
||||||
|
|
||||||
|
return self.render_to_response({**context, "error": None, "authorized": True})
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,9 @@ logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
TWITTER_URL = "https://twitter.com"
|
TWITTER_URL = "https://twitter.com"
|
||||||
TWITTER_API_URL = "https://api.twitter.com/1.1"
|
TWITTER_API_URL = "https://api.twitter.com/1.1"
|
||||||
|
TWITTER_REQUEST_TOKEN_URL = "https://api.twitter.com/oauth/request_token"
|
||||||
|
TWITTER_AUTH_URL = "https://api.twitter.com/oauth/authorize"
|
||||||
|
TWITTER_ACCESS_TOKEN_URL = "https://api.twitter.com/oauth/access_token"
|
||||||
|
|
||||||
|
|
||||||
class TwitterBuilder(PostBuilder):
|
class TwitterBuilder(PostBuilder):
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue