Skip to content

Commit

Permalink
Added foursquare support
Browse files Browse the repository at this point in the history
  • Loading branch information
flashingpumpkin committed Oct 4, 2011
1 parent 53b848b commit 18f23a7
Show file tree
Hide file tree
Showing 16 changed files with 207 additions and 26 deletions.
4 changes: 3 additions & 1 deletion example/app/views.py
Expand Up @@ -2,6 +2,7 @@
from django.shortcuts import render_to_response
from django.template import RequestContext
from socialregistration.contrib.facebook.models import FacebookProfile
from socialregistration.contrib.foursquare.models import FoursquareProfile
from socialregistration.contrib.github.models import GithubProfile
from socialregistration.contrib.linkedin.models import LinkedInProfile
from socialregistration.contrib.openid.models import OpenIDProfile
Expand All @@ -14,5 +15,6 @@ def index(request):
twitter=TwitterProfile.objects.all(),
openid=OpenIDProfile.objects.all(),
linkedin=LinkedInProfile.objects.all(),
github = GithubProfile.objects.all(),
github=GithubProfile.objects.all(),
foursquare=FoursquareProfile.objects.all(),
), context_instance=RequestContext(request))
9 changes: 8 additions & 1 deletion example/settings.py
Expand Up @@ -117,6 +117,7 @@
'socialregistration.contrib.linkedin',
'socialregistration.contrib.github',
'socialregistration.contrib.facebook',
'socialregistration.contrib.foursquare',
'example.app',
)

Expand Down Expand Up @@ -153,6 +154,7 @@
'socialregistration.contrib.linkedin.auth.LinkedInAuth',
'socialregistration.contrib.github.auth.GithubAuth',
'socialregistration.contrib.facebook.auth.FacebookAuth',
'socialregistration.contrib.foursquare.auth.FoursquareAuth',
)

