mirror of
https://github.com/samuelclay/NewsBlur.git
synced 2025-09-18 13:22:05 +00:00
Completing Twitter/FB OAuth end to end. Now need to surface and find friends.
This commit is contained in:
parent
c4d4eecc81
commit
d9efea8f1a
11 changed files with 176 additions and 38 deletions
|
@ -1,8 +1,7 @@
|
|||
import datetime
|
||||
import time
|
||||
from django.shortcuts import render_to_response, get_object_or_404
|
||||
from django.shortcuts import get_object_or_404
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.template import RequestContext
|
||||
from django.template.loader import render_to_string
|
||||
from django.db import IntegrityError
|
||||
from django.views.decorators.cache import never_cache
|
||||
|
@ -40,13 +39,14 @@ from utils.story_functions import format_story_link_date__long
|
|||
from utils.story_functions import bunch
|
||||
from utils.story_functions import story_score
|
||||
from utils import log as logging
|
||||
from utils.view_functions import get_argument_or_404
|
||||
from utils.view_functions import get_argument_or_404, render_to
|
||||
from utils.ratelimit import ratelimit
|
||||
from vendor.timezones.utilities import localtime_for_timezone
|
||||
|
||||
SINGLE_DAY = 60*60*24
|
||||
|
||||
@never_cache
|
||||
@render_to('reader/feeds.xhtml')
|
||||
def index(request):
|
||||
if request.method == "POST":
|
||||
if request.POST['submit'] == 'login':
|
||||
|
@ -80,7 +80,7 @@ def index(request):
|
|||
if start_import_from_google_reader:
|
||||
del request.session['import_from_google_reader']
|
||||
|
||||
return render_to_response('reader/feeds.xhtml', {
|
||||
return {
|
||||
'user_profile' : hasattr(user, 'profile') and user.profile,
|
||||
'login_form' : login_form,
|
||||
'signup_form' : signup_form,
|
||||
|
@ -96,7 +96,7 @@ def index(request):
|
|||
'user_statistics' : user_statistics,
|
||||
'feedbacks' : feedbacks,
|
||||
'start_import_from_google_reader': start_import_from_google_reader,
|
||||
}, context_instance=RequestContext(request))
|
||||
}
|
||||
|
||||
@never_cache
|
||||
def login(request):
|
||||
|
|
|
@ -12,6 +12,7 @@ from apps.rss_feeds.models import MStory
|
|||
from apps.social.models import MSharedStory, MSocialServices
|
||||
from utils import json_functions as json
|
||||
from utils.user_functions import get_user, ajax_login_required
|
||||
from utils.view_functions import render_to
|
||||
from utils import log as logging
|
||||
from utils import PyRSS2Gen as RSS
|
||||
from vendor import facebook
|
||||
|
@ -101,6 +102,7 @@ def friends(request):
|
|||
return social_services.to_json()
|
||||
|
||||
@login_required
|
||||
@render_to('social/social_connect.xhtml')
|
||||
def twitter_connect(request):
|
||||
twitter_consumer_key = settings.TWITTER_CONSUMER_KEY
|
||||
twitter_consumer_secret = settings.TWITTER_CONSUMER_SECRET
|
||||
|
@ -118,15 +120,15 @@ def twitter_connect(request):
|
|||
api = tweepy.API(auth)
|
||||
twitter_user = api.me()
|
||||
except (tweepy.error.TweepError, IOError):
|
||||
return json.json_response(request, dict(error="Twitter has returned an error. Try connecting again."))
|
||||
return dict(error="Twitter has returned an error. Try connecting again.")
|
||||
|
||||
# Be sure that two people aren't using the same Twitter account.
|
||||
existing_user = MSocialServices.objects.filter(twitter_uid=unicode(twitter_user.id))
|
||||
if existing_user and existing_user[0].user_id != request.user.pk:
|
||||
user = User.objects.get(pk=existing_user[0].user_id)
|
||||
return json.json_response(request, dict(error=("Another user (%s, %s) has "
|
||||
return dict(error=("Another user (%s, %s) has "
|
||||
"already connected with those Twitter credentials."
|
||||
% (user.username, user.email_address))))
|
||||
% (user.username, user.email_address)))
|
||||
|
||||
social_services, _ = MSocialServices.objects.get_or_create(user_id=request.user.pk)
|
||||
social_services.twitter_uid = unicode(twitter_user.id)
|
||||
|
@ -134,15 +136,16 @@ def twitter_connect(request):
|
|||
social_services.twitter_access_secret = access_token.secret
|
||||
social_services.save()
|
||||
social_services.sync_twitter_friends()
|
||||
return json.json_response(request, dict(code=1))
|
||||
return {}
|
||||
else:
|
||||
# Start the OAuth process
|
||||
auth = tweepy.OAuthHandler(twitter_consumer_key, twitter_consumer_secret)
|
||||
auth_url = auth.get_authorization_url()
|
||||
return HttpResponseRedirect(auth_url)
|
||||
return {'next': auth_url}
|
||||
|
||||
|
||||
@login_required
|
||||
@render_to('social/social_connect.xhtml')
|
||||
def facebook_connect(request):
|
||||
facebook_app_id = settings.FACEBOOK_APP_ID
|
||||
facebook_secret = settings.FACEBOOK_SECRET
|
||||
|
@ -164,7 +167,7 @@ def facebook_connect(request):
|
|||
response = urlparse.parse_qs(response_text)
|
||||
|
||||
if "access_token" not in response:
|
||||
return json.json_response(request, dict(error="Facebook has returned an error. Try connecting again."))
|
||||
return dict(error="Facebook has returned an error. Try connecting again.")
|
||||
|
||||
access_token = response["access_token"][-1]
|
||||
|
||||
|
@ -177,22 +180,22 @@ def facebook_connect(request):
|
|||
existing_user = MSocialServices.objects.filter(facebook_uid=uid)
|
||||
if existing_user and existing_user[0].user_id != request.user.pk:
|
||||
user = User.objects.get(pk=existing_user[0].user_id)
|
||||
return json.json_response(request, dict(error=("Another user (%s, %s) has "
|
||||
return dict(error=("Another user (%s, %s) has "
|
||||
"already connected with those Facebook credentials."
|
||||
% (user.username, user.email_address))))
|
||||
% (user.username, user.email_address)))
|
||||
|
||||
social_services, _ = MSocialServices.objects.get_or_create(user_id=request.user.pk)
|
||||
social_services.facebook_uid = uid
|
||||
social_services.facebook_access_token = access_token
|
||||
social_services.save()
|
||||
social_services.sync_facebook_friends()
|
||||
return json.json_response(request, dict(code=1))
|
||||
return {}
|
||||
elif request.REQUEST.get('error'):
|
||||
pass
|
||||
else:
|
||||
# Start the OAuth process
|
||||
url = "https://www.facebook.com/dialog/oauth?" + urllib.urlencode(args)
|
||||
return HttpResponseRedirect(url)
|
||||
return {'next': url}
|
||||
|
||||
@ajax_login_required
|
||||
def twitter_disconnect(request):
|
||||
|
|
|
@ -279,6 +279,7 @@
|
|||
float: right;
|
||||
position: relative;
|
||||
bottom: -1px;
|
||||
margin-right: 16px;
|
||||
}
|
||||
|
||||
.NB-modal .NB-modal-tab {
|
||||
|
@ -311,7 +312,6 @@
|
|||
margin-top: 0;
|
||||
clear: both;
|
||||
border-top: 1px solid #A0A0A0;
|
||||
padding: 12px 0 0;
|
||||
|
||||
}
|
||||
.NB-modal .NB-tab.NB-active {
|
||||
|
@ -319,7 +319,7 @@
|
|||
}
|
||||
|
||||
.NB-modal .NB-modal-section {
|
||||
padding: 12px 0;
|
||||
padding: 24px 0;
|
||||
border-bottom: 1px solid #A0A0A0;
|
||||
}
|
||||
|
||||
|
|
|
@ -4564,7 +4564,7 @@ background: transparent;
|
|||
background: transparent url('../img/icons/silk/email.png') no-repeat 0 0;
|
||||
}
|
||||
.NB-menu-manage .NB-menu-manage-story-thirdparty .NB-menu-manage-thirdparty-twitter {
|
||||
background: transparent url('../img/reader/twitter_icon_2.png') no-repeat 0 0;
|
||||
background: transparent url('../img/reader/twitter_icon.png') no-repeat 0 0;
|
||||
}
|
||||
.NB-menu-manage .NB-menu-manage-story-thirdparty .NB-menu-manage-thirdparty-facebook {
|
||||
background: transparent url('../img/reader/facebook_icon.png') no-repeat 0 0;
|
||||
|
@ -4839,7 +4839,7 @@ background: transparent;
|
|||
/* ===================== */
|
||||
|
||||
.NB-modal-email .NB-modal-loading {
|
||||
margin: 6px 8px 0;
|
||||
margin: 6px 8px 0;;
|
||||
}
|
||||
.NB-modal-email label {
|
||||
float: left;
|
||||
|
@ -6355,9 +6355,12 @@ background: transparent;
|
|||
/* = Friends Modal = */
|
||||
/* ================= */
|
||||
|
||||
.NB-modal-friends .NB-modal-loading {
|
||||
float: none;
|
||||
margin: 4px 8px 0 0;
|
||||
.NB-modal-friends .NB-tab {
|
||||
min-height: 80px;
|
||||
}
|
||||
.NB-modal-friends .NB-modal-tabs .NB-modal-loading {
|
||||
margin: 6px 8px 0 0;
|
||||
float: left;
|
||||
}
|
||||
.NB-modal-friends .NB-friends-services {
|
||||
overflow: hidden;
|
||||
|
@ -6366,7 +6369,7 @@ background: transparent;
|
|||
float: left;
|
||||
text-align: center;
|
||||
font-weight: bold;
|
||||
margin-right: 12px;
|
||||
margin-right: 0px;
|
||||
}
|
||||
.NB-modal-friends .NB-friends-service-title {
|
||||
float: left;
|
||||
|
@ -6378,10 +6381,13 @@ background: transparent;
|
|||
width: auto;
|
||||
margin-top: -2px;
|
||||
}
|
||||
.NB-modal-friends .NB-friends-service-connect img {
|
||||
vertical-align: bottom;
|
||||
margin: 0 4px 0 0;
|
||||
}
|
||||
.NB-modal-friends .NB-friends-autofollow {
|
||||
width: auto;
|
||||
margin-left: 20px;
|
||||
float: left;
|
||||
float: right;
|
||||
font-size: 12px;
|
||||
position: relative;
|
||||
margin-top: -4px;
|
||||
|
@ -6396,4 +6402,14 @@ background: transparent;
|
|||
margin-left: 20px;
|
||||
display: block;
|
||||
text-align: left;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.NB-modal-friends .NB-tab .NB-ghost {
|
||||
margin: 0 auto;
|
||||
padding: 24px 0;
|
||||
color: #A0A0A0;
|
||||
font-size: 14px;
|
||||
text-align: center;
|
||||
font-weight: bold;
|
||||
}
|
Binary file not shown.
Before Width: | Height: | Size: 698 B After Width: | Height: | Size: 474 B |
Binary file not shown.
Before Width: | Height: | Size: 474 B After Width: | Height: | Size: 698 B |
|
@ -3527,7 +3527,7 @@
|
|||
},
|
||||
|
||||
open_friends_modal: function(score) {
|
||||
NEWSBLUR.friends = new NEWSBLUR.ReaderFriends();
|
||||
NEWSBLUR.reader_friends = new NEWSBLUR.ReaderFriends();
|
||||
},
|
||||
|
||||
open_recommend_modal: function(feed_id) {
|
||||
|
|
|
@ -36,26 +36,27 @@ _.extend(NEWSBLUR.ReaderFriends.prototype, {
|
|||
$.make('div', { className: 'NB-tab NB-tab-findfriends NB-active' }, [
|
||||
$.make('div', { className: 'NB-modal-section NB-friends-services'})
|
||||
]),
|
||||
$.make('div', { className: 'NB-tab NB-tab-following' }, [
|
||||
'List of followings'
|
||||
]),
|
||||
$.make('div', { className: 'NB-tab NB-tab-followers' }, [
|
||||
'List of followers'
|
||||
])
|
||||
$.make('div', { className: 'NB-tab NB-tab-following' }),
|
||||
$.make('div', { className: 'NB-tab NB-tab-followers' })
|
||||
]);
|
||||
},
|
||||
|
||||
fetch_friends: function() {
|
||||
this.model.fetch_friends(_.bind(this.make_friends, this));
|
||||
$('.NB-modal-loading', this.$modal).addClass('NB-active');
|
||||
this.model.fetch_friends(_.bind(function(data) {
|
||||
this.make_friends(data);
|
||||
this.make_followers(data);
|
||||
this.make_following(data);
|
||||
}, this));
|
||||
},
|
||||
|
||||
make_friends: function(data) {
|
||||
console.log(["data", data]);
|
||||
$('.NB-modal-loading', this.$modal).removeClass('NB-active');
|
||||
var $services = $('.NB-friends-services', this.$modal).empty();
|
||||
|
||||
_.each(['twitter', 'facebook'], function(service) {
|
||||
var $service;
|
||||
console.log(["data", data, service, data.services[service][service+'_uid']]);
|
||||
if (data.services[service][service+'_uid']) {
|
||||
$service = $.make('div', { className: 'NB-friends-service NB-connected NB-friends-service-'+service}, [
|
||||
$.make('div', { className: 'NB-friends-service-title' }, _.capitalize(service)),
|
||||
|
@ -64,7 +65,10 @@ _.extend(NEWSBLUR.ReaderFriends.prototype, {
|
|||
} else {
|
||||
$service = $.make('div', { className: 'NB-friends-service NB-friends-service-'+service}, [
|
||||
$.make('div', { className: 'NB-friends-service-title' }, _.capitalize(service)),
|
||||
$.make('div', { className: 'NB-friends-service-connect NB-modal-submit-button NB-modal-submit-green' }, 'Connect to ' + _.capitalize(service))
|
||||
$.make('div', { className: 'NB-friends-service-connect NB-modal-submit-button NB-modal-submit-green' }, [
|
||||
$.make('img', { src: NEWSBLUR.Globals.MEDIA_URL + '/img/reader/' + service + '_icon.png' }),
|
||||
'Connect to ' + _.capitalize(service)
|
||||
])
|
||||
]);
|
||||
}
|
||||
$services.append($service);
|
||||
|
@ -79,6 +83,21 @@ _.extend(NEWSBLUR.ReaderFriends.prototype, {
|
|||
])
|
||||
]);
|
||||
$services.append($autofollow);
|
||||
this.resize();
|
||||
},
|
||||
|
||||
make_followers: function(data) {
|
||||
if (!data.followers || !data.followers.length) {
|
||||
var $ghost = $.make('div', { className: 'NB-ghost NB-modal-section' }, 'Nobody has yet subscribed to your shared stories.');
|
||||
$('.NB-tab-followers', this.$modal).empty().append($ghost);
|
||||
}
|
||||
},
|
||||
|
||||
make_following: function(data) {
|
||||
if (!data.following || !data.following.length) {
|
||||
var $ghost = $.make('div', { className: 'NB-ghost NB-modal-section' }, 'You are not yet subscribing to anybody\'s shared stories.');
|
||||
$('.NB-tab-following', this.$modal).empty().append($ghost);
|
||||
}
|
||||
},
|
||||
|
||||
open_modal: function(callback) {
|
||||
|
@ -130,12 +149,27 @@ _.extend(NEWSBLUR.ReaderFriends.prototype, {
|
|||
$tabs.filter('.NB-tab-'+newtab).addClass('NB-active');
|
||||
},
|
||||
|
||||
connect: function(service) {
|
||||
var options = "location=0,status=0,width=800,height=500";
|
||||
var url = "/social/" + service + "_connect";
|
||||
this.connect_window = window.open(url, '_blank', options);
|
||||
},
|
||||
|
||||
disconnect: function(service) {
|
||||
var $service = $('.NB-friends-service-'+service, this.$modal);
|
||||
$('.NB-friends-service-connect', $service).text('Disconnecting...');
|
||||
this.model.disconnect_social_service(service, _.bind(this.make_friends, this));
|
||||
},
|
||||
|
||||
post_connect: function(data) {
|
||||
if (data.error) {
|
||||
var $error = $.make('div', { className: 'DV-error' }, data.error);
|
||||
$('.NB-friends-services', this.$modal).append($error);
|
||||
} else {
|
||||
this.fetch_friends();
|
||||
}
|
||||
},
|
||||
|
||||
// ===========
|
||||
// = Actions =
|
||||
// ===========
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
<p style="line-height:20px;">Stay up to date and in touch with me, yr. developer, in a few different ways:</p>
|
||||
<p style="line-height: 20px;">
|
||||
<ul style="list-style: none;">
|
||||
<li style="line-height:22px;"><a href="http://twitter.com/samuelclay/" style="text-decoration:none"><img src="http://www.newsblur.com/media/img/reader/twitter_icon_2.png" style="width:16px;height:16px;vertical-align:top;padding-top:3px;"> Follow @samuelclay on Twitter</a>.</li>
|
||||
<li style="line-height:22px;"><a href="http://twitter.com/samuelclay/" style="text-decoration:none"><img src="http://www.newsblur.com/media/img/reader/twitter_icon.png" style="width:16px;height:16px;vertical-align:top;padding-top:3px;"> Follow @samuelclay on Twitter</a>.</li>
|
||||
<li style="line-height:22px;"><a href="http://twitter.com/newsblur/" style="text-decoration:none"><img src="http://www.newsblur.com/media/img/reader/twitter.png" style="width:16px;height:16px;vertical-align:top;padding-top:3px;"> Follow @newsblur on Twitter</a>.</li>
|
||||
<li style="line-height:22px;"><a href="http://github.com/samuelclay/" style="text-decoration:none"><img src="http://www.newsblur.com/media/img/reader/github_icon.png" style="width:16px;height:16px;vertical-align:top;padding-top:3px;"> Follow the constantly evolving source code on GitHub</a>.</li>
|
||||
</ul>
|
||||
|
|
59
templates/social/social_connect.xhtml
Normal file
59
templates/social/social_connect.xhtml
Normal file
|
@ -0,0 +1,59 @@
|
|||
<!DOCTYPE html>
|
||||
|
||||
<html>
|
||||
<title>NewsBlur - Connecting...</title>
|
||||
|
||||
<head>
|
||||
<style>
|
||||
body {
|
||||
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
color: #A0A0A0;
|
||||
font-style: italic;
|
||||
}
|
||||
@-webkit-keyframes spin{
|
||||
from {-webkit-transform: rotate(0deg)}
|
||||
to {-webkit-transform: rotate(360deg)}
|
||||
}
|
||||
.NB-loader {
|
||||
margin: 72px auto;
|
||||
width: 256px;
|
||||
height: 256px;
|
||||
display: block;
|
||||
-webkit-animation: spin 3.4s infinite linear;
|
||||
}
|
||||
</style>
|
||||
<script type="text/javascript" charset="utf-8">
|
||||
var next = "{{ next|safe }}";
|
||||
if (next) {
|
||||
console.log(["next", next]);
|
||||
setTimeout(function() {
|
||||
window.location.href = next;
|
||||
}, 1000);
|
||||
} else if (window.opener && window.opener.NEWSBLUR) {
|
||||
window.opener.NEWSBLUR.reader_friends.post_connect({
|
||||
{% if error %}
|
||||
'error': "{{ error }}",
|
||||
{% endif %}
|
||||
});
|
||||
window.close();
|
||||
} else {
|
||||
window.location.href = "/";
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div style="text-align: center;">
|
||||
|
||||
<img class="NB-loader" src="{{ MEDIA_URL }}img/logo_512.png">
|
||||
|
||||
<div>Hold on just a smidgen...</div>
|
||||
<div>If I was a bird I'd be a pigeon.</div>
|
||||
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -1,8 +1,34 @@
|
|||
from django.http import Http404
|
||||
|
||||
from django.template import RequestContext
|
||||
from django.shortcuts import render_to_response
|
||||
|
||||
def get_argument_or_404(request, param, method='REQUEST'):
|
||||
try:
|
||||
return getattr(request, method)[param]
|
||||
except KeyError:
|
||||
raise Http404
|
||||
raise Http404
|
||||
|
||||
def render_to(template):
|
||||
"""
|
||||
Decorator for Django views that sends returned dict to render_to_response function
|
||||
with given template and RequestContext as context instance.
|
||||
|
||||
If view doesn't return dict then decorator simply returns output.
|
||||
Additionally view can return two-tuple, which must contain dict as first
|
||||
element and string with template name as second. This string will
|
||||
override template name, given as parameter
|
||||
|
||||
Parameters:
|
||||
|
||||
- template: template name to use
|
||||
"""
|
||||
def renderer(func):
|
||||
def wrapper(request, *args, **kw):
|
||||
output = func(request, *args, **kw)
|
||||
if isinstance(output, (list, tuple)):
|
||||
return render_to_response(output[1], output[0], RequestContext(request))
|
||||
elif isinstance(output, dict):
|
||||
return render_to_response(template, output, RequestContext(request))
|
||||
return output
|
||||
return wrapper
|
||||
return renderer
|
Loading…
Add table
Reference in a new issue