9add73372c501f8b09f4c4004c3e4a68194ecbc9
[zzz-spline-users.git] / splinext / users / controllers / accounts.py
1 import logging
2 from openid.consumer.consumer import Consumer
3 from openid.extensions.sreg import SRegRequest, SRegResponse
4 from openid.store.filestore import FileOpenIDStore
5 from openid.yadis.discover import DiscoveryFailure
6 from sqlalchemy.orm.exc import NoResultFound
7
8 from pylons import config, request, response, session, tmpl_context as c, url
9 from pylons.controllers.util import abort, redirect_to
10 from routes import request_config
11
12 from spline import model
13 from spline.model import meta
14 from spline.lib import helpers as h
15 from spline.lib.base import BaseController, render
16
17 log = logging.getLogger(__name__)
18
19 class AccountsController(BaseController):
20
21 openid_store = FileOpenIDStore('/var/tmp')
22
23 def _bail(self, reason):
24 # Used for bailing on a login attempt; reshows the login page
25 c.error = reason
26 c.attempted_openid = request.params.get('openid_identifier', '')
27 return render('/users/login.mako')
28
29
30 def login(self):
31 c.error = None
32 c.attempted_openid = None
33 return render('/users/login.mako')
34
35 def login_begin(self):
36 """Step one of logging in with OpenID; we redirect to the provider"""
37
38 cons = Consumer(session=session, store=self.openid_store)
39
40 try:
41 openid_url = request.params['openid_identifier']
42 except KeyError:
43 return self._bail("Gotta enter an OpenID to log in.")
44
45 try:
46 auth_request = cons.begin(openid_url)
47 except DiscoveryFailure:
48 return self._bail(
49 "Can't connect to '{0}'. You sure it's an OpenID?"
50 .format(openid_url)
51 )
52
53 sreg_req = SRegRequest(optional=['nickname', 'email', 'dob', 'gender',
54 'country', 'language', 'timezone'])
55 auth_request.addExtension(sreg_req)
56
57 host = request.headers['host']
58 protocol = request_config().protocol
59 return_url = url(host=host, controller='accounts', action='login_finish')
60 new_url = auth_request.redirectURL(return_to=return_url,
61 realm=protocol + '://' + host)
62 redirect_to(new_url)
63
64 def login_finish(self):
65 """Step two of logging in; the OpenID provider redirects back here."""
66
67 cons = Consumer(session=session, store=self.openid_store)
68 host = request.headers['host']
69 return_url = url(host=host, controller='accounts', action='login_finish')
70 res = cons.complete(request.params, return_url)
71
72 if res.status != 'success':
73 return 'Error! %s' % res.message
74
75 try:
76 # Grab an existing user record, if one exists
77 q = meta.Session.query(model.User) \
78 .filter(model.User.openids.any(openid=res.identity_url))
79 user = q.one()
80 except NoResultFound:
81 # Try to pull a name out of the SReg response
82 sreg_res = SRegResponse.fromSuccessResponse(res)
83 try:
84 username = sreg_res['nickname']
85 except (KeyError, TypeError):
86 # KeyError if sreg has no nickname; TypeError if sreg is None
87 username = 'Anonymous'
88
89 # Create db records
90 user = model.User(name=username)
91 meta.Session.add(user)
92
93 openid = model.OpenID(openid=res.identity_url)
94 user.openids.append(openid)
95
96 meta.Session.commit()
97
98 # Remember who's logged in, and we're good to go
99 session['user_id'] = user.id
100 session.save()
101
102 h.flash(u"""Hello, {0}!""".format(user.name),
103 icon='user')
104
105 redirect_to('/', _code=303)
106
107 def logout(self):
108 """Logs the user out."""
109
110 if 'user_id' in session:
111 del session['user_id']
112 session.save()
113
114 h.flash(u"""Logged out.""",
115 icon='user-silhouette')
116
117 redirect_to('/', _code=303)