[ckan-changes] commit/ckan: 3 new changesets

Bitbucket commits-noreply at bitbucket.org
Tue Jul 26 14:07:28 UTC 2011


3 new changesets in ckan:

http://bitbucket.org/okfn/ckan/changeset/5c1c0d7ae4ad/
changeset:   5c1c0d7ae4ad
branch:      feature-1229-db-out-of-controllers
user:        amercader
date:        2011-07-26 14:00:28
summary:     [logic,forms] Move user edit, including forms
affected #:  10 files (9.0 KB)

--- a/ckan/controllers/user.py	Mon Jul 25 14:45:56 2011 +0100
+++ b/ckan/controllers/user.py	Tue Jul 26 13:00:28 2011 +0100
@@ -10,10 +10,11 @@
 from ckan.lib.navl.dictization_functions import DataError, unflatten
 from ckan.logic import NotFound, NotAuthorized, ValidationError
 from ckan.logic import tuplize_dict, clean_dict, parse_params
-from ckan.logic.schema import user_form_schema
+from ckan.logic.schema import user_new_form_schema, user_edit_form_schema 
 
 import ckan.logic.action.get as get
 import ckan.logic.action.create as create
+import ckan.logic.action.update as update
 
 log = logging.getLogger(__name__)
 
@@ -23,12 +24,20 @@
 class UserController(BaseController):
 
     ## hooks for subclasses 
-    user_form = 'user/new_user_form.html'
+    new_user_form = 'user/new_user_form.html'
+    edit_user_form = 'user/edit_user_form.html'
 
-    def _form_to_db_schema(self):
-        return user_form_schema()
+    def _new_form_to_db_schema(self):
+        return user_new_form_schema()
 
-    def _db_to_form_schema(self):
+    def _db_to_new_form_schema(self):
+        '''This is an interface to manipulate data from the database
+        into a format suitable for the form (optional)'''
+
+    def _edit_form_to_db_schema(self):
+        return user_edit_form_schema()
+
+    def _db_to_edit_form_schema(self):
         '''This is an interface to manipulate data from the database
         into a format suitable for the form (optional)'''
 
@@ -71,7 +80,7 @@
                    'user': c.user or c.author}
 
         data_dict = {'id':id,
-                     'user':c.userobj}
+                     'user_obj':c.userobj}
         try:
             user_dict = get.user_show(context,data_dict)
         except NotFound:
@@ -98,7 +107,7 @@
     def new(self, data=None, errors=None, error_summary=None):
         context = {'model': model, 'session': model.Session,
                    'user': c.user or c.author,
-                   'schema': self._form_to_db_schema(),
+                   'schema': self._new_form_to_db_schema(),
                    'save': 'save' in request.params}
 
         auth_for_create = Authorizer().am_authorized(c, model.Action.USER_CREATE, model.System())
@@ -114,7 +123,7 @@
         vars = {'data': data, 'errors': errors, 'error_summary': error_summary}
 
         self._setup_template_variables(context)
-        c.form = render(self.user_form, extra_vars=vars)
+        c.form = render(self.new_user_form, extra_vars=vars)
         return render('user/new.html')
 
     def _save_new(self, context):
@@ -135,6 +144,77 @@
             error_summary = e.error_summary
             return self.new(data_dict, errors, error_summary)
 
