| 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 exc |
| 20 | |
| 21 | from mediagoblin.util import render_to_response, redirect |
| 22 | from mediagoblin.db.util import ObjectId |
| 23 | from mediagoblin.auth import lib as auth_lib |
| 24 | from mediagoblin.auth import forms as auth_forms |
| 25 | from mediagoblin.auth.lib import send_verification_email |
| 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 | send_verification_email(entry, request) |
| 56 | |
| 57 | return redirect(request, "mediagoblin.auth.register_success") |
| 58 | |
| 59 | return render_to_response( |
| 60 | request, |
| 61 | 'mediagoblin/auth/register.html', |
| 62 | {'register_form': register_form}) |
| 63 | |
| 64 | |
| 65 | def login(request): |
| 66 | """ |
| 67 | MediaGoblin login view. |
| 68 | |
| 69 | If you provide the POST with 'next', it'll redirect to that view. |
| 70 | """ |
| 71 | login_form = auth_forms.LoginForm(request.POST) |
| 72 | |
| 73 | login_failed = False |
| 74 | |
| 75 | if request.method == 'POST' and login_form.validate(): |
| 76 | user = request.db.User.one( |
| 77 | {'username': request.POST['username'].lower()}) |
| 78 | |
| 79 | if user and user.check_login(request.POST['password']): |
| 80 | # set up login in session |
| 81 | request.session['user_id'] = unicode(user['_id']) |
| 82 | request.session.save() |
| 83 | |
| 84 | if request.POST.get('next'): |
| 85 | return exc.HTTPFound(location=request.POST['next']) |
| 86 | else: |
| 87 | return redirect(request, "index") |
| 88 | |
| 89 | else: |
| 90 | # Prevent detecting who's on this system by testing login |
| 91 | # attempt timings |
| 92 | auth_lib.fake_login_attempt() |
| 93 | login_failed = True |
| 94 | |
| 95 | return render_to_response( |
| 96 | request, |
| 97 | 'mediagoblin/auth/login.html', |
| 98 | {'login_form': login_form, |
| 99 | 'next': request.GET.get('next') or request.POST.get('next'), |
| 100 | 'login_failed': login_failed}) |
| 101 | |
| 102 | |
| 103 | def logout(request): |
| 104 | # Maybe deleting the user_id parameter would be enough? |
| 105 | request.session.delete() |
| 106 | |
| 107 | return redirect(request, "index") |
| 108 | |
| 109 | |
| 110 | def verify_email(request): |
| 111 | """ |
| 112 | Email verification view |
| 113 | |
| 114 | validates GET parameters against database and unlocks the user account, if |
| 115 | you are lucky :) |
| 116 | """ |
| 117 | # If we don't have userid and token parameters, we can't do anything; 404 |
| 118 | if not request.GET.has_key('userid') or not request.GET.has_key('token'): |
| 119 | return exc.HTTPNotFound() |
| 120 | |
| 121 | user = request.db.User.find_one( |
| 122 | {'_id': ObjectId(unicode(request.GET['userid']))}) |
| 123 | |
| 124 | if user and user['verification_key'] == unicode(request.GET['token']): |
| 125 | user['status'] = u'active' |
| 126 | user['email_verified'] = True |
| 127 | verification_successful = True |
| 128 | user.save() |
| 129 | else: |
| 130 | verification_successful = False |
| 131 | |
| 132 | return render_to_response( |
| 133 | request, |
| 134 | 'mediagoblin/auth/verify_email.html', |
| 135 | {'user': user, |
| 136 | 'verification_successful': verification_successful}) |
| 137 | |
| 138 | |
| 139 | def resend_activation(request): |
| 140 | """ |
| 141 | The reactivation view |
| 142 | |
| 143 | Resend the activation email. |
| 144 | """ |
| 145 | request.user['verification_key'] = unicode(uuid.uuid4()) |
| 146 | request.user.save() |
| 147 | |
| 148 | send_verification_email(request.user, request) |
| 149 | |
| 150 | return redirect(request, 'mediagoblin.auth.resend_verification_success') |