moved forgot pw views to basic_auth plugin
authorRodney Ewing <ewing.rj@gmail.com>
Tue, 7 May 2013 15:36:04 +0000 (08:36 -0700)
committerRodney Ewing <ewing.rj@gmail.com>
Fri, 24 May 2013 23:52:47 +0000 (16:52 -0700)
mediagoblin/auth/forms.py
mediagoblin/auth/lib.py
mediagoblin/auth/routing.py
mediagoblin/auth/views.py
mediagoblin/plugins/basic_auth/forms.py
mediagoblin/plugins/basic_auth/templates/mediagoblin/plugins/basic_auth/change_fp.html [new file with mode: 0644]
mediagoblin/plugins/basic_auth/templates/mediagoblin/plugins/basic_auth/forgot_password.html [new file with mode: 0644]
mediagoblin/plugins/basic_auth/views.py [new file with mode: 0644]
mediagoblin/templates/mediagoblin/auth/forgot_password.html

index bab0d35e15af089e68557911ab2b2bc9e689adbe..7a67285b4e1b8241a38950d77ec53d8070aebe0c 100644 (file)
@@ -16,7 +16,6 @@
 
 import wtforms
 
-from mediagoblin.tools.mail import normalize_email
 from mediagoblin.tools.translate import lazy_pass_to_ugettext as _
 from mediagoblin.auth.tools import normalize_user_or_email_field
 
index 8829995a7083f423b8072dfcb350d27c9c97331c..6ce23f5b50b7a9e89fd23ab3783a8f2cfcb5afe4 100644 (file)
@@ -143,7 +143,7 @@ def send_fp_verification_email(user, request):
         {'username': user.username,
          'verification_url': EMAIL_FP_VERIFICATION_TEMPLATE.format(
                 host=request.host,
-                uri=request.urlgen('mediagoblin.auth.verify_forgot_password'),
+                uri=request.urlgen('mediagoblin.plugins.basic_auth.verify_forgot_password'),
                 userid=unicode(user.id),
                 fp_verification_key=user.fp_verification_key)})
 
index 2a6abb47df4a0ce608acdcc9096419192bc1230d..7a688a49eee55508b1f8df12cb48062094006f35 100644 (file)
@@ -25,9 +25,4 @@ auth_routes = [
     ('mediagoblin.auth.verify_email', '/verify_email/',
      'mediagoblin.auth.views:verify_email'),
     ('mediagoblin.auth.resend_verification', '/resend_verification/',
-     'mediagoblin.auth.views:resend_activation'),
-    ('mediagoblin.auth.forgot_password', '/forgot_password/',
-     'mediagoblin.auth.views:forgot_password'),
-    ('mediagoblin.auth.verify_forgot_password',
-     '/forgot_password/verify/',
-     'mediagoblin.auth.views:verify_forgot_password')]
+     'mediagoblin.auth.views:resend_activation')]
index 2b3b036a0aebf3fd50cd3515b74dd2f5b07f4b0e..ec40930381c53265fca8d66f733f54469a936997 100644 (file)
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 import uuid
-import datetime
 
 from mediagoblin import messages, mg_globals
 from mediagoblin.db.models import User
 from mediagoblin.tools.response import render_to_response, redirect, render_404
 from mediagoblin.tools.translate import pass_to_ugettext as _
 from mediagoblin.auth import lib as auth_lib
-from mediagoblin.auth import forms as auth_forms
-from mediagoblin.auth.lib import send_verification_email, \
-                                 send_fp_verification_email
+from mediagoblin.auth.lib import send_verification_email
 import mediagoblin.auth as auth