+    def edit(self, id, data=None, errors=None, error_summary=None):
+        context = {'model': model, 'session': model.Session,
+                   'user': c.user or c.author,
+                   'preview': 'preview' in request.params,
+                   'save': 'save' in request.params,
+                   'schema': self._edit_form_to_db_schema(),
+                   }
+        data_dict = {'id': id}
+
+        if (context['save'] or context['preview']) and not data:
+            return self._save_edit(id, context)
+
+        try:
+            old_data = get.user_show(context, data_dict)
+
+            schema = self._db_to_edit_form_schema()
+            if schema:
+                old_data, errors = validate(old_data, schema)
+
+            c.display_name = old_data.get('display_name')
+            c.user_name = old_data.get('name')
+
+            data = data or old_data
+
+        except NotAuthorized:
+            abort(401, _('Unauthorized to edit user %s') % '')
+
+        user_obj = context.get('user_obj')
+        
+        if not (ckan.authz.Authorizer().is_sysadmin(unicode(c.user)) or c.user == user_obj.name):
+            abort(401, _('User %s not authorized to edit %s') % (str(c.user), id))
+        
+        errors = errors or {}
+        vars = {'data': data, 'errors': errors, 'error_summary': error_summary}
+
+        self._setup_template_variables(context)
+
+        c.form = render(self.edit_user_form, extra_vars=vars)
+
+        return render('user/edit.html')
+
+    def _save_edit(self, id, context):
+        try:
+            data_dict = clean_dict(unflatten(
+                tuplize_dict(parse_params(request.params))))
+            context['message'] = data_dict.get('log_message', '')
+            data_dict['id'] = id
+            user = update.user_update(context, data_dict)
+
+            if context['preview']:
+                about = request.params.getone('about')
+                c.preview = self._format_about(about)
+                c.user_about = about
+                c.full_name = request.params.get('fullname','')
+                c.email = request.params.getone('email')
+
+                return self.edit(id, data_dict)
+
+            h.redirect_to(controller='user', action='read', id=user['id'])
+        except NotAuthorized:
+            abort(401, _('Unauthorized to edit user %s') % id)
+        except NotFound, e:
+            abort(404, _('User not found'))
+        except DataError:
+            abort(400, _(u'Integrity Error'))
+        except ValidationError, e:
+            errors = e.error_dict
+            error_summary = e.error_summary
+            return self.edit(id, data_dict, errors, error_summary)
+
+
     def login(self):
         return render('user/login.html')
     
@@ -162,58 +242,6 @@
         response.delete_cookie("ckan_display_name")
         response.delete_cookie("ckan_apikey")
         return render('user/logout.html')
-
-    def edit(self, id=None):
-        if id is not None:
-            user = model.User.get(id)
-        else:
-            user = model.User.by_name(c.user)
-        if user is None:
-            abort(404)
-        currentuser = model.User.by_name(c.user)
-        if not (ckan.authz.Authorizer().is_sysadmin(unicode(c.user)) or user == currentuser):
-            abort(401)
-        c.userobj = user
-        if not 'save' in request.params and not 'preview' in request.params:
-            c.user_about = user.about
-            c.user_fullname = user.fullname
-            c.user_email = user.email
-        elif 'preview' in request.params:
-            about = request.params.getone('about')
-            c.preview = self._format_about(about)
-            c.user_about = about
-            c.user_fullname = request.params.getone('fullname')
-            c.user_email = request.params.getone('email')
-        elif 'save' in request.params:
-            try:
-                about = request.params.getone('about')
-                if 'http://' in about or 'https://' in about:
-                    msg = _('Edit not allowed as it looks like spam. Please avoid links in your description.')
-                    h.flash_error(msg)
-                    c.user_about = about
-                    c.user_fullname = request.params.getone('fullname')
-                    c.user_email = request.params.getone('email')
-                    return render('user/edit.html')
-                user.about = about
-                user.fullname = request.params.getone('fullname')
-                user.email = request.params.getone('email')
-                try:
-                    password = self._get_form_password()
-                    if password: 
-                        user.password = password
-                except ValueError, ve:
-                    h.flash_error(ve)
-                    return render('user/edit.html')
-            except Exception, inst:
-                model.Session.rollback()
-                raise
-            else:
-                model.Session.commit()
-                h.flash_notice(_("Your account has been updated."))
-            response.set_cookie("ckan_display_name", user.display_name)
-            h.redirect_to(controller='user', action='read', id=user.id)
-            
-        return render('user/edit.html')
     
     def request_reset(self):
         if request.method == 'POST':


--- a/ckan/lib/dictization/model_save.py	Mon Jul 25 14:45:56 2011 +0100
+++ b/ckan/lib/dictization/model_save.py	Tue Jul 26 13:00:28 2011 +0100
@@ -301,11 +301,11 @@
 
     model = context['model']
     session = context['session']
-    user = context.get('userobj')
+    user = context.get('user_obj')
     
     User = model.User
     if user:
-        user_dict['id'] = user.id 
+        user_dict['id'] = user.id
 
     user = table_dict_save(user_dict, User, context)
 


