Alessandro Molina avatar Alessandro Molina committed f4f3973

Fix bypassing missing user in profile page and add change password link

Comments (0)

Files changed (7)

 
 install_requires=[
     "TurboGears2 >= 2.1.4",
-    "tgext.pluggable"
+    "tgext.pluggable",
+    "tgext.datahelpers"
 ]
 
 here = os.path.abspath(os.path.dirname(__file__))

userprofile/controllers/root.py

 from tg import TGController
 from tg import expose, flash, require, url, lurl, request, redirect, validate, config
 from tg.i18n import ugettext as _, lazy_ugettext as l_
-from tg.exceptions import HTTPNotFound
 
 try:
     from repoze.what import predicates
 except ImportError:
     from tg import predicates
 
-from userprofile.model import DBSession
-from userprofile.lib import create_user_form, get_user_data, get_profile_css, update_user_data
+from userprofile.lib import create_user_form, get_user_data, get_profile_css, \
+                            update_user_data, create_change_password_form
 from tgext.pluggable import app_model, plug_url, primary_key
+from tgext.datahelpers.validators import SQLAEntityConverter
+from tgext.datahelpers.utils import fail_with
+
+edit_password_form = create_change_password_form()
 
 class RootController(TGController):
     @expose('userprofile.templates.index')
-    def default(self, uid):
-        user = DBSession.query(app_model.User).filter(primary_key(app_model.User)==uid).first()
-        if not user:
-            raise HTTPNotFound()
-
+    @validate({'user':SQLAEntityConverter(app_model.User)},
+              error_handler=fail_with(404))
+    def _default(self, user):
         user_data, user_avatar = get_user_data(user)
         user_displayname = user_data.pop('display_name', (None, 'Unknown'))
         user_partial = config['_pluggable_userprofile_config'].get('user_partial')
         if not profile_save:
             profile_save = update_user_data
         profile_save(user, kw)
+        flash(_('Profile successfully updated'))
+        return redirect(plug_url('userprofile', '/%s' % getattr(user, primary_key(app_model.User).name)))
+
+    @expose('userprofile.templates.chpasswd')
+    @require(predicates.not_anonymous())
+    def chpasswd(self, **kw):
+        user = request.identity['user']
+        return dict(user=user, profile_css=get_profile_css(config),
+                    form=edit_password_form)
+
+    @expose()
+    @validate(edit_password_form, error_handler=chpasswd)
+    def save_password(self, password, verify_password):
+        user = request.identity['user']
+        user.password = password
+        flash(_('Password successfully changed'))
         return redirect(plug_url('userprofile', '/%s' % getattr(user, primary_key(app_model.User).name)))

userprofile/lib/__init__.py

 from tg import url
 from tgext.pluggable import app_model, plug_url
 
-from tw.forms import ListForm, TextField
+from tw.forms import ListForm, TextField, PasswordField
 from tw.forms.validators import UnicodeString
+from sprox.formbase import FilteringSchema
+from formencode.validators import FieldsMatch
 
 def get_profile_css(config):
     return url(config['_pluggable_userprofile_config'].get('custom_css',
                                 action=plug_url('userprofile', '/save'))
     return profile_form
 
+class ChangePasswordForm(ListForm):
+    password = PasswordField(label_text='Password')
+    password_confirm = PasswordField(label_text='Confirm Password')
+
+_password_match = FieldsMatch('password', 'verify_password',
+                              messages={'invalidNoMatch': 'Passwords do not match'})
+if hasattr(TextField, 'req'):
+    change_password_form_validator = _password_match
+else:
+    change_password_form_validator =  FilteringSchema(chained_validators=[_password_match])
+
+def create_change_password_form():
+    return ListForm(fields=[PasswordField('password', label_text='Password',
+                                          validator=UnicodeString(not_empty=True)),
+                            PasswordField('verify_password', label_text='Confirm Password',
+                                          validator=UnicodeString(not_empty=True))],
+                    action=plug_url('userprofile', '/save_password', lazy=True),
+                    validator=change_password_form_validator,
+                    submit_text='Save')

userprofile/public/css/style.css

     clear: both;
 }
 
-#userprofile_edit_form input[type="text"] {
+#userprofile_edit_form input[type="text"],
+#userprofile_edit_form input[type="password"] {
     padding: 4px;
     border: 1px solid #CCC;
     min-width: 200px;
 
 #userprofile_edit_form > form > ul > li {
     margin-top: 5px;
+}
+
+#userprofile_edit_form h3 {
+    margin-bottom: 20px;
 }

userprofile/templates/chpasswd.html

+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+        "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"
+      xmlns:py="http://genshi.edgewall.org/"
+      xmlns:xi="http://www.w3.org/2001/XInclude">
+
+<xi:include href="master.html" />
+
+<head>
+    <title>Change Password</title>
+    <link rel="stylesheet" type="text/css" media="screen" href="${profile_css}" />
+</head>
+
+<body>
+    <h3>Change Password</h3>
+    <div id="userprofile_container">
+        <div id="userprofile_edit_form">
+            <h3>Edit Profile</h3>
+            ${form.display()}
+        </div>
+    </div>
+</body>
+</html>

userprofile/templates/edit.html

             <img id="userprofile_avatar" src="${user_avatar}" />
         </div>
         <div id="userprofile_edit_form">
+            <h3>Edit Profile</h3>
             ${form.display(user)}
         </div>
     </div>

userprofile/templates/index.html

             <div id="userprofile_title">
                 ${user_displayname[1]}
                 <div id="userprofile_edit" py:if="is_my_own_profile">
-                    <a href="${h.plug_url('userprofile', '/edit')}">edit</a>
+                    <a href="${h.plug_url('userprofile', '/edit')}">edit</a> -
+                    <a href="${h.plug_url('userprofile', '/chpasswd')}">change password</a>
                 </div>
             </div>
             <div id="userprofile_other_attr">
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.