root / astakos / im / views.py @ 64cd4730
History | View | Annotate | Download (26.1 kB)
1 |
# Copyright 2011 GRNET S.A. All rights reserved.
|
---|---|
2 |
#
|
3 |
# Redistribution and use in source and binary forms, with or
|
4 |
# without modification, are permitted provided that the following
|
5 |
# conditions are met:
|
6 |
#
|
7 |
# 1. Redistributions of source code must retain the above
|
8 |
# copyright notice, this list of conditions and the following
|
9 |
# disclaimer.
|
10 |
#
|
11 |
# 2. Redistributions in binary form must reproduce the above
|
12 |
# copyright notice, this list of conditions and the following
|
13 |
# disclaimer in the documentation and/or other materials
|
14 |
# provided with the distribution.
|
15 |
#
|
16 |
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
|
17 |
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
18 |
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
19 |
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
|
20 |
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
21 |
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
22 |
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
|
23 |
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
24 |
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
25 |
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
26 |
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
27 |
# POSSIBILITY OF SUCH DAMAGE.
|
28 |
#
|
29 |
# The views and conclusions contained in the software and
|
30 |
# documentation are those of the authors and should not be
|
31 |
# interpreted as representing official policies, either expressed
|
32 |
# or implied, of GRNET S.A.
|
33 |
|
34 |
import json |
35 |
import logging |
36 |
import socket |
37 |
import csv |
38 |
import sys |
39 |
|
40 |
from datetime import datetime |
41 |
from functools import wraps |
42 |
from math import ceil |
43 |
from random import randint |
44 |
from smtplib import SMTPException |
45 |
|
46 |
from django.conf import settings |
47 |
from django.core.mail import send_mail |
48 |
from django.http import HttpResponse, HttpResponseRedirect, HttpResponseBadRequest |
49 |
from django.shortcuts import redirect |
50 |
from django.template.loader import render_to_string |
51 |
from django.shortcuts import render_to_response |
52 |
from django.utils.http import urlencode |
53 |
from django.utils.translation import ugettext as _ |
54 |
from django.core.urlresolvers import reverse |
55 |
from django.forms import Form |
56 |
from django.forms.formsets import formset_factory |
57 |
#from openid.consumer.consumer import Consumer, \
|
58 |
# SUCCESS, CANCEL, FAILURE, SETUP_NEEDED
|
59 |
|
60 |
from hashlib import new as newhasher |
61 |
|
62 |
from urllib import quote |
63 |
|
64 |
#from astakos.im.openid_store import PithosOpenIDStore
|
65 |
from astakos.im.models import User, Invitation |
66 |
from astakos.im.util import isoformat |
67 |
from astakos.im.forms import * |
68 |
|
69 |
def render_response(template, tab=None, status=200, **kwargs): |
70 |
if tab is None: |
71 |
tab = template.partition('_')[0] |
72 |
kwargs.setdefault('tab', tab)
|
73 |
html = render_to_string(template, kwargs) |
74 |
return HttpResponse(html, status=status)
|
75 |
|
76 |
|
77 |
def requires_login(func): |
78 |
@wraps(func)
|
79 |
def wrapper(request, *args): |
80 |
if not settings.BYPASS_ADMIN_AUTH: |
81 |
if not request.user: |
82 |
next = urlencode({'next': request.build_absolute_uri()})
|
83 |
login_uri = reverse(index) + '?' + next |
84 |
return HttpResponseRedirect(login_uri)
|
85 |
return func(request, *args)
|
86 |
return wrapper
|
87 |
|
88 |
def requires_admin(func): |
89 |
@wraps(func)
|
90 |
def wrapper(request, *args): |
91 |
if not settings.BYPASS_ADMIN_AUTH: |
92 |
if not request.user: |
93 |
next = urlencode({'next': request.build_absolute_uri()})
|
94 |
login_uri = reverse(index) + '?' + next |
95 |
return HttpResponseRedirect(login_uri)
|
96 |
if not request.user.is_admin: |
97 |
return HttpResponse('Forbidden', status=403) |
98 |
return func(request, *args)
|
99 |
return wrapper
|
100 |
|
101 |
|
102 |
def index(request): |
103 |
kwargs = {'im_modules':settings.IM_MODULES,
|
104 |
'other_modules':settings.IM_MODULES[1:]} |
105 |
return render_response('index.html', |
106 |
next=request.GET.get('next', ''), |
107 |
**kwargs) |
108 |
|
109 |
|
110 |
@requires_admin
|
111 |
def admin(request): |
112 |
stats = {} |
113 |
stats['users'] = User.objects.count()
|
114 |
stats['pending'] = User.objects.filter(state = 'PENDING').count() |
115 |
|
116 |
invitations = Invitation.objects.all() |
117 |
stats['invitations'] = invitations.count()
|
118 |
stats['invitations_consumed'] = invitations.filter(is_consumed=True).count() |
119 |
|
120 |
return render_response('admin.html', tab='home', stats=stats) |
121 |
|
122 |
|
123 |
@requires_admin
|
124 |
def users_list(request): |
125 |
users = User.objects.order_by('id')
|
126 |
|
127 |
filter = request.GET.get('filter', '') |
128 |
if filter: |
129 |
if filter.startswith('-'): |
130 |
users = users.exclude(uniq__icontains=filter[1:]) |
131 |
else:
|
132 |
users = users.filter(uniq__icontains=filter)
|
133 |
|
134 |
try:
|
135 |
page = int(request.GET.get('page', 1)) |
136 |
except ValueError: |
137 |
page = 1
|
138 |
offset = max(0, page - 1) * settings.ADMIN_PAGE_LIMIT |
139 |
limit = offset + settings.ADMIN_PAGE_LIMIT |
140 |
|
141 |
npages = int(ceil(1.0 * users.count() / settings.ADMIN_PAGE_LIMIT)) |
142 |
prev = page - 1 if page > 1 else None |
143 |
next = page + 1 if page < npages else None |
144 |
return render_response('users_list.html', |
145 |
users=users[offset:limit], |
146 |
filter=filter,
|
147 |
pages=range(1, npages + 1), |
148 |
page=page, |
149 |
prev=prev, |
150 |
next=next)
|
151 |
|
152 |
@requires_admin
|
153 |
def users_info(request, user_id): |
154 |
user = User.objects.get(id=user_id) |
155 |
states = [x[0] for x in User.ACCOUNT_STATE] |
156 |
return render_response('users_info.html', |
157 |
user=user, |
158 |
states=states) |
159 |
|
160 |
|
161 |
@requires_admin
|
162 |
def users_modify(request, user_id): |
163 |
user = User.objects.get(id=user_id) |
164 |
user.uniq = request.POST.get('uniq')
|
165 |
user.realname = request.POST.get('realname')
|
166 |
user.is_admin = True if request.POST.get('admin') else False |
167 |
user.affiliation = request.POST.get('affiliation')
|
168 |
user.state = request.POST.get('state')
|
169 |
user.invitations = int(request.POST.get('invitations') or 0) |
170 |
user.quota = int(request.POST.get('quota') or 0) * (1024 ** 3) # In GiB |
171 |
user.auth_token = request.POST.get('auth_token')
|
172 |
try:
|
173 |
auth_token_expires = request.POST.get('auth_token_expires')
|
174 |
d = datetime.strptime(auth_token_expires, '%Y-%m-%dT%H:%MZ')
|
175 |
user.auth_token_expires = d |
176 |
except ValueError: |
177 |
pass
|
178 |
user.save() |
179 |
return redirect(users_info, user.id)
|
180 |
|
181 |
@requires_admin
|
182 |
def users_delete(request, user_id): |
183 |
user = User.objects.get(id=user_id) |
184 |
user.delete() |
185 |
return redirect(users_list)
|
186 |
|
187 |
@requires_admin
|
188 |
def pending_users(request): |
189 |
users = User.objects.order_by('id')
|
190 |
|
191 |
users = users.filter(state = 'PENDING')
|
192 |
|
193 |
try:
|
194 |
page = int(request.GET.get('page', 1)) |
195 |
except ValueError: |
196 |
page = 1
|
197 |
offset = max(0, page - 1) * settings.ADMIN_PAGE_LIMIT |
198 |
limit = offset + settings.ADMIN_PAGE_LIMIT |
199 |
|
200 |
npages = int(ceil(1.0 * users.count() / settings.ADMIN_PAGE_LIMIT)) |
201 |
prev = page - 1 if page > 1 else None |
202 |
next = page + 1 if page < npages else None |
203 |
return render_response('pending_users.html', |
204 |
users=users[offset:limit], |
205 |
filter=filter,
|
206 |
pages=range(1, npages + 1), |
207 |
page=page, |
208 |
prev=prev, |
209 |
next=next)
|
210 |
|
211 |
def send_greeting(baseurl, user): |
212 |
url = baseurl |
213 |
subject = _('Welcome to Pithos')
|
214 |
message = render_to_string('welcome.txt', {
|
215 |
'user': user,
|
216 |
'url': url,
|
217 |
'baseurl': baseurl,
|
218 |
'service': settings.SERVICE_NAME,
|
219 |
'support': settings.DEFAULT_CONTACT_EMAIL})
|
220 |
sender = settings.DEFAULT_FROM_EMAIL |
221 |
send_mail(subject, message, sender, [user.email]) |
222 |
logging.info('Sent greeting %s', user)
|
223 |
|
224 |
@requires_admin
|
225 |
def users_activate(request, user_id): |
226 |
user = User.objects.get(id=user_id) |
227 |
user.state = 'ACTIVE'
|
228 |
status = 'success'
|
229 |
try:
|
230 |
send_greeting(request.build_absolute_uri('/').rstrip('/'), user) |
231 |
message = _('Greeting sent to %s' % user.email)
|
232 |
user.save() |
233 |
except (SMTPException, socket.error) as e: |
234 |
status = 'error'
|
235 |
name = 'strerror'
|
236 |
message = getattr(e, name) if hasattr(e, name) else e |
237 |
|
238 |
users = User.objects.order_by('id')
|
239 |
users = users.filter(state = 'PENDING')
|
240 |
|
241 |
try:
|
242 |
page = int(request.POST.get('page', 1)) |
243 |
except ValueError: |
244 |
page = 1
|
245 |
offset = max(0, page - 1) * settings.ADMIN_PAGE_LIMIT |
246 |
limit = offset + settings.ADMIN_PAGE_LIMIT |
247 |
|
248 |
npages = int(ceil(1.0 * users.count() / settings.ADMIN_PAGE_LIMIT)) |
249 |
prev = page - 1 if page > 1 else None |
250 |
next = page + 1 if page < npages else None |
251 |
return render_response('pending_users.html', |
252 |
users=users[offset:limit], |
253 |
filter=filter,
|
254 |
pages=range(1, npages + 1), |
255 |
page=page, |
256 |
prev=prev, |
257 |
next=next,
|
258 |
message=message) |
259 |
|
260 |
def generate_invitation_code(): |
261 |
while True: |
262 |
code = randint(1, 2L**63 - 1) |
263 |
try:
|
264 |
Invitation.objects.get(code=code) |
265 |
# An invitation with this code already exists, try again
|
266 |
except Invitation.DoesNotExist:
|
267 |
return code
|
268 |
|
269 |
|
270 |
def send_invitation(baseurl, inv): |
271 |
url = settings.SIGNUP_TARGET % (baseurl, inv.code, quote(baseurl)) |
272 |
subject = _('Invitation to Pithos')
|
273 |
message = render_to_string('invitation.txt', {
|
274 |
'invitation': inv,
|
275 |
'url': url,
|
276 |
'baseurl': baseurl,
|
277 |
'service': settings.SERVICE_NAME,
|
278 |
'support': settings.DEFAULT_CONTACT_EMAIL})
|
279 |
sender = settings.DEFAULT_FROM_EMAIL |
280 |
send_mail(subject, message, sender, [inv.uniq]) |
281 |
logging.info('Sent invitation %s', inv)
|
282 |
|
283 |
|
284 |
@requires_login
|
285 |
def invite(request): |
286 |
status = None
|
287 |
message = None
|
288 |
inviter = request.user |
289 |
|
290 |
if request.method == 'POST': |
291 |
uniq = request.POST.get('uniq')
|
292 |
realname = request.POST.get('realname')
|
293 |
|
294 |
if inviter.invitations > 0: |
295 |
code = generate_invitation_code() |
296 |
invitation, created = Invitation.objects.get_or_create( |
297 |
inviter=inviter, |
298 |
uniq=uniq, |
299 |
defaults={'code': code, 'realname': realname}) |
300 |
|
301 |
try:
|
302 |
send_invitation(request.build_absolute_uri('/').rstrip('/'), invitation) |
303 |
if created:
|
304 |
inviter.invitations = max(0, inviter.invitations - 1) |
305 |
inviter.save() |
306 |
status = 'success'
|
307 |
message = _('Invitation sent to %s' % uniq)
|
308 |
except (SMTPException, socket.error) as e: |
309 |
status = 'error'
|
310 |
message = getattr(e, 'strerror', '') |
311 |
else:
|
312 |
status = 'error'
|
313 |
message = _('No invitations left')
|
314 |
|
315 |
if request.GET.get('format') == 'json': |
316 |
sent = [{'email': inv.uniq,
|
317 |
'realname': inv.realname,
|
318 |
'is_accepted': inv.is_accepted}
|
319 |
for inv in inviter.invitations_sent.all()] |
320 |
rep = {'invitations': inviter.invitations, 'sent': sent} |
321 |
return HttpResponse(json.dumps(rep))
|
322 |
|
323 |
html = render_to_string('invitations.html', {
|
324 |
'user': inviter,
|
325 |
'status': status,
|
326 |
'message': message})
|
327 |
return HttpResponse(html)
|
328 |
|
329 |
def send_verification(baseurl, user): |
330 |
url = settings.ACTIVATION_LOGIN_TARGET % (baseurl, |
331 |
quote(user.auth_token), |
332 |
quote(baseurl)) |
333 |
message = render_to_string('activation.txt', {
|
334 |
'user': user,
|
335 |
'url': url,
|
336 |
'baseurl': baseurl,
|
337 |
'service': settings.SERVICE_NAME,
|
338 |
'support': settings.DEFAULT_CONTACT_EMAIL})
|
339 |
sender = settings.DEFAULT_FROM_EMAIL |
340 |
send_mail('Pithos account activation', message, sender, [user.email])
|
341 |
logging.info('Sent activation %s', user)
|
342 |
|
343 |
def send_password(baseurl, user): |
344 |
url = settings.PASSWORD_RESET_TARGET % (baseurl, |
345 |
quote(user.uniq), |
346 |
quote(baseurl)) |
347 |
message = render_to_string('password.txt', {
|
348 |
'user': user,
|
349 |
'url': url,
|
350 |
'baseurl': baseurl,
|
351 |
'service': settings.SERVICE_NAME,
|
352 |
'support': settings.DEFAULT_CONTACT_EMAIL})
|
353 |
sender = settings.DEFAULT_FROM_EMAIL |
354 |
send_mail('Pithos password recovering', message, sender, [user.email])
|
355 |
logging.info('Sent password %s', user)
|
356 |
|
357 |
def reclaim_password(request): |
358 |
if request.method == 'GET': |
359 |
return render_response('reclaim.html') |
360 |
elif request.method == 'POST': |
361 |
username = request.POST.get('uniq')
|
362 |
try:
|
363 |
user = User.objects.get(uniq=username) |
364 |
try:
|
365 |
send_password(request.build_absolute_uri('/').rstrip('/'), user) |
366 |
status = 'success'
|
367 |
message = _('Password reset sent to %s' % user.email)
|
368 |
user.status = 'UNVERIFIED'
|
369 |
user.save() |
370 |
except (SMTPException, socket.error) as e: |
371 |
status = 'error'
|
372 |
name = 'strerror'
|
373 |
message = getattr(e, name) if hasattr(e, name) else e |
374 |
except User.DoesNotExist:
|
375 |
status = 'error'
|
376 |
message = 'Username does not exist'
|
377 |
|
378 |
html = render_to_string('reclaim.html', {
|
379 |
'status': status,
|
380 |
'message': message})
|
381 |
return HttpResponse(html)
|
382 |
|
383 |
@requires_admin
|
384 |
def invitations_list(request): |
385 |
invitations = Invitation.objects.order_by('id')
|
386 |
|
387 |
filter = request.GET.get('filter', '') |
388 |
if filter: |
389 |
if filter.startswith('-'): |
390 |
invitations = invitations.exclude(uniq__icontains=filter[1:]) |
391 |
else:
|
392 |
invitations = invitations.filter(uniq__icontains=filter)
|
393 |
|
394 |
try:
|
395 |
page = int(request.GET.get('page', 1)) |
396 |
except ValueError: |
397 |
page = 1
|
398 |
offset = max(0, page - 1) * settings.ADMIN_PAGE_LIMIT |
399 |
limit = offset + settings.ADMIN_PAGE_LIMIT |
400 |
|
401 |
npages = int(ceil(1.0 * invitations.count() / settings.ADMIN_PAGE_LIMIT)) |
402 |
prev = page - 1 if page > 1 else None |
403 |
next = page + 1 if page < npages else None |
404 |
return render_response('invitations_list.html', |
405 |
invitations=invitations[offset:limit], |
406 |
filter=filter,
|
407 |
pages=range(1, npages + 1), |
408 |
page=page, |
409 |
prev=prev, |
410 |
next=next)
|
411 |
|
412 |
@requires_admin
|
413 |
def invitations_export(request): |
414 |
# Create the HttpResponse object with the appropriate CSV header.
|
415 |
response = HttpResponse(mimetype='text/csv')
|
416 |
response['Content-Disposition'] = 'attachment; filename=invitations.csv' |
417 |
|
418 |
writer = csv.writer(response) |
419 |
writer.writerow(['ID',
|
420 |
'Uniq',
|
421 |
'Real Name',
|
422 |
'Code',
|
423 |
'Inviter Uniq',
|
424 |
'Inviter Real Name',
|
425 |
'Is_accepted',
|
426 |
'Created',
|
427 |
'Accepted',])
|
428 |
invitations = Invitation.objects.order_by('id')
|
429 |
for inv in invitations: |
430 |
writer.writerow([inv.id, |
431 |
inv.uniq.encode("utf-8"),
|
432 |
inv.realname.encode("utf-8"),
|
433 |
inv.code, |
434 |
inv.inviter.uniq.encode("utf-8"),
|
435 |
inv.inviter.realname.encode("utf-8"),
|
436 |
inv.is_accepted, |
437 |
inv.created, |
438 |
inv.accepted]) |
439 |
|
440 |
return response
|
441 |
|
442 |
|
443 |
@requires_admin
|
444 |
def users_export(request): |
445 |
# Create the HttpResponse object with the appropriate CSV header.
|
446 |
response = HttpResponse(mimetype='text/csv')
|
447 |
response['Content-Disposition'] = 'attachment; filename=users.csv' |
448 |
|
449 |
writer = csv.writer(response) |
450 |
writer.writerow(['ID',
|
451 |
'Uniq',
|
452 |
'Real Name',
|
453 |
'Admin',
|
454 |
'Affiliation',
|
455 |
'State',
|
456 |
'Quota (GiB)',
|
457 |
'Updated',])
|
458 |
users = User.objects.order_by('id')
|
459 |
for u in users: |
460 |
writer.writerow([u.id, |
461 |
u.uniq.encode("utf-8"),
|
462 |
u.realname.encode("utf-8"),
|
463 |
u.is_admin, |
464 |
u.affiliation.encode("utf-8"),
|
465 |
u.state.encode("utf-8"),
|
466 |
u.quota, |
467 |
u.updated]) |
468 |
|
469 |
return response
|
470 |
|
471 |
@requires_admin
|
472 |
def users_create(request): |
473 |
if request.method == 'GET': |
474 |
return render_response('users_local_create.html') |
475 |
if request.method == 'POST': |
476 |
user = User() |
477 |
user.uniq = request.POST.get('uniq')
|
478 |
user.realname = request.POST.get('realname')
|
479 |
user.is_admin = True if request.POST.get('admin') else False |
480 |
user.affiliation = request.POST.get('affiliation')
|
481 |
user.quota = int(request.POST.get('quota') or 0) * (1024 ** 3) # In GiB |
482 |
user.renew_token() |
483 |
user.provider = 'local'
|
484 |
user.save() |
485 |
return redirect(users_info, user.id)
|
486 |
|
487 |
@requires_login
|
488 |
def users_profile(request): |
489 |
next = request.GET.get('next')
|
490 |
try:
|
491 |
user = User.objects.get(uniq=request.user) |
492 |
except User.DoesNotExist:
|
493 |
user = User.objects.get(auth_token=request.GET.get('auth', None)) |
494 |
states = [x[0] for x in User.ACCOUNT_STATE] |
495 |
return render_response('users_profile.html', |
496 |
user=user, |
497 |
states=states, |
498 |
next=next)
|
499 |
|
500 |
@requires_login
|
501 |
def users_edit(request): |
502 |
try:
|
503 |
user = User.objects.get(uniq=request.user) |
504 |
except User.DoesNotExist:
|
505 |
token = request.POST.get('auth', None) |
506 |
users = User.objects.all() |
507 |
user = User.objects.get(auth_token=token) |
508 |
user.realname = request.POST.get('realname')
|
509 |
user.affiliation = request.POST.get('affiliation')
|
510 |
user.is_verified = True
|
511 |
user.save() |
512 |
next = request.POST.get('next')
|
513 |
if next: |
514 |
return redirect(next) |
515 |
|
516 |
status = 'success'
|
517 |
message = _('Profile has been updated')
|
518 |
html = render_to_string('users_profile.html', {
|
519 |
'user': user,
|
520 |
'status': status,
|
521 |
'message': message})
|
522 |
return HttpResponse(html)
|
523 |
|
524 |
def signup(request): |
525 |
if request.method == 'GET': |
526 |
kwargs = {'im_modules':settings.IM_MODULES,
|
527 |
'next':request.GET.get('next', ''), |
528 |
'code':request.GET.get('code', '')} |
529 |
return render_response('signup.html', **kwargs) |
530 |
elif request.method == 'POST': |
531 |
provider = request.POST.get('choice')
|
532 |
if not provider: |
533 |
return on_failure(_('No provider selected'), template='signup.html') |
534 |
|
535 |
kwargs = {'code':request.POST.get('code', ''), |
536 |
'next':request.POST.get('next', '')} |
537 |
url = '%s%s?' %(reverse('astakos.im.views.register'), provider) |
538 |
for k,v in kwargs.items(): |
539 |
if v:
|
540 |
url = '%s%s=%s&' %(url, k, v)
|
541 |
return redirect(url)
|
542 |
|
543 |
def render_registration(provider, code='', next=''): |
544 |
initial_data = {'provider':provider}
|
545 |
if settings.INVITATIONS_ENABLED and code: |
546 |
try:
|
547 |
print '#', type(code), code |
548 |
invitation = Invitation.objects.get(code=code) |
549 |
if invitation.is_consumed:
|
550 |
return HttpResponseBadRequest('Invitation has beeen used') |
551 |
initial_data.update({'uniq':invitation.uniq,
|
552 |
'email':invitation.uniq,
|
553 |
'realname':invitation.realname})
|
554 |
try:
|
555 |
inviter = User.objects.get(uniq=invitation.inviter) |
556 |
initial_data['inviter'] = inviter.realname
|
557 |
except User.DoesNotExist:
|
558 |
pass
|
559 |
except Invitation.DoesNotExist:
|
560 |
return on_failure(_('Wrong invitation code'), template='register.html') |
561 |
|
562 |
prefix = 'Invited' if code else '' |
563 |
formclassname = '%s%sRegisterForm' %(prefix, provider.capitalize())
|
564 |
formclass_ = getattr(sys.modules['astakos.im.forms'], formclassname) |
565 |
RegisterFormSet = formset_factory(formclass_, extra=0)
|
566 |
formset = RegisterFormSet(initial=[initial_data]) |
567 |
return render_response('register.html', |
568 |
formset=formset, |
569 |
next=next,
|
570 |
filter=filter,
|
571 |
code=code) |
572 |
|
573 |
def is_preaccepted(user): |
574 |
if user.invitation and not user.invitation.is_consumed: |
575 |
return True |
576 |
|
577 |
return False |
578 |
|
579 |
def should_send_verification(): |
580 |
if not settings.INVITATIONS_ENABLED: |
581 |
return True |
582 |
return False |
583 |
|
584 |
def register(request, provider): |
585 |
print '---', request |
586 |
code = request.GET.get('code')
|
587 |
next = request.GET.get('next')
|
588 |
if request.method == 'GET': |
589 |
code = request.GET.get('code', '') |
590 |
next = request.GET.get('next', '') |
591 |
if provider not in settings.IM_MODULES: |
592 |
return on_failure(_('Invalid provider')) |
593 |
return render_registration(provider, code, next) |
594 |
elif request.method == 'POST': |
595 |
provider = request.POST.get('form-0-provider')
|
596 |
inviter = request.POST.get('form-0-inviter')
|
597 |
|
598 |
#instantiate the form
|
599 |
prefix = 'Invited' if inviter else '' |
600 |
formclassname = '%sRegisterForm' %(provider.capitalize())
|
601 |
formclass_ = getattr(sys.modules['astakos.im.forms'], formclassname) |
602 |
RegisterFormSet = formset_factory(formclass_, extra=0)
|
603 |
formset = RegisterFormSet(request.POST) |
604 |
if not formset.is_valid(): |
605 |
return render_to_response('register.html', |
606 |
{'formset':formset,
|
607 |
'code':code,
|
608 |
'next':next}) |
609 |
|
610 |
user = User() |
611 |
for form in formset.forms: |
612 |
for field in form.fields: |
613 |
if hasattr(user, field): |
614 |
setattr(user, field, form.cleaned_data[field])
|
615 |
break
|
616 |
|
617 |
if user.openidurl:
|
618 |
redirect_url = reverse('astakos.im.views.create')
|
619 |
return ask_openid(request,
|
620 |
user.openidurl, |
621 |
redirect_url, |
622 |
'signup')
|
623 |
|
624 |
#save hashed password
|
625 |
if user.password:
|
626 |
hasher = newhasher('sha256')
|
627 |
hasher.update(user.password) |
628 |
user.password = hasher.hexdigest() |
629 |
|
630 |
user.renew_token() |
631 |
|
632 |
if is_preaccepted(user):
|
633 |
user.state = 'ACTIVE'
|
634 |
user.save() |
635 |
url = reverse('astakos.im.views.index')
|
636 |
return redirect(url)
|
637 |
|
638 |
status = 'success'
|
639 |
if should_send_verification():
|
640 |
try:
|
641 |
send_verification(request.build_absolute_uri('/').rstrip('/'), user) |
642 |
message = _('Verification sent to %s' % user.email)
|
643 |
user.save() |
644 |
except (SMTPException, socket.error) as e: |
645 |
status = 'error'
|
646 |
name = 'strerror'
|
647 |
message = getattr(e, name) if hasattr(e, name) else e |
648 |
else:
|
649 |
user.save() |
650 |
message = _('Registration completed. You will receive an email upon your account\'s activation')
|
651 |
|
652 |
return info(status, message)
|
653 |
|
654 |
#def discover_extensions(openid_url):
|
655 |
# service = discover(openid_url)
|
656 |
# use_ax = False
|
657 |
# use_sreg = False
|
658 |
# for endpoint in service[1]:
|
659 |
# if not use_sreg:
|
660 |
# use_sreg = sreg.supportsSReg(endpoint)
|
661 |
# if not use_ax:
|
662 |
# use_ax = endpoint.usesExtension("http://openid.net/srv/ax/1.0")
|
663 |
# if use_ax and use_sreg: break
|
664 |
# return use_ax, use_sreg
|
665 |
#
|
666 |
#def ask_openid(request, openid_url, redirect_to, on_failure=None):
|
667 |
# """ basic function to ask openid and return response """
|
668 |
# on_failure = on_failure or signin_failure
|
669 |
# sreg_req = None
|
670 |
# ax_req = None
|
671 |
#
|
672 |
# trust_root = getattr(
|
673 |
# settings, 'OPENID_TRUST_ROOT', request.build_absolute_uri() + '/'
|
674 |
# )
|
675 |
# request.session = {}
|
676 |
# consumer = Consumer(request.session, PithosOpenIDStore())
|
677 |
# try:
|
678 |
# auth_request = consumer.begin(openid_url)
|
679 |
# except DiscoveryFailure:
|
680 |
# msg = _("The OpenID %s was invalid") % openid_url
|
681 |
# return on_failure(request, msg)
|
682 |
#
|
683 |
# get capabilities
|
684 |
# use_ax, use_sreg = discover_extensions(openid_url)
|
685 |
# if use_sreg:
|
686 |
# set sreg extension
|
687 |
# we always ask for nickname and email
|
688 |
# sreg_attrs = getattr(settings, 'OPENID_SREG', {})
|
689 |
# sreg_attrs.update({ "optional": ['nickname', 'email'] })
|
690 |
# sreg_req = sreg.SRegRequest(**sreg_attrs)
|
691 |
# if use_ax:
|
692 |
# set ax extension
|
693 |
# we always ask for nickname and email
|
694 |
# ax_req = ax.FetchRequest()
|
695 |
# ax_req.add(ax.AttrInfo('http://schema.openid.net/contact/email',
|
696 |
# alias='email', required=True))
|
697 |
# ax_req.add(ax.AttrInfo('http://schema.openid.net/namePerson/friendly',
|
698 |
# alias='nickname', required=True))
|
699 |
#
|
700 |
# add custom ax attrs
|
701 |
# ax_attrs = getattr(settings, 'OPENID_AX', [])
|
702 |
# for attr in ax_attrs:
|
703 |
# if len(attr) == 2:
|
704 |
# ax_req.add(ax.AttrInfo(attr[0], required=alias[1]))
|
705 |
# else:
|
706 |
# ax_req.add(ax.AttrInfo(attr[0]))
|
707 |
#
|
708 |
# if sreg_req is not None:
|
709 |
# auth_request.addExtension(sreg_req)
|
710 |
# if ax_req is not None:
|
711 |
# auth_request.addExtension(ax_req)
|
712 |
#
|
713 |
# redirect_url = auth_request.redirectURL(trust_root, redirect_to)
|
714 |
# return HttpResponseRedirect(redirect_url)
|
715 |
|
716 |
def info(status, message, template='base.html'): |
717 |
html = render_to_string(template, { |
718 |
'status': status,
|
719 |
'message': message})
|
720 |
response = HttpResponse(html) |
721 |
return response
|
722 |
|
723 |
def on_success(message, template='base.html'): |
724 |
return info('success', message) |
725 |
|
726 |
def on_failure(message, template='base.html'): |
727 |
return info('error', message) |