--- a/ckan/logic/action/get.py	Mon Jul 25 14:45:56 2011 +0100
+++ b/ckan/logic/action/get.py	Tue Jul 26 13:00:28 2011 +0100
@@ -300,14 +300,14 @@
     model = context['model']
 
     id = data_dict.get('id',None)
-    provided_user = data_dict.get('user',None)
+    provided_user = data_dict.get('user_obj',None)
     if id:
         user = model.User.get(id)
-        context['user'] = user
+        context['user_obj'] = user
         if user is None:
             raise NotFound
     elif provided_user:
-        context['user'] = user = provided_user
+        context['user_obj'] = user = provided_user
     else:
         return None
 


--- a/ckan/logic/action/update.py	Mon Jul 25 14:45:56 2011 +0100
+++ b/ckan/logic/action/update.py	Tue Jul 26 13:00:28 2011 +0100
@@ -11,13 +11,16 @@
                                                 package_to_api2,
                                                 group_dictize,
                                                 group_to_api1,
-                                                group_to_api2)
+                                                group_to_api2,
+                                                user_dictize)
 from ckan.lib.dictization.model_save import (group_api_to_dict,
                                              package_api_to_dict,
                                              group_dict_save,
-                                             package_dict_save)
+                                             package_dict_save,
+                                             user_dict_save)
 from ckan.logic.schema import (default_update_group_schema,
-                               default_update_package_schema)
+                               default_update_package_schema,
+                               default_update_user_schema)
 from ckan.lib.navl.dictization_functions import validate
 log = logging.getLogger(__name__)
 
@@ -276,6 +279,44 @@
 
     return group_dictize(group, context)
 
+def user_update(context, data_dict):
+    '''Updates the user's details'''
+
+    model = context['model']
+    user = context['user']
+    preview = context.get('preview', False)
+    schema = context.get('schema') or default_update_user_schema() 
+    id = data_dict['id']
+
+    user_obj = model.User.get(id)
+    context['user_obj'] = user_obj
+    if user_obj is None:
+        raise NotFound('User was not found.')
+
+    if not (ckan.authz.Authorizer().is_sysadmin(unicode(user)) or user == user_obj.name):
+        raise NotAuthorized( _('User %s not authorized to edit %s') % (str(user), id))
+
+    data, errors = validate(data_dict, schema, context)
+    if errors:
+        model.Session.rollback()
+        raise ValidationError(errors, group_error_summary(errors))
+
+    if not preview:
+        rev = model.repo.new_revision()
+        rev.author = user
+        if 'message' in context:
+            rev.message = context['message']
+        else:
+            rev.message = _(u'REST API: Update user %s') % data.get('name')
+
+    user = user_dict_save(data, context)
+    
+    if not preview:
+        model.repo.commit()        
+        return user_dictize(user, context)
+
+    return data
+
 ## Modifications for rest api
 
 def package_update_rest(context, data_dict):


--- a/ckan/logic/schema.py	Mon Jul 25 14:45:56 2011 +0100
+++ b/ckan/logic/schema.py	Tue Jul 26 13:00:28 2011 +0100
@@ -25,7 +25,8 @@
                                    user_password_validator,
                                    user_both_passwords_entered,
                                    user_passwords_match,
-                                   user_password_not_empty)
+                                   user_password_not_empty,
+                                   user_about_validator)
 from formencode.validators import OneOf
 import ckan.model
 
@@ -198,7 +199,7 @@
         'fullname': [ignore_missing, unicode],
         'password': [user_password_validator, user_password_not_empty, ignore_missing, unicode],
         'email': [ignore_missing, unicode],
-        'about': [ignore_missing, unicode],
+        'about': [ignore_missing, user_about_validator, unicode],
         'created': [ignore],
         'openid': [ignore],
         'apikey': [ignore],
@@ -206,7 +207,7 @@
     }
     return schema
 
-def user_form_schema():
+def user_new_form_schema():
     schema = default_user_schema()
     
     schema['password1'] = [unicode,user_both_passwords_entered,user_password_validator,user_passwords_match]
@@ -214,3 +215,19 @@
 
     return schema
 
+def user_edit_form_schema():
+    schema = default_user_schema()
+
+    schema['name'] = [ignore_missing]   
+    schema['password1'] = [unicode,user_both_passwords_entered,user_password_validator,user_passwords_match]
+    schema['password2'] = [unicode]
+
+    return schema
+
+def default_update_user_schema():
+    schema = default_user_schema()
+    
+    schema['name'] = [ignore_missing]
+
+    return schema
+


