PageRenderTime 28ms CodeModel.GetById 19ms RepoModel.GetById 1ms app.codeStats 0ms

/socialregistration/views.py

https://github.com/selwin/django-socialregistration
Python | 391 lines | 276 code | 63 blank | 52 comment | 39 complexity | de0963cce3779c6fc5d069c9ccbc73f7 MD5 | raw file
  1. import uuid
  2. from django.conf import settings
  3. from django.template import RequestContext
  4. from django.core.urlresolvers import reverse
  5. from django.shortcuts import render_to_response
  6. from django.utils.translation import gettext as _
  7. from django.http import HttpResponseRedirect
  8. try:
  9. from django.views.decorators.csrf import csrf_protect
  10. has_csrf = True
  11. except ImportError:
  12. has_csrf = False
  13. from django.contrib.auth.models import User
  14. from django.contrib.auth import login, authenticate, logout as auth_logout
  15. from django.contrib.sites.models import Site
  16. from socialregistration.forms import UserForm
  17. from socialregistration.utils import (OAuthClient, OAuthTwitter,
  18. OpenID, _https, DiscoveryFailure)
  19. from socialregistration.models import FacebookProfile, TwitterProfile, LinkedInProfile, OpenIDProfile
  20. from socialregistration import signals
  21. FB_ERROR = _('We couldn\'t validate your Facebook credentials')
  22. GENERATE_USERNAME = bool(getattr(settings, 'SOCIALREGISTRATION_GENERATE_USERNAME', False))
  23. def _get_next(request):
  24. """
  25. Returns a url to redirect to after the login
  26. """
  27. if 'next' in request.session:
  28. next = request.session['next']
  29. del request.session['next']
  30. return next
  31. elif 'next' in request.GET:
  32. return request.GET.get('next')
  33. elif 'next' in request.POST:
  34. return request.POST.get('next')
  35. else:
  36. return getattr(settings, 'LOGIN_REDIRECT_URL', '/')
  37. def _login(request, user, profile, client):
  38. # we need to persist 'next' across the call to login() as
  39. # it appears to reset the session data.
  40. next = request.session.get('next')
  41. login(request, user)
  42. if next:
  43. request.session['next'] = next
  44. signals.login.send(sender = profile.__class__,
  45. user = user,
  46. profile = profile,
  47. client = client)
  48. def _connect(user, profile, client):
  49. signals.connect.send(sender = profile.__class__,
  50. user = user,
  51. profile = profile,
  52. client = client)
  53. def setup(request, template='socialregistration/setup.html',
  54. form_class=UserForm, extra_context=dict(), initial=dict()):
  55. """
  56. Setup view to create a username & set email address after authentication
  57. """
  58. try:
  59. social_user = request.session['socialregistration_user']
  60. social_profile = request.session['socialregistration_profile']
  61. social_client = request.session['socialregistration_client']
  62. except KeyError:
  63. return render_to_response(
  64. template, dict(error=True), context_instance=RequestContext(request))
  65. if GENERATE_USERNAME:
  66. social_user.username = str(uuid.uuid4())[:30]
  67. social_user.save()
  68. social_profile.user = social_user
  69. social_profile.save()
  70. user = social_profile.authenticate()
  71. else:
  72. if not request.method == "POST":
  73. form = form_class(social_user, social_profile, initial=initial)
  74. extra_context.update({'form': form})
  75. return render_to_response(template, extra_context,
  76. context_instance = RequestContext(request))
  77. form = form_class(social_user, social_profile, request.POST, initial=initial)
  78. if form.is_valid():
  79. form.save(request = request)
  80. user = form.profile.authenticate()
  81. else:
  82. extra_context.update({'form': form})
  83. return render_to_response(template, extra_context,
  84. context_instance = RequestContext(request))
  85. social_client.request = request
  86. # Removing unused bits. It's important to remove the
  87. # client from the session because the session gets written
  88. # to the storage on login and the client holds the request,
  89. # which is going to fail. Might be worth to change the
  90. # clients to not hold the whole request.
  91. if 'socialregistration_user' in request.session:
  92. del request.session['socialregistration_user']
  93. if 'socialregistration_profile' in request.session:
  94. del request.session['socialregistration_profile']
  95. if 'socialregistration_client' in request.session:
  96. del request.session['socialregistration_client']
  97. _connect(user, social_profile, social_client)
  98. _login(request, user, social_profile, social_client)
  99. return HttpResponseRedirect(_get_next(request))
  100. if has_csrf:
  101. setup = csrf_protect(setup)
  102. def facebook_login(request, template='socialregistration/facebook.html',
  103. extra_context=dict(), account_inactive_template='socialregistration/account_inactive.html'):
  104. """
  105. View to handle the Facebook login
  106. """
  107. if request.facebook.uid is None:
  108. extra_context.update(dict(error=FB_ERROR))
  109. return render_to_response(template, extra_context,
  110. context_instance=RequestContext(request))
  111. user = authenticate(uid=request.facebook.uid)
  112. if user is None:
  113. request.session['socialregistration_user'] = User()
  114. request.session['socialregistration_profile'] = FacebookProfile(uid=request.facebook.uid)
  115. request.session['socialregistration_client'] = request.facebook
  116. request.session['next'] = _get_next(request)
  117. return HttpResponseRedirect(reverse('socialregistration_setup'))
  118. if not user.is_active:
  119. return render_to_response(account_inactive_template, extra_context,
  120. context_instance=RequestContext(request))
  121. _login(request, user, FacebookProfile.objects.get(user = user), request.facebook)
  122. return HttpResponseRedirect(_get_next(request))
  123. def facebook_connect(request, template='socialregistration/facebook.html',
  124. extra_context=dict()):
  125. """
  126. View to handle connecting existing django accounts with facebook
  127. """
  128. if request.facebook.uid is None or request.user.is_authenticated() is False:
  129. extra_context.update(dict(error=FB_ERROR))
  130. return render_to_response(template, extra_context,
  131. context_instance=RequestContext(request))
  132. try:
  133. profile = FacebookProfile.objects.get(uid=request.facebook.uid)
  134. except FacebookProfile.DoesNotExist:
  135. profile = FacebookProfile.objects.create(user=request.user,
  136. uid=request.facebook.uid)
  137. _connect(request.user, profile, request.facebook)
  138. return HttpResponseRedirect(_get_next(request))
  139. def logout(request, redirect_url=None):
  140. """
  141. Logs the user out of django. This is only a wrapper around
  142. django.contrib.auth.logout. Logging users out of Facebook for instance
  143. should be done like described in the developer wiki on facebook.
  144. http://wiki.developers.facebook.com/index.php/Connect/Authorization_Websites#Logging_Out_Users
  145. """
  146. auth_logout(request)
  147. url = redirect_url or getattr(settings, 'LOGOUT_REDIRECT_URL', '/')
  148. return HttpResponseRedirect(url)
  149. def twitter(request, account_inactive_template='socialregistration/account_inactive.html',
  150. extra_context=dict(), client_class=None):
  151. """
  152. Actually setup/login an account relating to a twitter user after the oauth
  153. process is finished successfully
  154. """
  155. client = client_class(
  156. request, settings.TWITTER_CONSUMER_KEY,
  157. settings.TWITTER_CONSUMER_SECRET_KEY,
  158. settings.TWITTER_REQUEST_TOKEN_URL,
  159. )
  160. user_info = client.get_user_info()
  161. if request.user.is_authenticated():
  162. # Handling already logged in users connecting their accounts
  163. try:
  164. profile = TwitterProfile.objects.get(twitter_id=user_info['id'])
  165. except TwitterProfile.DoesNotExist: # There can only be one profile!
  166. profile = TwitterProfile.objects.create(user=request.user, twitter_id=user_info['id'])
  167. _connect(request.user, profile, client)
  168. return HttpResponseRedirect(_get_next(request))
  169. user = authenticate(twitter_id=user_info['id'])
  170. if user is None:
  171. profile = TwitterProfile(twitter_id=user_info['id'])
  172. user = User()
  173. request.session['socialregistration_profile'] = profile
  174. request.session['socialregistration_user'] = user
  175. # Client is not pickleable with the request on it
  176. client.request = None
  177. request.session['socialregistration_client'] = client
  178. request.session['next'] = _get_next(request)
  179. return HttpResponseRedirect(reverse('socialregistration_setup'))
  180. if not user.is_active:
  181. return render_to_response(
  182. account_inactive_template,
  183. extra_context,
  184. context_instance=RequestContext(request)
  185. )
  186. _login(request, user, TwitterProfile.objects.get(user = user), client)
  187. return HttpResponseRedirect(_get_next(request))
  188. def linkedin(request, account_inactive_template='socialregistration/account_inactive.html',
  189. extra_context=dict(), client_class=None):
  190. """
  191. Actually setup/login an account relating to a linkedin user after the oauth
  192. process is finished successfully
  193. """
  194. client = client_class(
  195. request, settings.LINKEDIN_CONSUMER_KEY,
  196. settings.LINKEDIN_CONSUMER_SECRET_KEY,
  197. settings.LINKEDIN_REQUEST_TOKEN_URL,
  198. )
  199. user_info = client.get_user_info()
  200. if request.user.is_authenticated():
  201. # Handling already logged in users connecting their accounts
  202. try:
  203. profile = LinkedInProfile.objects.get(linkedin_id=user_info['id'])
  204. except LinkedInProfile.DoesNotExist: # There can only be one profile!
  205. profile = LinkedInProfile.objects.create(user=request.user, linkedin_id=user_info['id'])
  206. _connect(request.user, profile, client)
  207. return HttpResponseRedirect(_get_next(request))
  208. user = authenticate(linkedin_id=user_info['id'])
  209. if user is None:
  210. profile = LinkedInProfile(linkedin_id=user_info['id'])
  211. user = User()
  212. request.session['socialregistration_profile'] = profile
  213. request.session['socialregistration_user'] = user
  214. # Client is not pickleable with the request on it
  215. client.request = None
  216. request.session['socialregistration_client'] = client
  217. request.session['next'] = _get_next(request)
  218. return HttpResponseRedirect(reverse('socialregistration_setup'))
  219. if not user.is_active:
  220. return render_to_response(
  221. account_inactive_template,
  222. extra_context,
  223. context_instance=RequestContext(request)
  224. )
  225. _login(request, user, LinkedInProfile.objects.get(user = user), client)
  226. return HttpResponseRedirect(_get_next(request))
  227. def oauth_redirect(request, consumer_key=None, secret_key=None,
  228. request_token_url=None, access_token_url=None, authorization_url=None,
  229. callback_url=None, parameters=None, client_class = None):
  230. """
  231. View to handle the OAuth based authentication redirect to the service provider
  232. """
  233. request.session['next'] = _get_next(request)
  234. client = client_class(request, consumer_key, secret_key,
  235. request_token_url, access_token_url, authorization_url, callback_url, parameters)
  236. return client.get_redirect()
  237. def oauth_callback(request, consumer_key=None, secret_key=None,
  238. request_token_url=None, access_token_url=None, authorization_url=None,
  239. callback_url=None, template='socialregistration/oauthcallback.html',
  240. extra_context=dict(), parameters=None, client_class = None):
  241. """
  242. View to handle final steps of OAuth based authentication where the user
  243. gets redirected back to from the service provider
  244. """
  245. client = client_class(request, consumer_key, secret_key, request_token_url,
  246. access_token_url, authorization_url, callback_url, parameters)
  247. extra_context.update(dict(oauth_client=client))
  248. if not client.is_valid():
  249. return render_to_response(
  250. template, extra_context, context_instance=RequestContext(request)
  251. )
  252. # We're redirecting to the setup view for this oauth service
  253. return HttpResponseRedirect(reverse(client.callback_url))
  254. def openid_redirect(request, client_class = None):
  255. """
  256. Redirect the user to the openid provider
  257. """
  258. request.session['next'] = _get_next(request)
  259. request.session['openid_provider'] = request.GET.get('openid_provider')
  260. client = client_class(
  261. request,
  262. 'http%s://%s%s' % (
  263. _https(),
  264. Site.objects.get_current().domain,
  265. reverse('openid_callback')
  266. ),
  267. request.GET.get('openid_provider')
  268. )
  269. try:
  270. return client.get_redirect()
  271. except DiscoveryFailure:
  272. request.session['openid_error'] = True
  273. return HttpResponseRedirect(settings.LOGIN_URL)
  274. def openid_callback(request, template='socialregistration/openid.html',
  275. extra_context=dict(), account_inactive_template='socialregistration/account_inactive.html',
  276. client_class = None):
  277. """
  278. Catches the user when he's redirected back from the provider to our site
  279. """
  280. client = client_class(
  281. request,
  282. 'http%s://%s%s' % (
  283. _https(),
  284. Site.objects.get_current().domain,
  285. reverse('openid_callback')
  286. ),
  287. request.session.get('openid_provider')
  288. )
  289. if client.is_valid():
  290. identity = client.result.identity_url
  291. if request.user.is_authenticated():
  292. # Handling already logged in users just connecting their accounts
  293. try:
  294. profile = OpenIDProfile.objects.get(identity=identity)
  295. except OpenIDProfile.DoesNotExist: # There can only be one profile with the same identity
  296. profile = OpenIDProfile.objects.create(user=request.user,
  297. identity=identity)
  298. _connect(request.user, profile, client)
  299. return HttpResponseRedirect(_get_next(request))
  300. user = authenticate(identity=identity)
  301. if user is None:
  302. request.session['socialregistration_user'] = User()
  303. request.session['socialregistration_profile'] = OpenIDProfile(
  304. identity=identity
  305. )
  306. # Client is not pickleable with the request on it
  307. client.request = None
  308. request.session['socialregistration_client'] = client
  309. return HttpResponseRedirect(reverse('socialregistration_setup'))
  310. if not user.is_active:
  311. return render_to_response(
  312. account_inactive_template,
  313. extra_context,
  314. context_instance=RequestContext(request)
  315. )
  316. _login(request, user, OpenIDProfile.objects.get(user = user), client)
  317. return HttpResponseRedirect(_get_next(request))
  318. return render_to_response(
  319. template,
  320. dict(),
  321. context_instance=RequestContext(request)
  322. )