No reason for 'verification_successful = bool' here.
[mediagoblin.git] / mediagoblin / auth / views.py
1 # GNU MediaGoblin -- federated, autonomous media hosting
2 # Copyright (C) 2011 Free Software Foundation, Inc
3 #
4 # This program is free software: you can redistribute it and/or modify
5 # it under the terms of the GNU Affero General Public License as published by
6 # the Free Software Foundation, either version 3 of the License, or
7 # (at your option) any later version.
8 #
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU Affero General Public License for more details.
13 #
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16
17 import uuid
18
19 from webob import Response, exc
20
21 from mediagoblin.db.util import ObjectId
22 from mediagoblin.auth import lib as auth_lib
23 from mediagoblin.auth import forms as auth_forms
24 from mediagoblin.util import send_email
25 from mediagoblin import globals as mgoblin_globals
26
27
28 def register(request):
29 """
30 Your classic registration view!
31 """
32 register_form = auth_forms.RegistrationForm(request.POST)
33
34 if request.method == 'POST' and register_form.validate():
35 # TODO: Make sure the user doesn't exist already
36
37 users_with_username = \
38 request.db.User.find({
39 'username': request.POST['username'].lower()
40 }).count()
41
42 if users_with_username:
43 register_form.username.errors.append(
44 u'Sorry, a user with that name already exists.')
45
46 else:
47 # Create the user
48 entry = request.db.User()
49 entry['username'] = request.POST['username'].lower()
50 entry['email'] = request.POST['email']
51 entry['pw_hash'] = auth_lib.bcrypt_gen_password_hash(
52 request.POST['password'])
53 entry.save(validate=True)
54
55 email_template = request.template_env.get_template(
56 'mediagoblin/auth/verification_email.txt')
57
58 # TODO: There is no error handling in place
59 send_email(
60 mgoblin_globals.email_sender_address,
61 [entry['email']],
62 # TODO
63 # Due to the distributed nature of GNU MediaGoblin, we should
64 # find a way to send some additional information about the
65 # specific GNU MediaGoblin instance in the subject line. For
66 # example "GNU MediaGoblin @ Wandborg - [...]".
67 'GNU MediaGoblin - Verify email',
68 email_template.render(
69 username=entry['username'],
70 verification_url='http://{host}{uri}?userid={userid}&token={verification_key}'.format(
71 host=request.host,
72 uri=request.urlgen('mediagoblin.auth.verify_email'),
73 userid=unicode(entry['_id']),
74 verification_key=entry['verification_key'])))
75
76 # Redirect to register_success
77 return exc.HTTPFound(
78 location=request.urlgen("mediagoblin.auth.register_success"))
79
80 # render
81 template = request.template_env.get_template(
82 'mediagoblin/auth/register.html')
83 return Response(
84 template.render(
85 {'request': request,
86 'register_form': register_form}))
87
88
89 def register_success(request):
90 template = request.template_env.get_template(
91 'mediagoblin/auth/register_success.html')
92 return Response(
93 template.render(
94 {'request': request}))
95
96
97 def login(request):
98 """
99 MediaGoblin login view.
100
101 If you provide the POST with 'next', it'll redirect to that view.
102 """
103 login_form = auth_forms.LoginForm(request.POST)
104
105 login_failed = False
106
107 if request.method == 'POST' and login_form.validate():
108 user = request.db.User.one(
109 {'username': request.POST['username'].lower()})
110
111 if user and user.check_login(request.POST['password']):
112 # set up login in session
113 request.session['user_id'] = unicode(user['_id'])
114 request.session.save()
115
116 if request.POST.get('next'):
117 return exc.HTTPFound(location=request.POST['next'])
118 else:
119 return exc.HTTPFound(
120 location=request.urlgen("index"))
121
122 else:
123 # Prevent detecting who's on this system by testing login
124 # attempt timings
125 auth_lib.fake_login_attempt()
126 login_failed = True
127
128 # render
129 template = request.template_env.get_template(
130 'mediagoblin/auth/login.html')
131 return Response(
132 template.render(
133 {'request': request,
134 'login_form': login_form,
135 'next': request.GET.get('next') or request.POST.get('next'),
136 'login_failed': login_failed}))
137
138
139 def logout(request):
140 # Maybe deleting the user_id parameter would be enough?
141 request.session.delete()
142
143 return exc.HTTPFound(
144 location=request.urlgen("index"))
145
146
147 def verify_email(request):
148 """
149 Email verification view
150
151 validates GET parameters against database and unlocks the user account, if
152 you are lucky :)
153 """
154 # If we don't have userid and token parameters, we can't do anything; 404
155 if not request.GET.has_key('userid') or not request.GET.has_key('token'):
156 return exc.HTTPNotFound()
157
158 user = request.db.User.find_one(
159 {'_id': ObjectId(unicode(request.GET['userid']))})
160
161 if user and user['verification_key'] == unicode(request.GET['token']):
162 user['status'] = u'active'
163 user['email_verified'] = True
164 verification_successful = True
165 user.save()
166 else:
167 verification_successful = False
168
169 template = request.template_env.get_template(
170 'mediagoblin/auth/verify_email.html')
171 return Response(
172 template.render(
173 {'request': request,
174 'user': user,
175 'verification_successful': verification_successful}))
176
177 def verify_email_notice(request):
178 """
179 Verify warning view.
180
181 When the user tries to do some action that requires their account
182 to be verified beforehand, this view is called upon!
183 """
184
185 template = request.template_env.get_template(
186 'mediagoblin/auth/verification_needed.html')
187 return Response(
188 template.render(
189 {'request': request}))
190
191
192 def resend_activation(request):
193 """
194 The reactivation view
195
196 Resend the activation email.
197 """
198 request.user['verification_key'] = unicode(uuid.uuid4())
199 request.user.save()
200
201 # Copied shamelessly from the register view above.
202
203 email_template = request.template_env.get_template(
204 'mediagoblin/auth/verification_email.txt')
205
206 # TODO: There is no error handling in place
207 send_email(
208 mgoblin_globals.email_sender_address,
209 [request.user['email']],
210 # TODO
211 # Due to the distributed nature of GNU MediaGoblin, we should
212 # find a way to send some additional information about the
213 # specific GNU MediaGoblin instance in the subject line. For
214 # example "GNU MediaGoblin @ Wandborg - [...]".
215 'GNU MediaGoblin - Verify email',
216 email_template.render(
217 username=request.user['username'],
218 verification_url='http://{host}{uri}?userid={userid}&token={verification_key}'.format(
219 host=request.host,
220 uri=request.urlgen('mediagoblin.auth.verify_email'),
221 userid=unicode(request.user['_id']),
222 verification_key=request.user['verification_key'])))
223
224 return exc.HTTPFound(
225 location=request.urlgen('mediagoblin.auth.resend_verification_success'))
226
227
228 def resend_activation_success(request):
229 template = request.template_env.get_template(
230 'mediagoblin/auth/resent_verification_email.html')
231 return Response(
232 template.render(
233 {'request': request}))