--- a/ckan/logic/validators.py	Mon Jul 25 14:45:56 2011 +0100
+++ b/ckan/logic/validators.py	Tue Jul 26 13:00:28 2011 +0100
@@ -217,3 +217,9 @@
         password = data.get(('password',),None)
         if not password:
             errors[key].append(_('Missing value'))
+
+def user_about_validator(value,context):
+    if 'http://' in value or 'https://' in value:
+        raise Invalid(_('Edit not allowed as it looks like spam. Please avoid links in your description.'))
+
+    return value


--- a/ckan/templates/user/edit.html	Mon Jul 25 14:45:56 2011 +0100
+++ b/ckan/templates/user/edit.html	Tue Jul 26 13:00:28 2011 +0100
@@ -11,51 +11,27 @@
 
   <div py:match="content"><h2>
-      Edit User: ${c.userobj.display_name} (${c.userobj.name})
+      Edit User: ${c.display_name} (${c.user_name})
       <a href="#preview" py:if="c.preview">(skip to preview)</a></h2>
 
-    <form id="user-edit" action="" method="post" class="simple-form" 
-      xmlns:py="http://genshi.edgewall.org/"
-      xmlns:xi="http://www.w3.org/2001/XInclude"
-      >
-      <fieldset>
-        <legend>Base details</legend>
-        <label for="fullname">Full name:</label>
-        <input name="fullname" value="${c.user_fullname}" /><br/>
-         
-        <label for="email">E-Mail:</label>
-        <input name="email" value="${c.user_email}" /><br/>
-      </fieldset>
-      <fieldset>
-        <legend>Change your password</legend>
-        <label for="password1">Password:</label>
-        <input type="password" name="password1" value="" />
-        <br/>
-        <label for="password2">Password (repeat):</label>
-        <input type="password" name="password2" value="" />
-        <br/>
-      </fieldset>
-      <label for="about">About user:</label>
-      <textarea id="about" rows="5" name="about" cols="60">${c.user_about}</textarea>
-      <p class="small" i18n:msg="">You can use <a href="http://daringfireball.net/projects/markdown/syntax">Markdown formatting</a> here.</p>
-
-      <div>
-        <input name="preview" type="submit" value="Preview" />
-        ${h.submit('save', _('Save'))}
-      </div>
-    </form><div id="preview" style="margin-left: 20px;" py:if="c.preview"><hr /><h2>Preview</h2>
-      <h4>Full name: ${c.user_fullname}</h4>
+      <h4>Full name: ${c.full_name}</h4>
+      <h4>Email: ${c.email}</h4><div style="border: 2px dashed red; padding: 5px;"> 
         ${c.preview}
       </div></div>
+
+    ${Markup(c.form)}
+
+
   </div>
 
+
   <xi:include href="layout.html" /></html>


--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ckan/templates/user/edit_user_form.html	Tue Jul 26 13:00:28 2011 +0100
@@ -0,0 +1,42 @@
+<form id="user-edit" action="" method="post"
+    py:attrs="{'class':'has-errors'} if errors else {}"
+    xmlns:i18n="http://genshi.edgewall.org/i18n"
+    xmlns:py="http://genshi.edgewall.org/"
+    xmlns:xi="http://www.w3.org/2001/XInclude">
+
+<div class="error-explanation" py:if="error_summary">
+<h2>Errors in form</h2>
+<p>The form contains invalid entries:</p>
+<ul>
+  <li py:for="key, error in error_summary.items()">${"%s: %s" % (key, error)}</li>
+</ul>
+</div>
+  <fieldset>
+    <legend>Base details</legend>
+    <dl>
+    <dt><label for="fullname">Full name:</label></dt>
+    <dd><input type="text" name="fullname" value="${data.get('fullname','')}" /></dd>
+     
+    <dt><label for="email">E-Mail:</label></dt>
+    <dd><input type="text" name="email" value="${data.get('email','')}" /></dd>
+    </dl>
+  </fieldset>
+  <fieldset>
+    <legend>Change your password</legend>
+    <dl>
+    <dt><label for="password1">Password:</label></dt>
+    <dd><input type="password" name="password1" value="" /></dd>
+    <dt><label for="password2">Password (repeat):</label></dt>
+    <dd><input type="password" name="password2" value="" /></dd>
+    </dl>
+  </fieldset>
+  <label for="about">About user:</label>
+  <textarea id="about" rows="5" name="about" cols="60">${data.get('about','')}</textarea>
+  <p class="small" i18n:msg="">You can use <a href="http://daringfireball.net/projects/markdown/syntax">Markdown formatting</a> here.</p>
+
+  <div>
+    <input name="preview" type="submit" value="Preview" />
+    ${h.submit('save', _('Save'))}
+  </div>
+</form>
+