-from sqlalchemy import or_
+
 
 def email_debug_message(request):
     """
@@ -203,141 +200,3 @@ def resend_activation(request):
     return redirect(
         request, 'mediagoblin.user_pages.user_home',
         user=request.user.username)
-
-
-def forgot_password(request):
-    """
-    Forgot password view
-
-    Sends an email with an url to renew forgotten password.
-    Use GET querystring parameter 'username' to pre-populate the input field
-    """
-    fp_form = auth_forms.ForgotPassForm(request.form,
-                                        username=request.args.get('username'))
-
-    if not (request.method == 'POST' and fp_form.validate()):
-        # Either GET request, or invalid form submitted. Display the template
-        return render_to_response(request,
-            'mediagoblin/auth/forgot_password.html', {'fp_form': fp_form})
-
-    # If we are here: method == POST and form is valid. username casing
-    # has been sanitized. Store if a user was found by email. We should
-    # not reveal if the operation was successful then as we don't want to
-    # leak if an email address exists in the system.
-    found_by_email = '@' in fp_form.username.data
-
-    if found_by_email:
-        user = User.query.filter_by(
-            email = fp_form.username.data).first()
-        # Don't reveal success in case the lookup happened by email address.
-        success_message=_("If that email address (case sensitive!) is "
-                          "registered an email has been sent with instructions "
-                          "on how to change your password.")
-
-    else: # found by username
-        user = User.query.filter_by(
-            username = fp_form.username.data).first()
-
-        if user is None:
-            messages.add_message(request,
-                                 messages.WARNING,
-                                 _("Couldn't find someone with that username."))
-            return redirect(request, 'mediagoblin.auth.forgot_password')
-
-        success_message=_("An email has been sent with instructions "
-                          "on how to change your password.")
-
-    if user and not(user.email_verified and user.status == 'active'):
-        # Don't send reminder because user is inactive or has no verified email
-        messages.add_message(request,
-            messages.WARNING,
-            _("Could not send password recovery email as your username is in"
-              "active or your account's email address has not been verified."))
-
-        return redirect(request, 'mediagoblin.user_pages.user_home',
-                        user=user.username)
-
-    # SUCCESS. Send reminder and return to login page
-    if user:
-        user.fp_verification_key = unicode(uuid.uuid4())
-        user.fp_token_expire = datetime.datetime.now() + \
-                               datetime.timedelta(days=10)
-        user.save()
-
-        email_debug_message(request)
-        send_fp_verification_email(user, request)
-
-    messages.add_message(request, messages.INFO, success_message)
-    return redirect(request, 'mediagoblin.auth.login')
-
-
-def verify_forgot_password(request):
-    """
-    Check the forgot-password verification and possibly let the user
-    change their password because of it.
-    """
-    # get form data variables, and specifically check for presence of token
-    formdata = _process_for_token(request)
-    if not formdata['has_userid_and_token']:
-        return render_404(request)
-
-    formdata_token = formdata['vars']['token']
-    formdata_userid = formdata['vars']['userid']
-    formdata_vars = formdata['vars']
-
-    # check if it's a valid user id
-    user = User.query.filter_by(id=formdata_userid).first()
-    if not user:
-        return render_404(request)
-
-    # check if we have a real user and correct token
-    if ((user and user.fp_verification_key and
-         user.fp_verification_key == unicode(formdata_token) and
-         datetime.datetime.now() < user.fp_token_expire
-         and user.email_verified and user.status == 'active')):
-
-        cp_form = auth_forms.ChangePassForm(formdata_vars)
-
-        if request.method == 'POST' and cp_form.validate():
-            user.pw_hash = auth_lib.bcrypt_gen_password_hash(
-                cp_form.password.data)
-            user.fp_verification_key = None
-            user.fp_token_expire = None
-            user.save()
-
-            messages.add_message(
-                request,
-                messages.INFO,
-                _("You can now log in using your new password."))
-            return redirect(request, 'mediagoblin.auth.login')
-        else:
-            return render_to_response(
-                request,
-                'mediagoblin/auth/change_fp.html',
-                {'cp_form': cp_form})
-
-    # in case there is a valid id but no user with that id in the db
-    # or the token expired
-    else:
-        return render_404(request)
-
-
-def _process_for_token(request):
-    """
-    Checks for tokens in formdata without prior knowledge of request method
-
-    For now, returns whether the userid and token formdata variables exist, and
-    the formdata variables in a hash. Perhaps an object is warranted?
-    """
-    # retrieve the formdata variables
-    if request.method == 'GET':
-        formdata_vars = request.GET
-    else:
-        formdata_vars = request.form
-
-    formdata = {
-        'vars': formdata_vars,
-        'has_userid_and_token':
-            'userid' in formdata_vars and 'token' in formdata_vars}
-
-    return formdata
index 28eb7d0acd92795c71261ec10c48987cf4345f63..6598169108bbf85b8524a4fef39a1ac3448b4250 100644 (file)
@@ -28,3 +28,23 @@ class LoginForm(wtforms.Form):
         _('Password'),
         [wtforms.validators.Required(),
          wtforms.validators.Length(min=5, max=1024)])
+
+
+class ForgotPassForm(wtforms.Form):
+    username = wtforms.TextField(
+        _('Username or email'),
+        [wtforms.validators.Required(),
+         normalize_user_or_email_field()])
+
+
+class ChangePassForm(wtforms.Form):
+    password = wtforms.PasswordField(
+        'Password',
+        [wtforms.validators.Required(),
+         wtforms.validators.Length(min=5, max=1024)])
+    userid = wtforms.HiddenField(
+        '',
+        [wtforms.validators.Required()])
+    token = wtforms.HiddenField(
+        '',
+        [wtforms.validators.Required()])
diff --git a/mediagoblin/plugins/basic_auth/templates/mediagoblin/plugins/basic_auth/change_fp.html b/mediagoblin/plugins/basic_auth/templates/mediagoblin/plugins/basic_auth/change_fp.html
new file mode 100644 (file)
index 0000000..9ce12e1
--- /dev/null
@@ -0,0 +1,44 @@
+{#
+# GNU MediaGoblin -- federated, autonomous media hosting
+# Copyright (C) 2011 Free Software Foundation, Inc
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#}
+{% extends "mediagoblin/base.html" %}
+
+{% import "/mediagoblin/utils/wtforms.html" as wtforms_util %}
+
+{% block mediagoblin_head %}
+  <script type="text/javascript"
+          src="{{ request.staticdirect('/js/show_password.js') }}"></script>
+{% endblock mediagoblin_head %}
+
+{% block title -%}
+  {% trans %}Set your new password{% endtrans %} &mdash; {{ super() }}
+{%- endblock %}
+
+{% block mediagoblin_content %}
+  <form action="{{ request.urlgen('mediagoblin.plugins.basic_auth.verify_forgot_password') }}"
+        method="POST" enctype="multipart/form-data">
+    {{ csrf_token }}
+    <div class="form_box">
+      <h1>{% trans %}Set your new password{% endtrans %}</h1>
+      {{ wtforms_util.render_divs(cp_form) }}
+      <div class="form_submit_buttons">
+        <input type="submit" value="{% trans %}Set password{% endtrans %}" class="button_form"/>
+      </div>
+    </div>
+  </form>
+{% endblock %}
+
diff --git a/mediagoblin/plugins/basic_auth/templates/mediagoblin/plugins/basic_auth/forgot_password.html b/mediagoblin/plugins/basic_auth/templates/mediagoblin/plugins/basic_auth/forgot_password.html
new file mode 100644 (file)
index 0000000..98cd9a0
--- /dev/null
@@ -0,0 +1,38 @@
+{#
+# GNU MediaGoblin -- federated, autonomous media hosting
+# Copyright (C) 2011 Free Software Foundation, Inc
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#}
+{% extends "mediagoblin/base.html" %}
+
+{% import "/mediagoblin/utils/wtforms.html" as wtforms_util %}
+
+{% block title -%}
+  {% trans %}Recover password{% endtrans %} &mdash; {{ super() }}
+{%- endblock %}
+
+{% block mediagoblin_content %}
+  <form action="{{ request.urlgen('mediagoblin.plugins.basic_auth.forgot_password') }}"
+        method="POST" enctype="multipart/form-data">
+    {{ csrf_token }}
+    <div class="form_box">
+      <h1>{% trans %}Recover password{% endtrans %}</h1>
+      {{ wtforms_util.render_divs(fp_form) }}
+      <div class="form_submit_buttons">
+        <input type="submit" value="{% trans %}Send instructions{% endtrans %}" class="button_form"/>
+      </div>
+    </div>
+  </form>
+{% endblock %}
diff --git a/mediagoblin/plugins/basic_auth/views.py b/mediagoblin/plugins/basic_auth/views.py
new file mode 100644 (file)
index 0000000..69d2c52
--- /dev/null
@@ -0,0 +1,165 @@
+# GNU MediaGoblin -- federated, autonomous media hosting
+# Copyright (C) 2011, 2012 MediaGoblin contributors.  See AUTHORS.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+import uuid
+import datetime
+
+import forms as auth_forms
+from mediagoblin.tools.response import render_to_response, redirect, render_404
+from mediagoblin.db.models import User
+from mediagoblin.tools.translate import pass_to_ugettext as _
+from mediagoblin import messages
+from mediagoblin.auth.views import email_debug_message
+from mediagoblin.auth.lib import send_fp_verification_email
+from mediagoblin.auth import lib as auth_lib
+
+
+
+def forgot_password(request):
+    """
+    Forgot password view
+
+    Sends an email with an url to renew forgotten password.
+    Use GET querystring parameter 'username' to pre-populate the input field
+    """
+    fp_form = auth_forms.ForgotPassForm(request.form,
+                                        username=request.args.get('username'))
+
+    if not (request.method == 'POST' and fp_form.validate()):
+        # Either GET request, or invalid form submitted. Display the template
+        return render_to_response(request,
+            'mediagoblin/plugins/basic_auth/forgot_password.html', {'fp_form': fp_form})
+
+    # If we are here: method == POST and form is valid. username casing
+    # has been sanitized. Store if a user was found by email. We should
+    # not reveal if the operation was successful then as we don't want to
+    # leak if an email address exists in the system.
+    found_by_email = '@' in fp_form.username.data
+
+    if found_by_email:
+        user = User.query.filter_by(
+            email=fp_form.username.data).first()
+        # Don't reveal success in case the lookup happened by email address.
+        success_message = _("If that email address (case sensitive!) is "
+                            "registered an email has been sent with "
+                            "instructions on how to change your password.")
+
+    else:  # found by username
+        user = User.query.filter_by(
+            username=fp_form.username.data).first()
+
+        if user is None:
+            messages.add_message(request,
+                                 messages.WARNING,
+                                 _("Couldn't find someone with that username."))
+            return redirect(request, 'mediagoblin.auth.forgot_password')
+
+        success_message = _("An email has been sent with instructions "
+                            "on how to change your password.")
+
+    if user and not(user.email_verified and user.status == 'active'):
+        # Don't send reminder because user is inactive or has no verified email
+        messages.add_message(request,
+            messages.WARNING,
+            _("Could not send password recovery email as your username is in"
+              "active or your account's email address has not been verified."))
+
+        return redirect(request, 'mediagoblin.user_pages.user_home',
+                        user=user.username)
+
+    # SUCCESS. Send reminder and return to login page
+    if user:
+        user.fp_verification_key = unicode(uuid.uuid4())
+        user.fp_token_expire = datetime.datetime.now() + \
+                               datetime.timedelta(days=10)
+        user.save()
+
+        email_debug_message(request)
+        send_fp_verification_email(user, request)
+
+    messages.add_message(request, messages.INFO, success_message)
+    return redirect(request, 'mediagoblin.auth.login')
+
+
+def verify_forgot_password(request):
+    """
+    Check the forgot-password verification and possibly let the user
+    change their password because of it.
+    """
+    # get form data variables, and specifically check for presence of token
+    formdata = _process_for_token(request)
+    if not formdata['has_userid_and_token']:
+        return render_404(request)
+
+    formdata_token = formdata['vars']['token']
+    formdata_userid = formdata['vars']['userid']
+    formdata_vars = formdata['vars']
+
+    # check if it's a valid user id
+    user = User.query.filter_by(id=formdata_userid).first()
+    if not user:
+        return render_404(request)
+
+    # check if we have a real user and correct token
+    if ((user and user.fp_verification_key and
+         user.fp_verification_key == unicode(formdata_token) and
+         datetime.datetime.now() < user.fp_token_expire
+         and user.email_verified and user.status == 'active')):
+
+        cp_form = auth_forms.ChangePassForm(formdata_vars)
+
+        if request.method == 'POST' and cp_form.validate():
+            user.pw_hash = auth_lib.bcrypt_gen_password_hash(
+                cp_form.password.data)
+            user.fp_verification_key = None
+            user.fp_token_expire = None
+            user.save()
+
+            messages.add_message(
+                request,
+                messages.INFO,
+                _("You can now log in using your new password."))
+            return redirect(request, 'mediagoblin.auth.login')
+        else:
+            return render_to_response(
+                request,
+                'mediagoblin/plugins/basic_auth/change_fp.html',
+                {'cp_form': cp_form})
+
+    # in case there is a valid id but no user with that id in the db
+    # or the token expired
+    else:
+        return render_404(request)
+
+
+def _process_for_token(request):
+    """
+    Checks for tokens in formdata without prior knowledge of request method
+
+    For now, returns whether the userid and token formdata variables exist, and
+    the formdata variables in a hash. Perhaps an object is warranted?
+    """
+    # retrieve the formdata variables
+    if request.method == 'GET':
+        formdata_vars = request.GET
+    else:
+        formdata_vars = request.form
+
+    formdata = {
+        'vars': formdata_vars,
+        'has_userid_and_token':
+            'userid' in formdata_vars and 'token' in formdata_vars}
+
+    return formdata
index 46aeddef743405e5c7c8de837f4c27ce2d04e1c3..98cd9a06ab3a3adf47105fddd3629f597dd6777b 100644 (file)
@@ -24,7 +24,7 @@
 {%- endblock %}
 
 {% block mediagoblin_content %}
-  <form action="{{ request.urlgen('mediagoblin.auth.forgot_password') }}"
+  <form action="{{ request.urlgen('mediagoblin.plugins.basic_auth.forgot_password') }}"
         method="POST" enctype="multipart/form-data">
     {{ csrf_token }}
     <div class="form_box">