MIDDLEWARE_CLASSES = (
Expand Down Expand Up @@ -189,9 +191,14 @@

# Add your Github API keys here
GITHUB_CLIENT_ID = ''
GITHUB_SECRET = ''
GITHUB_CLIENT_SECRET = ''
GITHUB_REQUEST_PERMISSIONS = ''

# Add your Foursquare API keys here
FOURSQUARE_CLIENT_ID = ''
FOURSQUARE_CLIENT_SECRET = ''
FOURSQUARE_REQUEST_PERMISSIONS = ''


SOCIALREGISTRATION_USE_HTTPS = False
SOCIALREGISTRATION_GENERATE_USERNAME = False
Expand Down
4 changes: 3 additions & 1 deletion example/templates/index.html
Expand Up @@ -7,12 +7,13 @@ <h1>django-socialregistration login</h2>
<h1>Hi, {{ request.user }}</h1>
{% endif %}

{% load facebook twitter openid linkedin github %}
{% load facebook twitter openid linkedin github foursquare %}
<ol>
<li>{% facebook_button %}</li>
<li>{% twitter_button %}</li>
<li>{% linkedin_button %}</li>
<li>{% github_button %}</li>
<li>{% foursquare_button %}</li>
<li>{% openid_form %}</li>
<li>
<form action="{% url socialregistration:openid:redirect %}" method="post">
Expand All @@ -30,6 +31,7 @@ <h4>Connected profiles:</h4>
<li>Twitter: {{ twitter.count }}</li>
<li>LinkedIn: {{ linkedin.count }}</li>
<li>Github: {{ github.count }}</li>
<li>Foursquare: {{ foursquare.count }}</li>
<li>OpenID: {{ openid.count }}</li>
</ol>

Expand Down
47 changes: 27 additions & 20 deletions socialregistration/clients/oauth.py
Expand Up @@ -120,69 +120,76 @@ class OAuth2(Client):

_access_token = None

def __init__(self, access_token = None):
def __init__(self, access_token=None):
self._access_token = access_token

def client(self):
return httplib2.Http()

def get_redirect_url(self,state = ''):
def get_redirect_url(self, state=''):
params = {
'response_type': 'code',
'client_id': self.client_id,
'client_id': self.client_id,
'redirect_uri': self.get_callback_url(),
'scope': self.scope or '',
'state': state,
}

return '%s?%s' % (self.auth_url, urllib.urlencode(params))

def _get_access_token(self, code):
params = {
def parse_access_token(self, content):
return dict(urlparse.parse_qsl(content))

def request_access_token(self, params):
return self.request(self.access_token_url, method="POST", params=params)

def _get_access_token(self, code, **params):
params.update({
'code': code,
'client_id': self.client_id,
'client_secret': self.secret,
'redirect_uri': self.get_callback_url(),
}
})

resp, content = self.request(self.access_token_url, method = "POST",
params = params)
resp, content = self.request_access_token(params=params)

content = dict(urlparse.parse_qsl(content))
content = self.parse_access_token(content)

if 'error' in content:
raise OAuthError(_(
"Received error while obtaining access token from %s: %s") %(
"Received error while obtaining access token from %s: %s") % (
self.access_token_url, content['error']))

return content

def get_access_token(self, code = None):
def get_access_token(self, code=None, **params):
if self._access_token is None:
if code is None:
raise ValueError(_('Invalid code.'))
self._access_token = self._get_access_token(code)['access_token']

self._access_token = self._get_access_token(code, **params)['access_token']
return self._access_token

def complete(self, GET):
return self.get_access_token(GET.get('code'))
return self.get_access_token(code=GET.get('code'))

def get_signing_params(self):
return dict(access_token=self._access_token)

def request(self, url, method = "GET", params = None, headers = None):
def request(self, url, method="GET", params=None, headers=None):
params = params or {}
headers = headers or {}

params.update(access_token = self._access_token)
params.update(self.get_signing_params())

if method.upper() == "GET":
url = '%s?%s' % (url, urllib.urlencode(params))
return self.client().request(url, method = method, headers = headers)
return self.client().request(url, method, body = urllib.urlencode(params),
headers = headers)
return self.client().request(url, method=method, headers=headers)
return self.client().request(url, method, body=urllib.urlencode(params),
headers=headers)

def get_user_info(self):
raise NotImplementedError

def get_callback_url(self):
raise NotImplementedError


Empty file.
12 changes: 12 additions & 0 deletions socialregistration/contrib/foursquare/auth.py
@@ -0,0 +1,12 @@
from django.contrib.auth.backends import ModelBackend
from django.contrib.sites.models import Site
from socialregistration.contrib.foursquare.models import FoursquareProfile

class FoursquareAuth(ModelBackend):
def authenticate(self, foursquare=None):
try:
return FoursquareProfile.objects.get(
foursquare=foursquare,
site=Site.objects.get_current()).user
except FoursquareProfile.DoesNotExist:
return None
59 changes: 59 additions & 0 deletions socialregistration/contrib/foursquare/client.py
@@ -0,0 +1,59 @@
from django.conf import settings
from django.contrib.sites.models import Site
from django.core.urlresolvers import reverse
from socialregistration.clients.oauth import OAuth2
import json


class Foursquare(OAuth2):
client_id = getattr(settings, 'FOURSQUARE_CLIENT_ID', '')
secret = getattr(settings, 'FOURSQUARE_CLIENT_SECRET', '')
scope = getattr(settings, 'FOURSQUARE_REQUEST_PERMISSIONS', '')

auth_url = 'https://foursquare.com/oauth2/authorize'
access_token_url = 'https://foursquare.com/oauth2/access_token'

_user_info = None

def get_callback_url(self):
if self.is_https():
return 'https://%s%s' % (Site.objects.get_current().domain,
reverse('socialregistration:foursquare:callback'))
return 'http://%s%s' % (Site.objects.get_current().domain,
reverse('socialregistration:foursquare:callback'))

def parse_access_token(self, content):
"""
Forsquare returns JSON instead of url encoded data.
"""
return json.loads(content)

def request_access_token(self, params):
"""
Foursquare does not accept POST requests to retrieve an access token,
so we'll be doing a GET request instead.
"""
return self.request(self.access_token_url, method="GET", params=params)

def get_access_token(self, **params):
"""
Foursquare requires a `grant_type` parameter when requesting the access
token.
"""
return super(Foursquare, self).get_access_token(grant_type='authorization_code', **params)

def get_signing_params(self):
"""
Foursquare requires `oauth_token` parameter instead of `access_token`
"""
return dict(oauth_token=self._access_token)

def get_user_info(self):
if self._user_info is None:
resp, content = self.request('https://api.foursquare.com/v2/users/self')
self._user_info = json.loads(content)['response']['user']
return self._user_info

@staticmethod
def get_session_key():
return 'socialreg:foursquare'
36 changes: 36 additions & 0 deletions socialregistration/contrib/foursquare/models.py
@@ -0,0 +1,36 @@
from django.contrib.auth import authenticate
from django.contrib.auth.models import User
from django.contrib.sites.models import Site
from django.db import models
from socialregistration.signals import connect

class FoursquareProfile(models.Model):
user = models.ForeignKey(User, unique=True)
site = models.ForeignKey(Site, default=Site.objects.get_current)
foursquare = models.CharField(max_length=255)

def __unicode__(self):
try:
return u'%s: %s' % (self.user, self.foursquare)
except User.DoesNotExist:
return u'None'

def authenticate(self):
return authenticate(foursquare=self.foursquare)

class FoursquareAccessToken(models.Model):
profile = models.OneToOneField(FoursquareProfile, related_name='access_token')
access_token = models.CharField(max_length=255)

def save_foursquare_token(sender, user, profile, client, **kwargs):
try:
FoursquareAccessToken.objects.get(profile=profile).delete()
except FoursquareAccessToken.DoesNotExist:
pass

FoursquareAccessToken.objects.create(access_token=client.get_access_token(),
profile=profile)


connect.connect(save_foursquare_token, sender=FoursquareProfile,
dispatch_uid='socialregistration_github_token')
@@ -0,0 +1,3 @@
{% if error %}
<p>{{ error }}</p>
{% endif %}
@@ -0,0 +1,7 @@
<form action="{% url socialregistration:foursquare:redirect %}" method="post">
{% csrf_token %}
{% if next %}
<input type="hidden" name="next" value="{{ next }}" />
{% endif %}
<input type="submit" value="Sign in with Foursquare" />
</form>
Empty file.
@@ -0,0 +1,6 @@
from django import template
from socialregistration.templatetags import button

register = template.Library()

register.tag('foursquare_button', button('socialregistration/foursquare/foursquare_button.html'))
11 changes: 11 additions & 0 deletions socialregistration/contrib/foursquare/urls.py
@@ -0,0 +1,11 @@
from django.conf import settings
from django.conf.urls.defaults import *
from socialregistration.contrib.foursquare.views import FoursquareRedirect, \
FoursquareCallback, FoursquareSetup


urlpatterns = patterns('',
url('^redirect/$', FoursquareRedirect.as_view(), name='redirect'),
url('^callback/$', FoursquareCallback.as_view(), name='callback'),
url('^setup/$', FoursquareSetup.as_view(), name='setup'),
)
24 changes: 24 additions & 0 deletions socialregistration/contrib/foursquare/views.py
@@ -0,0 +1,24 @@
from django.core.urlresolvers import reverse
from socialregistration.contrib.foursquare.client import Foursquare
from socialregistration.contrib.foursquare.models import FoursquareProfile
from socialregistration.views import OAuthRedirect, OAuthCallback, SetupCallback

class FoursquareRedirect(OAuthRedirect):
client = Foursquare
template_name = 'socialregistration/foursquare/foursquare.html'

class FoursquareCallback(OAuthCallback):
client = Foursquare
template_name = 'socialregistration/foursquare/foursquare.html'

def get_redirect(self):
return reverse('socialregistration:foursquare:setup')

class FoursquareSetup(SetupCallback):
client = Foursquare
profile = FoursquareProfile
template_name = 'socialregistration/foursquare/foursquare.html'

def get_lookup_kwargs(self, request, client):
return {'foursquare': client.get_user_info()['id']}

4 changes: 2 additions & 2 deletions socialregistration/contrib/github/client.py
Expand Up @@ -7,7 +7,7 @@

class Github(OAuth2):
client_id = getattr(settings, 'GITHUB_CLIENT_ID', '')
secret = getattr(settings, 'GITHUB_SECRET', '')
secret = getattr(settings, 'GITHUB_CLIENT_SECRET', '')
scope = getattr(settings, 'GITHUB_REQUEST_PERMISSIONS', '')

auth_url = 'https://github.com/login/oauth/authorize'
Expand All @@ -24,7 +24,7 @@ def get_callback_url(self):

def get_user_info(self):
if self._user_info is None:
resp, content = self.request('https://api.github.com/user')
resp, content = self.request('https://api.github.com/user')
self._user_info = json.loads(content)
return self._user_info

Expand Down
7 changes: 6 additions & 1 deletion socialregistration/urls.py
Expand Up @@ -27,7 +27,12 @@
if 'socialregistration.contrib.github' in settings.INSTALLED_APPS:
urlpatterns = urlpatterns + patterns('',
url(r'^github/', include('socialregistration.contrib.github.urls',
namespace = 'github')))
namespace='github')))

if 'socialregistration.contrib.foursquare' in settings.INSTALLED_APPS:
urlpatterns = urlpatterns + patterns('',
url(r'^foursquare/', include('socialregistration.contrib.foursquare.urls',
namespace='foursquare')))

urlpatterns = urlpatterns + patterns('',
url(r'^setup/$', Setup.as_view(), name='setup'),
Expand Down

0 comments on commit 18f23a7

Please sign in to comment.