--- a/ckan/tests/functional/api/test_action.py	Mon Jul 25 14:45:56 2011 +0100
+++ b/ckan/tests/functional/api/test_action.py	Tue Jul 26 13:00:28 2011 +0100
@@ -14,7 +14,8 @@
     STATUS_409_CONFLICT = 409
 
     sysadmin_user = None
-
+    
+    normal_user = None
 
     @classmethod
     def setup_class(self):
@@ -22,6 +23,8 @@
 
         self.sysadmin_user = model.User.get('testsysadmin')
 
+        self.normal_user = model.User.get('annafan')
+
     @classmethod
     def teardown_class(self):
         model.repo.rebuild_db()
@@ -163,6 +166,7 @@
         assert 'display_name' in result
         assert 'number_administered_packages' in result
         assert 'number_of_edits' in result
+        assert not 'password' in result
 
     def test_10_user_create_parameters_missing(self):
         user_dict = {}
@@ -200,3 +204,79 @@
             'help': 'Creates a new user',
             'success': False
         }
+
+    def test_12_user_update(self):
+        normal_user_dict = {'id': self.normal_user.id,
+                            'password': self.normal_user.password,
+                            'fullname': 'Updated normal user full name',
+                            'about':'Updated normal user about'}
+
+        sysadmin_user_dict = {'id': self.sysadmin_user.id,
+                            'password': self.sysadmin_user.password,
+                            'fullname': 'Updated sysadmin user full name',
+                            'about':'Updated sysadmin user about'} 
+
+        #Normal users can update themselves
+        postparams = '%s=1' % json.dumps(normal_user_dict)
+        res = self.app.post('/api/action/user_update', params=postparams,
+                            extra_environ={'Authorization': str(self.normal_user.apikey)})
+
+        res_obj = json.loads(res.body)
+        assert res_obj['help'] == 'Updates the user\'s details'
+        assert res_obj['success'] == True
+        result = res_obj['result']
+        assert result['id'] == self.normal_user.id
+        assert result['name'] == self.normal_user.name
+        assert result['fullname'] == normal_user_dict['fullname']
+        assert result['about'] == normal_user_dict['about']
+        assert 'apikey' in result
+        assert 'created' in result
+        assert 'display_name' in result
+        assert 'number_administered_packages' in result
+        assert 'number_of_edits' in result
+        assert not 'password' in result
+
+        #Sysadmin users can update themselves
+        postparams = '%s=1' % json.dumps(sysadmin_user_dict)
+        res = self.app.post('/api/action/user_update', params=postparams,
+                            extra_environ={'Authorization': str(self.sysadmin_user.apikey)})
+
+        res_obj = json.loads(res.body)
+        assert res_obj['help'] == 'Updates the user\'s details'
+        assert res_obj['success'] == True
+        result = res_obj['result']
+        assert result['id'] == self.sysadmin_user.id
+        assert result['name'] == self.sysadmin_user.name
+        assert result['fullname'] == sysadmin_user_dict['fullname']
+        assert result['about'] == sysadmin_user_dict['about']
+
+        #Sysadmin users can update all users
+        postparams = '%s=1' % json.dumps(normal_user_dict)
+        res = self.app.post('/api/action/user_update', params=postparams,
+                            extra_environ={'Authorization': str(self.sysadmin_user.apikey)})
+
+        res_obj = json.loads(res.body)
+        assert res_obj['help'] == 'Updates the user\'s details'
+        assert res_obj['success'] == True
+        result = res_obj['result']
+        assert result['id'] == self.normal_user.id
+        assert result['name'] == self.normal_user.name
+        assert result['fullname'] == normal_user_dict['fullname']
+        assert result['about'] == normal_user_dict['about']
+
+        #Normal users can not update other users
+        postparams = '%s=1' % json.dumps(sysadmin_user_dict)
+        res = self.app.post('/api/action/user_update', params=postparams,
+                            extra_environ={'Authorization': str(self.normal_user.apikey)},
+                            status=self.STATUS_403_ACCESS_DENIED)
+
+        res_obj = json.loads(res.body)
+        assert res_obj == {
+            'error': {
+                '__type': 'Authorization Error',
+                'message': 'Access denied'
+            },
+            'help': 'Updates the user\'s details',
+            'success': False
+        }
+


