mirror of
https://github.com/viq/NewsBlur.git
synced 2025-09-18 21:43:31 +00:00
OAuth -> OAuth 2! For a better feed import experience.
This commit is contained in:
parent
312857bdf8
commit
4892e14f29
5 changed files with 94 additions and 87 deletions
|
@ -1,13 +1,14 @@
|
|||
import datetime
|
||||
import oauth2 as oauth
|
||||
import mongoengine as mongo
|
||||
import httplib2
|
||||
import pickle
|
||||
import base64
|
||||
from collections import defaultdict
|
||||
from StringIO import StringIO
|
||||
from xml.etree.ElementTree import Element, SubElement, Comment, tostring
|
||||
from lxml import etree
|
||||
from django.db import models
|
||||
from django.contrib.auth.models import User
|
||||
from django.conf import settings
|
||||
from mongoengine.queryset import OperationError
|
||||
import vendor.opml as opml
|
||||
from apps.rss_feeds.models import Feed, DuplicateFeed, MStarredStory
|
||||
|
@ -15,7 +16,12 @@ from apps.reader.models import UserSubscription, UserSubscriptionFolders
|
|||
from utils import json_functions as json, urlnorm
|
||||
from utils import log as logging
|
||||
from utils.feed_functions import timelimit
|
||||
|
||||
|
||||
from south.modelsinspector import add_introspection_rules
|
||||
add_introspection_rules([], ["^oauth2client\.django_orm\.FlowField"])
|
||||
add_introspection_rules([], ["^oauth2client\.django_orm\.CredentialsField"])
|
||||
|
||||
|
||||
class OAuthToken(models.Model):
|
||||
user = models.OneToOneField(User, null=True, blank=True)
|
||||
session_id = models.CharField(max_length=50, null=True, blank=True)
|
||||
|
@ -25,6 +31,7 @@ class OAuthToken(models.Model):
|
|||
request_token_secret = models.CharField(max_length=50)
|
||||
access_token = models.CharField(max_length=50)
|
||||
access_token_secret = models.CharField(max_length=50)
|
||||
credential = models.TextField(null=True, blank=True)
|
||||
created_date = models.DateTimeField(default=datetime.datetime.now)
|
||||
|
||||
|
||||
|
@ -225,11 +232,11 @@ class GoogleReaderImporter(Importer):
|
|||
|
||||
if user_tokens.count():
|
||||
user_token = user_tokens[0]
|
||||
consumer = oauth.Consumer(settings.OAUTH_KEY, settings.OAUTH_SECRET)
|
||||
token = oauth.Token(user_token.access_token, user_token.access_token_secret)
|
||||
client = oauth.Client(consumer, token)
|
||||
_, content = client.request(url, 'GET')
|
||||
return content
|
||||
credential = pickle.loads(base64.b64decode(user_token.credential))
|
||||
http = httplib2.Http()
|
||||
http = credential.authorize(http)
|
||||
content = http.request(url)
|
||||
return content and content[1]
|
||||
|
||||
def process_feeds(self, feeds_xml):
|
||||
self.clear_feeds()
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import datetime
|
||||
import urllib
|
||||
import urlparse
|
||||
import pickle
|
||||
import base64
|
||||
from utils import log as logging
|
||||
import oauth2 as oauth
|
||||
from oauth2client.client import OAuth2WebServerFlow
|
||||
import uuid
|
||||
from django.contrib.sites.models import Site
|
||||
from django.db import IntegrityError
|
||||
# from django.db import IntegrityError
|
||||
from django.http import HttpResponse, HttpResponseRedirect
|
||||
from django.conf import settings
|
||||
from django.core.urlresolvers import reverse
|
||||
|
@ -80,34 +80,34 @@ def opml_export(request):
|
|||
)
|
||||
|
||||
return response
|
||||
|
||||
|
||||
|
||||
def reader_authorize(request):
|
||||
is_modal = request.GET.get('modal', False)
|
||||
# is_modal = request.GET.get('modal', False)
|
||||
domain = Site.objects.get_current().domain
|
||||
STEP2_URI = "http://%s%s" % (
|
||||
(domain + '.com') if not domain.endswith('.com') else domain,
|
||||
reverse('google-reader-callback'),
|
||||
)
|
||||
|
||||
FLOW = OAuth2WebServerFlow(
|
||||
client_id=settings.GOOGLE_OAUTH2_CLIENTID,
|
||||
client_secret=settings.GOOGLE_OAUTH2_SECRET,
|
||||
scope="http://www.google.com/reader/api",
|
||||
redirect_uri=STEP2_URI,
|
||||
user_agent='NewsBlur Pro, www.newsblur.com',
|
||||
)
|
||||
logging.user(request, "~BB~FW~SBAuthorize Google Reader import - %s" % (
|
||||
request.META['REMOTE_ADDR'],
|
||||
))
|
||||
oauth_key = settings.OAUTH_KEY
|
||||
oauth_secret = settings.OAUTH_SECRET
|
||||
scope = "http://www.google.com/reader/api"
|
||||
domain = Site.objects.get_current().domain
|
||||
request_token_url = ("https://www.google.com/accounts/OAuthGetRequestToken?"
|
||||
"scope=%s&secure=1&session=1&oauth_callback=http://%s%s%s") % (
|
||||
urllib.quote_plus(scope),
|
||||
domain,
|
||||
reverse('google-reader-callback'),
|
||||
'?modal=true' if is_modal else ''
|
||||
)
|
||||
authorize_url = 'https://www.google.com/accounts/OAuthAuthorizeToken'
|
||||
|
||||
# Grab request token from Google's OAuth
|
||||
consumer = oauth.Consumer(oauth_key, oauth_secret)
|
||||
client = oauth.Client(consumer)
|
||||
resp, content = client.request(request_token_url, "GET")
|
||||
request_token = dict(urlparse.parse_qsl(content))
|
||||
|
||||
authorize_url = FLOW.step1_get_authorize_url(redirect_uri=STEP2_URI)
|
||||
response = render_to_response('social/social_connect.xhtml', {
|
||||
'next': authorize_url,
|
||||
}, context_instance=RequestContext(request))
|
||||
|
||||
# Save request token and delete old tokens
|
||||
auth_token_dict = dict(request_token=request_token['oauth_token'],
|
||||
request_token_secret=request_token['oauth_token_secret'])
|
||||
auth_token_dict = dict()
|
||||
if request.user.is_authenticated():
|
||||
OAuthToken.objects.filter(user=request.user).delete()
|
||||
auth_token_dict['user'] = request.user
|
||||
|
@ -118,23 +118,29 @@ def reader_authorize(request):
|
|||
auth_token_dict['session_id'] = request.session.session_key
|
||||
auth_token_dict['remote_ip'] = request.META['REMOTE_ADDR']
|
||||
OAuthToken.objects.create(**auth_token_dict)
|
||||
|
||||
redirect = "%s?oauth_token=%s" % (authorize_url, request_token['oauth_token'])
|
||||
|
||||
if is_modal:
|
||||
response = render_to_response('social/social_connect.xhtml', {
|
||||
'next': redirect,
|
||||
}, context_instance=RequestContext(request))
|
||||
else:
|
||||
response = HttpResponseRedirect(redirect)
|
||||
|
||||
response.set_cookie('newsblur_reader_uuid', auth_token_dict['uuid'])
|
||||
response.set_cookie('newsblur_reader_uuid', str(uuid.uuid4()))
|
||||
return response
|
||||
|
||||
def reader_callback(request):
|
||||
|
||||
domain = Site.objects.get_current().domain
|
||||
STEP2_URI = "http://%s%s" % (
|
||||
(domain + '.com') if not domain.endswith('.com') else domain,
|
||||
reverse('google-reader-callback'),
|
||||
)
|
||||
FLOW = OAuth2WebServerFlow(
|
||||
client_id=settings.GOOGLE_OAUTH2_CLIENTID,
|
||||
client_secret=settings.GOOGLE_OAUTH2_SECRET,
|
||||
scope="http://www.google.com/reader/api",
|
||||
redirect_uri=STEP2_URI,
|
||||
user_agent='NewsBlur Pro, www.newsblur.com',
|
||||
)
|
||||
FLOW.redirect_uri = STEP2_URI
|
||||
is_modal = request.GET.get('modal', False)
|
||||
access_token_url = 'https://www.google.com/accounts/OAuthGetAccessToken'
|
||||
consumer = oauth.Consumer(settings.OAUTH_KEY, settings.OAUTH_SECRET)
|
||||
|
||||
credential = FLOW.step2_exchange(request.REQUEST)
|
||||
|
||||
user_token = None
|
||||
if request.user.is_authenticated():
|
||||
user_token = OAuthToken.objects.filter(user=request.user).order_by('-created_date')
|
||||
|
@ -148,48 +154,36 @@ def reader_callback(request):
|
|||
user_token = OAuthToken.objects.filter(session_id=request.session.session_key).order_by('-created_date')
|
||||
if not user_token:
|
||||
user_token = OAuthToken.objects.filter(remote_ip=request.META['REMOTE_ADDR']).order_by('-created_date')
|
||||
# logging.info("Found ip user_tokens: %s" % user_tokens)
|
||||
|
||||
if user_token:
|
||||
user_token = user_token[0]
|
||||
user_token.credential = base64.b64encode(pickle.dumps(credential))
|
||||
user_token.session_id = request.session.session_key
|
||||
user_token.save()
|
||||
|
||||
if user_token and request.GET.get('oauth_verifier'):
|
||||
# logging.info("Google Reader request.GET: %s" % request.GET)
|
||||
# Authenticated in Google, so verify and fetch access tokens
|
||||
token = oauth.Token(user_token.request_token, user_token.request_token_secret)
|
||||
token.set_verifier(request.GET['oauth_verifier'])
|
||||
client = oauth.Client(consumer, token)
|
||||
resp, content = client.request(access_token_url, "POST")
|
||||
access_token = dict(urlparse.parse_qsl(content))
|
||||
user_token.access_token = access_token.get('oauth_token')
|
||||
user_token.access_token_secret = access_token.get('oauth_token_secret')
|
||||
try:
|
||||
if not user_token.access_token:
|
||||
raise IntegrityError
|
||||
user_token.save()
|
||||
except IntegrityError:
|
||||
if is_modal:
|
||||
return render_to_response('social/social_connect.xhtml', {
|
||||
'error': 'There was an error trying to import from Google Reader. Trying again will probably fix the issue.'
|
||||
}, context_instance=RequestContext(request))
|
||||
logging.info(" ***> [%s] Bad token from Google Reader. Re-authenticating." % (request.user,))
|
||||
return HttpResponseRedirect(reverse('google-reader-authorize'))
|
||||
|
||||
# Fetch imported feeds on next page load
|
||||
request.session['import_from_google_reader'] = True
|
||||
|
||||
logging.user(request, "~BB~FW~SBFinishing Google Reader import - %s" % (request.META['REMOTE_ADDR'],))
|
||||
|
||||
if request.user.is_authenticated():
|
||||
if is_modal:
|
||||
return render_to_response('social/social_connect.xhtml', {}, context_instance=RequestContext(request))
|
||||
else:
|
||||
return HttpResponseRedirect(reverse('index'))
|
||||
else:
|
||||
logging.info(" ***> [%s] Bad token from Google Reader. Re-authenticating." % (request.user,))
|
||||
return HttpResponseRedirect(reverse('google-reader-authorize'))
|
||||
#
|
||||
# try:
|
||||
# if not user_token.access_token:
|
||||
# raise IntegrityError
|
||||
# user_token.save()
|
||||
# except IntegrityError:
|
||||
# if is_modal:
|
||||
# return render_to_response('social/social_connect.xhtml', {
|
||||
# 'error': 'There was an error trying to import from Google Reader. Trying again will probably fix the issue.'
|
||||
# }, context_instance=RequestContext(request))
|
||||
# logging.info(" ***> [%s] Bad token from Google Reader. Re-authenticating." % (request.user,))
|
||||
# return HttpResponseRedirect(reverse('google-reader-authorize'))
|
||||
|
||||
# Fetch imported feeds on next page load
|
||||
request.session['import_from_google_reader'] = True
|
||||
|
||||
logging.user(request, "~BB~FW~SBFinishing Google Reader import - %s" % (request.META['REMOTE_ADDR'],))
|
||||
|
||||
if request.user.is_authenticated():
|
||||
if is_modal or True:
|
||||
return render_to_response('social/social_connect.xhtml', {}, context_instance=RequestContext(request))
|
||||
else:
|
||||
return HttpResponseRedirect(reverse('index'))
|
||||
|
||||
return HttpResponseRedirect(reverse('import-signup'))
|
||||
|
||||
|
|
|
@ -112,16 +112,16 @@ body.NB-theme-serif #story_pane .NB-feed-story-content {
|
|||
|
||||
.NB-account .NB-import-signup {
|
||||
float: left;
|
||||
width: 142px;
|
||||
width: 146px;
|
||||
padding: 0 0 64px 0;
|
||||
margin: 0 50px 0 12px;
|
||||
margin: 0 24px 0 12px;
|
||||
height: 206px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.NB-account .NB-import-signup-text {
|
||||
text-align: center;
|
||||
width: 152px;
|
||||
width: 190px;
|
||||
}
|
||||
.NB-account .NB-import-signup-text h3 {
|
||||
margin-top: 48px;
|
||||
|
|
|
@ -4089,12 +4089,17 @@
|
|||
if (data.code >= 1) {
|
||||
$bar.progressbar({value: 100});
|
||||
NEWSBLUR.assets.load_feeds();
|
||||
$('.NB-progress-title', $progress).text('');
|
||||
$('.NB-progress-link', $progress).html('');
|
||||
} else {
|
||||
NEWSBLUR.log(['Import Error!', data]);
|
||||
this.$s.$feed_link_loader.fadeOut(250);
|
||||
$progress.addClass('NB-progress-error');
|
||||
$('.NB-progress-title', $progress).text('Error importing Google Reader');
|
||||
$('.NB-progress-link', $progress).html($.make('a', { href: NEWSBLUR.URLs['google-reader-authorize'], className: 'NB-splash-link' }, 'Try importing again'));
|
||||
$('.NB-progress-link', $progress).html($.make('a', {
|
||||
className: 'NB-modal-submit-button NB-modal-submit-green',
|
||||
href: NEWSBLUR.URLs['google-reader-authorize']
|
||||
}, ['Try importing again']));
|
||||
$('.left-center-footer').css('height', 'auto');
|
||||
}
|
||||
},
|
||||
|
|
|
@ -366,6 +366,7 @@ _.extend(NEWSBLUR.ReaderIntro.prototype, {
|
|||
advance_import_carousel: function(page) {
|
||||
var $carousel = $('.carousel', this.$modal);
|
||||
$carousel.carousel('pause');
|
||||
console.log(["Advancing import carousel", page, !_.isNumber(page), NEWSBLUR.assets.feeds.size(), !this.options.force_import]);
|
||||
if (!_.isNumber(page)) {
|
||||
if (NEWSBLUR.assets.feeds.size() && !this.options.force_import) {
|
||||
page = 2;
|
||||
|
@ -381,7 +382,7 @@ _.extend(NEWSBLUR.ReaderIntro.prototype, {
|
|||
$('.NB-tutorial-next-page-text', this.$modal).text('Next step ');
|
||||
}
|
||||
|
||||
$carousel.carousel(page || 0);
|
||||
$carousel.carousel(page && parseInt(page, 10) || 0);
|
||||
$carousel.carousel('pause');
|
||||
this.count_feeds();
|
||||
},
|
||||
|
|
Loading…
Add table
Reference in a new issue