--- a/ckan/tests/functional/test_user.py	Mon Jul 25 14:45:56 2011 +0100
+++ b/ckan/tests/functional/test_user.py	Tue Jul 26 13:00:28 2011 +0100
@@ -1,6 +1,7 @@
 from routes import url_for
 from nose.tools import assert_equal
 
+from pprint import pprint
 from ckan.tests import search_related, CreateTestData
 from ckan.tests.html_check import HtmlCheckMethods
 import ckan.model as model
@@ -185,7 +186,6 @@
         res = self.app.get(offset, status=200)
         main_res = self.main_div(res)
         assert 'Register' in main_res, main_res
-        from pprint import pprint
         fv = res.forms['user-edit']
         fv['name'] = username
         fv['fullname'] = fullname
@@ -389,8 +389,6 @@
         # preview
         main_res = self.main_div(res)
         assert 'Edit User: testedit' in main_res, main_res
-        before_preview = main_res[:main_res.find('Preview')]
-        assert new_about in before_preview, before_preview
         in_preview = main_res[main_res.find('Preview'):]
         assert new_about in in_preview, in_preview
 


http://bitbucket.org/okfn/ckan/changeset/3983f71ac7cb/
changeset:   3983f71ac7cb
branch:      feature-1229-db-out-of-controllers
user:        amercader
date:        2011-07-26 15:36:05
summary:     [logic] Move user request_reset and perform_reset
affected #:  2 files (1.1 KB)

--- a/ckan/controllers/user.py	Tue Jul 26 13:00:28 2011 +0100
+++ b/ckan/controllers/user.py	Tue Jul 26 14:36:05 2011 +0100
@@ -246,32 +246,64 @@
     def request_reset(self):
         if request.method == 'POST':
             id = request.params.get('user')
-            user = model.User.get(id)
-            if user is None:
+
+            context = {'model': model,
+                       'user': c.user}
+
+            data_dict = {'id':id}
+
+            try:
+                user_dict = get.user_show(context,data_dict)
+                user_obj = context['user_obj']
+
+                if user_dict is None:
+                    h.flash_error(_('No such user: %s') % id)
+                try:
+                    mailer.send_reset_link(user_obj)
+                    h.flash_success(_('Please check your inbox for a reset code.'))
+                    redirect('/')
+                except mailer.MailerException, e:
+                    h.flash_error(_('Could not send reset link: %s') % unicode(e))
+
+            except NotFound:
                 h.flash_error(_('No such user: %s') % id)
-            try:
-                mailer.send_reset_link(user)
-                h.flash_success(_('Please check your inbox for a reset code.'))
-                redirect('/')
-            except mailer.MailerException, e:
-                h.flash_error(_('Could not send reset link: %s') % unicode(e))
         return render('user/request_reset.html')
 
     def perform_reset(self, id):
-        user = model.User.get(id)
-        if user is None:
-            abort(404)
+        context = {'model': model, 'session': model.Session,
+                   'user': c.user}
+
+        data_dict = {'id':id}
+
+        try:
+            user_dict = get.user_show(context,data_dict)
+            user_obj = context['user_obj']
+        except NotFound, e:
+            abort(404, _('User not found'))
+
         c.reset_key = request.params.get('key')
-        if not mailer.verify_reset_link(user, c.reset_key):
+        if not mailer.verify_reset_link(user_obj, c.reset_key):
             h.flash_error(_('Invalid reset key. Please try again.'))
             abort(403)
+
         if request.method == 'POST':
             try:
-                user.password = self._get_form_password()
-                model.Session.add(user)
-                model.Session.commit()
+                context['reset_password'] = True 
+                new_password = self._get_form_password()
+                user_dict['password'] = new_password
+                user_dict['reset_key'] = c.reset_key
+                user = update.user_update(context, user_dict)
+
                 h.flash_success(_("Your password has been reset."))
                 redirect('/')
+            except NotAuthorized:
+                h.flash_error(_('Unauthorized to edit user %s') % id)
+            except NotFound, e:
+                h.flash_error(_('User not found'))
+            except DataError:
+                h.flash_error(_(u'Integrity Error'))
+            except ValidationError, e:
+                h.flash_error(u'%r'% e.error_dict)
             except ValueError, ve:
                 h.flash_error(unicode(ve))
         return render('user/perform_reset.html')


--- a/ckan/logic/action/update.py	Tue Jul 26 13:00:28 2011 +0100
+++ b/ckan/logic/action/update.py	Tue Jul 26 14:36:05 2011 +0100
@@ -293,7 +293,8 @@
     if user_obj is None:
         raise NotFound('User was not found.')
 
-    if not (ckan.authz.Authorizer().is_sysadmin(unicode(user)) or user == user_obj.name):
+    if not (ckan.authz.Authorizer().is_sysadmin(unicode(user)) or user == user_obj.name) and \
+       not ('reset_key' in data_dict and data_dict['reset_key'] == user_obj['reset_key']):
         raise NotAuthorized( _('User %s not authorized to edit %s') % (str(user), id))
 
     data, errors = validate(data_dict, schema, context)


http://bitbucket.org/okfn/ckan/changeset/bc14ffe11d16/
changeset:   bc14ffe11d16
branch:      feature-1229-db-out-of-controllers
user:        amercader
date:        2011-07-26 16:03:17
summary:     [logic] Make password not mandatory when editing users
affected #:  3 files (264 bytes)

--- a/ckan/logic/schema.py	Tue Jul 26 14:36:05 2011 +0100
+++ b/ckan/logic/schema.py	Tue Jul 26 15:03:17 2011 +0100
@@ -218,9 +218,10 @@
 def user_edit_form_schema():
     schema = default_user_schema()
 
-    schema['name'] = [ignore_missing]   
-    schema['password1'] = [unicode,user_both_passwords_entered,user_password_validator,user_passwords_match]
-    schema['password2'] = [unicode]
+    schema['name'] = [ignore_missing]
+    schema['password'] = [ignore_missing]
+    schema['password1'] = [ignore_missing,unicode,user_password_validator,user_passwords_match]
+    schema['password2'] = [ignore_missing,unicode]
 
     return schema
 
@@ -228,6 +229,6 @@
     schema = default_user_schema()
     
     schema['name'] = [ignore_missing]
-
+    schema['password'] = [user_password_validator,ignore_missing, unicode]
     return schema
 


--- a/ckan/logic/validators.py	Tue Jul 26 14:36:05 2011 +0100
+++ b/ckan/logic/validators.py	Tue Jul 26 15:03:17 2011 +0100
@@ -194,8 +194,8 @@
 
 def user_password_validator(key, data, errors, context):
     value = data[key]
-       
-    if not isinstance(value, Missing) and not len(value) >= 4:
+
+    if not value == '' and not isinstance(value, Missing) and not len(value) >= 4:
         errors[('password',)].append(_('Your password must be 4 characters or longer'))
 
 def user_passwords_match(key, data, errors, context):


--- a/ckan/tests/functional/api/test_action.py	Tue Jul 26 14:36:05 2011 +0100
+++ b/ckan/tests/functional/api/test_action.py	Tue Jul 26 15:03:17 2011 +0100
@@ -207,12 +207,10 @@
 
     def test_12_user_update(self):
         normal_user_dict = {'id': self.normal_user.id,
-                            'password': self.normal_user.password,
                             'fullname': 'Updated normal user full name',
                             'about':'Updated normal user about'}
 
         sysadmin_user_dict = {'id': self.sysadmin_user.id,
-                            'password': self.sysadmin_user.password,
                             'fullname': 'Updated sysadmin user full name',
                             'about':'Updated sysadmin user about'}

Repository URL: https://bitbucket.org/okfn/ckan/

--

This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.




More information about the ckan-changes mailing list