[Freeipa-devel] [PATCH] update user webgui

Kevin McCarthy kmccarth at redhat.com
Thu Aug 16 22:13:45 UTC 2007


This patch enables updating for the web gui.  Turbogears seems to be
sending unicode strings, which is choking the ldap code.  For now, I've
converted the to regular python strings, but this will affect i18n in
the future.

The server is returning lowercase ldap attribute names now, so this
fixes the web gui as well as ipaclient.py to refer to lowercase
attributes.

Lastly, there's a fix for user.getValue().  After debugging we've
determined that the xmlrpc layer isn't goofing up hash values (thank
goodness), and that getValue() was working by coincidence.

-Kevin

-------------- next part --------------
# HG changeset patch
# User Kevin McCarthy <kmccarth at redhat.com>
# Date 1187301936 25200
# Node ID 8d8234203e0e9cbfbc8d104e761d631da11da24a
# Parent  45eb7e8045f8d79dde6136e1a973471e57c82f21
Add update user to gui.
Fix fields to be lowercase in web gui (server now returns them lowercase).
Fix ipaclient.py to refer to lowercase fields when adding a user.
Fix user.getValue() to check isinstance(value,list) instead of value[0].

diff -r 45eb7e8045f8 -r 8d8234203e0e ipa-python/ipaclient.py
--- a/ipa-python/ipaclient.py	Wed Aug 15 10:48:34 2007 -0700
+++ b/ipa-python/ipaclient.py	Thu Aug 16 15:05:36 2007 -0700
@@ -54,18 +54,18 @@ class IPAClient:
 
         # FIXME: This should be dynamic and can include just about anything
         # Let us add in some missing attributes
-        if user.get('homeDirectory') is None:
-                user['homeDirectory'] ='/home/%s' % user['uid']
+        if user.get('homedirectory') is None:
+                user['homedirectory'] ='/home/%s' % user['uid']
         if user.get('gecos') is None:
                 user['gecos'] = user['uid']
 
         # FIXME: This can be removed once the DS plugin is installed
-        user['uidNumber'] ='501'
+        user['uidnumber'] ='501'
 
         # FIXME: What is the default group for users?
-        user['gidNumber'] ='501'
-        user['krbPrincipalName'] = "%s@%s" % (user['uid'], realm)
-        user['cn'] = "%s %s" % (user['givenName'], user['sn'])
+        user['gidnumber'] ='501'
+        user['krbprincipalname'] = "%s@%s" % (user['uid'], realm)
+        user['cn'] = "%s %s" % (user['givenname'], user['sn'])
         if user.get('gn'):
                 del user['gn']
 
diff -r 45eb7e8045f8 -r 8d8234203e0e ipa-python/user.py
--- a/ipa-python/user.py	Wed Aug 15 10:48:34 2007 -0700
+++ b/ipa-python/user.py	Thu Aug 16 15:05:36 2007 -0700
@@ -58,9 +58,7 @@ class User:
     def getValue(self,name):
         """Get the first value for the attribute named name"""
         value =  self.data.get(name,[None])
-        if (len(value) < 1):
-            return value
-        if isinstance(value[0],list) or isinstance(value[0],tuple):
+        if isinstance(value,list) or isinstance(value,tuple):
             return value[0]
         else:
             return value
diff -r 45eb7e8045f8 -r 8d8234203e0e ipa-server/ipa-gui/ipagui/controllers.py
--- a/ipa-server/ipa-gui/ipagui/controllers.py	Wed Aug 15 10:48:34 2007 -0700
+++ b/ipa-server/ipa-gui/ipagui/controllers.py	Thu Aug 16 15:05:36 2007 -0700
@@ -1,4 +1,7 @@ import random
 import random
+from pickle import dumps, loads
+from base64 import b64encode, b64decode
+
 import cherrypy
 import turbogears
 from turbogears import controllers, expose, flash
@@ -8,6 +11,7 @@ from turbogears import error_handler
 # from model import *
 # import logging
 # log = logging.getLogger("ipagui.controllers")
+
 import ipa.config
 import ipa.ipaclient
 import ipa.user
@@ -28,20 +32,26 @@ def restrict_post():
         turbogears.flash("This method only accepts posts")
         raise turbogears.redirect("/")
 
-def user_to_hash(user):
-    return {
-        'uid'       : user.getValue('uid'),
-        'givenName' : user.getValue('givenName'),
-        'sn'        : user.getValue('sn'),
-        'mail'      : user.getValue('mail'),
-        'telephoneNumber': user.getValue('telephoneNumber'),
-        'uidNumber'      : user.getValue('uidNumber'),
-        'gidNumber'      : user.getValue('gidNumber'),
-        'givenName_orig' : user.getValue('givenName'),
-        'sn_orig'        : user.getValue('sn'),
-        'mail_orig'      : user.getValue('mail'),
-        'telephoneNumber_orig': user.getValue('telephoneNumber'),
-            }
+def to_ldap_hash(orig):
+    """LDAP hashes expect all values to be a list.  This method converts single
+       entries to a list."""
+    new={}
+    for (k,v) in orig.iteritems():
+        if v == None:
+            continue
+        if not isinstance(v, list) and k != 'dn':
+            v = [v]
+        new[k] = v
+
+    return new
+
+def set_ldap_value(hash, key, value):
+    """Converts unicode strings to normal strings
+       (because LDAP is choking on unicode strings"""
+    if value != None:
+        value = str(value)
+    hash[key] = value
+
 
 class Root(controllers.RootController):
 
@@ -75,20 +85,14 @@ class Root(controllers.RootController):
             return dict(form=user_new_form, tg_template='ipagui.templates.usernew')
 
         try:
-            newuser = ipa.user.User(None)
-            newuser.setValue('uid', kw['uid'])
-            newuser.setValue('givenName', kw['givenName'])
-            newuser.setValue('sn', kw['sn'])
-            newuser.setValue('mail', kw['mail'])
-            newuser.setValue('telephoneNumber', kw['telephoneNumber'])
-            newuser2 = {
-                'uid'       : kw['uid'],
-                'givenName' : kw['givenName'],
-                'sn'        : kw['sn'],
-                'mail'      : kw['mail'],
-                'telephoneNumber': kw['telephoneNumber']
-                    }
-            rv = client.add_user(newuser2)
+            new_user = {}
+            set_ldap_value(new_user, 'uid', kw.get('uid'))
+            set_ldap_value(new_user, 'givenname', kw.get('givenname'))
+            set_ldap_value(new_user, 'sn', kw.get('sn'))
+            set_ldap_value(new_user, 'mail', kw.get('mail'))
+            set_ldap_value(new_user, 'telephonenumber', kw.get('telephonenumber'))
+
+            rv = client.add_user(new_user)
             turbogears.flash("%s added!" % kw['uid'])
             raise turbogears.redirect('/usershow', uid=kw['uid'])
         except xmlrpclib.Fault, f:
@@ -103,7 +107,11 @@ class Root(controllers.RootController):
             turbogears.flash("There was a problem with the form!")
 
         user = client.get_user(uid)
-        return dict(form=user_edit_form, user=user_to_hash(user))
+        user_hash = user.toDict()
+        # store a copy of the original user for the update later
+        user_data = b64encode(dumps(user_hash))
+        user_hash['user_orig'] = user_data
+        return dict(form=user_edit_form, user=user_hash)
 
     @expose()
     def userupdate(self, **kw):
@@ -119,10 +127,22 @@ class Root(controllers.RootController):
                         tg_template='ipagui.templates.useredit')
 
         try:
+            orig_user = loads(b64decode(kw.get('user_orig')))
+
+            new_user = dict(orig_user)
+            set_ldap_value(new_user, 'givenname', kw.get('givenname'))
+            set_ldap_value(new_user, 'sn', kw.get('sn'))
+            set_ldap_value(new_user, 'mail', kw.get('mail'))
+            set_ldap_value(new_user, 'telephonenumber', kw.get('telephonenumber'))
+
+            orig_user = to_ldap_hash(orig_user)
+            new_user = to_ldap_hash(new_user)
+
+            rv = client.update_user(orig_user, new_user)
             turbogears.flash("%s updated!" % kw['uid'])
             raise turbogears.redirect('/usershow', uid=kw['uid'])
         except xmlrpclib.Fault, f:
-            turbogears.flash("User add failed: " + str(f.faultString))
+            turbogears.flash("User update failed: " + str(f.faultString))
             return dict(form=user_edit_form, user=kw,
                         tg_template='ipagui.templates.useredit')
 
@@ -140,7 +160,7 @@ class Root(controllers.RootController):
         """Retrieve a single user for display"""
         try:
             user = client.get_user(uid)
-            return dict(user=user_to_hash(user), fields=forms.user.UserFields())
+            return dict(user=user.toDict(), fields=forms.user.UserFields())
         except xmlrpclib.Fault, f:
             turbogears.flash("User show failed: " + str(f.faultString))
             raise turbogears.redirect("/")
diff -r 45eb7e8045f8 -r 8d8234203e0e ipa-server/ipa-gui/ipagui/forms/user.py
--- a/ipa-server/ipa-gui/ipagui/forms/user.py	Wed Aug 15 10:48:34 2007 -0700
+++ b/ipa-server/ipa-gui/ipagui/forms/user.py	Thu Aug 16 15:05:36 2007 -0700
@@ -3,36 +3,34 @@ from turbogears import validators, widge
 
 class UserFields():
     uid = widgets.TextField(name="uid", label="Login:")
-    userPassword = widgets.TextField(name="userPassword", label="Password:")
-    uidNumber = widgets.TextField(name="uidNumber", label="UID:")
-    gidNumber = widgets.TextField(name="gidNumber", label="GID:")
-    givenName = widgets.TextField(name="givenName", label="First name:")
+    userpassword = widgets.TextField(name="userpassword", label="Password:")
+    uidnumber = widgets.TextField(name="uidnumber", label="UID:")
+    gidnumber = widgets.TextField(name="gidnumber", label="GID:")
+    givenname = widgets.TextField(name="givenname", label="First name:")
     sn = widgets.TextField(name="sn", label="Last name:")
     mail = widgets.TextField(name="mail", label="E-mail address:")
-    telephoneNumber = widgets.TextField(name="telephoneNumber", label="Phone:")
+    telephonenumber = widgets.TextField(name="telephonenumber", label="Phone:")
 
     uid.validator = validators.PlainText(not_empty=True)
-    userPassword.validator = validators.String(not_empty=True)
-    givenName.validator = validators.String(not_empty=True)
+    userpassword.validator = validators.String(not_empty=True)
+    givenname.validator = validators.String(not_empty=True)
     sn.validator = validators.String(not_empty=True)
     mail.validator = validators.Email(not_empty=True)
     #  validators.PhoneNumber may be a bit too picky, requiring an area code
-    telephoneNumber.validator = validators.PlainText(not_empty=True)
+    telephonenumber.validator = validators.PlainText(not_empty=True)
 
     uid_hidden = widgets.HiddenField(name="uid")
-    uidNumber_hidden = widgets.HiddenField(name="uidNumber")
-    gidNumber_hidden = widgets.HiddenField(name="gidNumber")
-    givenName_orig = widgets.HiddenField(name="givenName_orig")
-    sn_orig = widgets.HiddenField(name="sn_orig")
-    mail_orig = widgets.HiddenField(name="mail_orig")
-    telephoneNumber_orig = widgets.HiddenField(name="telephoneNumber_orig")
+    uidnumber_hidden = widgets.HiddenField(name="uidnumber")
+    gidnumber_hidden = widgets.HiddenField(name="gidnumber")
+
+    user_orig = widgets.HiddenField(name="user_orig")
 
 
 class UserNewForm(widgets.Form):
     params = ['user']
 
-    fields = [UserFields.uid, UserFields.givenName,
-              UserFields.uidNumber, UserFields.gidNumber,
+    fields = [UserFields.uid, UserFields.givenname,
+              UserFields.uidnumber, UserFields.gidnumber,
               UserFields.sn, UserFields.mail]
 
     def __init__(self, *args, **kw):
@@ -51,10 +49,10 @@ class UserEditForm(widgets.Form):
 class UserEditForm(widgets.Form):
     params = ['user']
 
-    fields = [UserFields.givenName, UserFields.sn, UserFields.mail,
-              UserFields.givenName_orig, UserFields.sn_orig, UserFields.mail_orig,
-              UserFields.uid_hidden,
-              UserFields.uidNumber_hidden, UserFields.gidNumber_hidden]
+    fields = [UserFields.givenname, UserFields.sn, UserFields.mail,
+              UserFields.uid_hidden, UserFields.user_orig,
+              UserFields.uidnumber_hidden, UserFields.gidnumber_hidden,
+              ]
 
     def __init__(self, *args, **kw):
         super(UserEditForm,self).__init__(*args, **kw)
diff -r 45eb7e8045f8 -r 8d8234203e0e ipa-server/ipa-gui/ipagui/templates/usereditform.kid
--- a/ipa-server/ipa-gui/ipagui/templates/usereditform.kid	Wed Aug 15 10:48:34 2007 -0700
+++ b/ipa-server/ipa-gui/ipagui/templates/usereditform.kid	Thu Aug 16 15:05:36 2007 -0700
@@ -21,13 +21,13 @@
 
       <tr>
         <th valign="top">
-          <label class="fieldlabel" for="${user.userPassword.field_id}"
-            py:content="user.userPassword.label" />
+          <label class="fieldlabel" for="${user.userpassword.field_id}"
+            py:content="user.userpassword.label" />
         </th>
         <td valign="top">
-          <span py:replace="user.userPassword.display(value_for(user.userPassword))" />
-          <span py:if="tg.errors.get('userPassword')" class="fielderror"
-              py:content="tg.errors.get('userPassword')" />
+          <span py:replace="user.userpassword.display(value_for(user.userpassword))" />
+          <span py:if="tg.errors.get('userpassword')" class="fielderror"
+              py:content="tg.errors.get('userpassword')" />
           <span id="password_text">********</span>
 
           <input id="genpassword_button" type="button" value="Generate Password"
@@ -36,7 +36,7 @@
                 {
                   method: 'get',
                   onSuccess: function(transport) {
-                    document.getElementById('form_userPassword').value =
+                    document.getElementById('form_userpassword').value =
                         transport.responseText;
                   }
                 });" />
@@ -44,10 +44,10 @@
           <input type="checkbox"
               onclick="togglePassword(this);"><span class="small">edit</span></input>
           <script type="text/javascript">
-            document.getElementById('form_userPassword').style.display='none';
+            document.getElementById('form_userpassword').style.display='none';
 
             function togglePassword(checkbox) {
-              passwordField = document.getElementById('form_userPassword');
+              passwordField = document.getElementById('form_userpassword');
               passwordText = document.getElementById('password_text');
               passwordButton = document.getElementById('genpassword_button');
               if (checkbox.checked) {
@@ -66,21 +66,21 @@
 
       <tr>
         <th>
-          <label class="fieldlabel" for="${user.uidNumber.field_id}"
-            py:content="user.uidNumber.label" />
+          <label class="fieldlabel" for="${user.uidnumber.field_id}"
+            py:content="user.uidnumber.label" />
         </th>
         <td>
-          ${value_for(user.uidNumber)}
+          ${value_for(user.uidnumber)}
         </td>
       </tr>
 
       <tr>
         <th>
-          <label class="fieldlabel" for="${user.gidNumber.field_id}"
-            py:content="user.gidNumber.label" />
+          <label class="fieldlabel" for="${user.gidnumber.field_id}"
+            py:content="user.gidnumber.label" />
         </th>
         <td>
-          ${value_for(user.gidNumber)}
+          ${value_for(user.gidnumber)}
         </td>
       </tr>
     </table>
@@ -89,13 +89,13 @@
     <table class="formtable" cellpadding="2" cellspacing="0" border="0">
       <tr>
         <th>
-          <label class="fieldlabel" for="${user.givenName.field_id}"
-            py:content="user.givenName.label" />
+          <label class="fieldlabel" for="${user.givenname.field_id}"
+            py:content="user.givenname.label" />
         </th>
         <td>
-          <span py:replace="user.givenName.display(value_for(user.givenName))" />
-          <span py:if="tg.errors.get('givenName')" class="fielderror"
-              py:content="tg.errors.get('givenName')" />
+          <span py:replace="user.givenname.display(value_for(user.givenname))" />
+          <span py:if="tg.errors.get('givenname')" class="fielderror"
+              py:content="tg.errors.get('givenname')" />
 
         </td>
       </tr>
@@ -128,13 +128,13 @@
       </tr>
       <tr>
         <th>
-          <label class="fieldlabel" for="${user.telephoneNumber.field_id}"
-            py:content="user.telephoneNumber.label" />
+          <label class="fieldlabel" for="${user.telephonenumber.field_id}"
+            py:content="user.telephonenumber.label" />
         </th>
         <td>
-          <span py:replace="user.telephoneNumber.display(value_for(user.telephoneNumber))" />
-          <span py:if="tg.errors.get('telephoneNumber')" class="fielderror"
-              py:content="tg.errors.get('telephoneNumber')" />
+          <span py:replace="user.telephonenumber.display(value_for(user.telephonenumber))" />
+          <span py:if="tg.errors.get('telephonenumber')" class="fielderror"
+              py:content="tg.errors.get('telephonenumber')" />
         </td>
       </tr>
     </table>
diff -r 45eb7e8045f8 -r 8d8234203e0e ipa-server/ipa-gui/ipagui/templates/usernewform.kid
--- a/ipa-server/ipa-gui/ipagui/templates/usernewform.kid	Wed Aug 15 10:48:34 2007 -0700
+++ b/ipa-server/ipa-gui/ipagui/templates/usernewform.kid	Thu Aug 16 15:05:36 2007 -0700
@@ -18,20 +18,20 @@
 
       <tr>
         <th>
-          <label class="fieldlabel" for="${user.userPassword.field_id}"
-            py:content="user.userPassword.label" />
+          <label class="fieldlabel" for="${user.userpassword.field_id}"
+            py:content="user.userpassword.label" />
         </th>
         <td>
-          <span py:replace="user.userPassword.display(value_for(user.userPassword))" />
-          <span py:if="tg.errors.get('userPassword')" class="fielderror"
-              py:content="tg.errors.get('userPassword')" />
+          <span py:replace="user.userpassword.display(value_for(user.userpassword))" />
+          <span py:if="tg.errors.get('userpassword')" class="fielderror"
+              py:content="tg.errors.get('userpassword')" />
 
           <input type="button" value="Generate Password"
               onclick="new Ajax.Request('${tg.url('/generate_password')}',
                 {
                   method: 'get',
                   onSuccess: function(transport) {
-                    document.getElementById('form_userPassword').value =
+                    document.getElementById('form_userpassword').value =
                         transport.responseText;
                   }
                 });" />
@@ -40,25 +40,25 @@
 
       <tr>
         <th>
-          <label class="fieldlabel" for="${user.uidNumber.field_id}"
-            py:content="user.uidNumber.label" />
+          <label class="fieldlabel" for="${user.uidnumber.field_id}"
+            py:content="user.uidnumber.label" />
         </th>
         <td>
-          <span py:replace="user.uidNumber.display(value_for(user.uidNumber))" />
-          <span py:if="tg.errors.get('uidNumber')" class="fielderror"
-              py:content="tg.errors.get('uidNumber')" />
+          <span py:replace="user.uidnumber.display(value_for(user.uidnumber))" />
+          <span py:if="tg.errors.get('uidnumber')" class="fielderror"
+              py:content="tg.errors.get('uidnumber')" />
         </td>
       </tr>
 
       <tr>
         <th>
-          <label class="fieldlabel" for="${user.gidNumber.field_id}"
-            py:content="user.gidNumber.label" />
+          <label class="fieldlabel" for="${user.gidnumber.field_id}"
+            py:content="user.gidnumber.label" />
         </th>
         <td>
-          <span py:replace="user.gidNumber.display(value_for(user.gidNumber))" />
-          <span py:if="tg.errors.get('gidNumber')" class="fielderror"
-              py:content="tg.errors.get('gidNumber')" />
+          <span py:replace="user.gidnumber.display(value_for(user.gidnumber))" />
+          <span py:if="tg.errors.get('gidnumber')" class="fielderror"
+              py:content="tg.errors.get('gidnumber')" />
         </td>
       </tr>
     </table>
@@ -67,13 +67,13 @@
     <table class="formtable" cellpadding="2" cellspacing="0" border="0">
       <tr>
         <th>
-          <label class="fieldlabel" for="${user.givenName.field_id}"
-            py:content="user.givenName.label" />
+          <label class="fieldlabel" for="${user.givenname.field_id}"
+            py:content="user.givenname.label" />
         </th>
         <td>
-          <span py:replace="user.givenName.display(value_for(user.givenName))" />
-          <span py:if="tg.errors.get('givenName')" class="fielderror"
-              py:content="tg.errors.get('givenName')" />
+          <span py:replace="user.givenname.display(value_for(user.givenname))" />
+          <span py:if="tg.errors.get('givenname')" class="fielderror"
+              py:content="tg.errors.get('givenname')" />
 
         </td>
       </tr>
@@ -106,13 +106,13 @@
       </tr>
       <tr>
         <th>
-          <label class="fieldlabel" for="${user.telephoneNumber.field_id}"
-            py:content="user.telephoneNumber.label" />
+          <label class="fieldlabel" for="${user.telephonenumber.field_id}"
+            py:content="user.telephonenumber.label" />
         </th>
         <td>
-          <span py:replace="user.telephoneNumber.display(value_for(user.telephoneNumber))" />
-          <span py:if="tg.errors.get('telephoneNumber')" class="fielderror"
-              py:content="tg.errors.get('telephoneNumber')" />
+          <span py:replace="user.telephonenumber.display(value_for(user.telephonenumber))" />
+          <span py:if="tg.errors.get('telephonenumber')" class="fielderror"
+              py:content="tg.errors.get('telephonenumber')" />
         </td>
       </tr>
     </table>
diff -r 45eb7e8045f8 -r 8d8234203e0e ipa-server/ipa-gui/ipagui/templates/usershow.kid
--- a/ipa-server/ipa-gui/ipagui/templates/usershow.kid	Wed Aug 15 10:48:34 2007 -0700
+++ b/ipa-server/ipa-gui/ipagui/templates/usershow.kid	Thu Aug 16 15:05:36 2007 -0700
@@ -18,15 +18,15 @@
         </tr>
         <tr>
           <th>
-            <label class="fieldlabel" py:content="fields.uidNumber.label" />
+            <label class="fieldlabel" py:content="fields.uidnumber.label" />
           </th>
-          <td>${user.get("uidNumber")}</td>
+          <td>${user.get("uidnumber")}</td>
         </tr>
         <tr>
           <th>
-            <label class="fieldlabel" py:content="fields.gidNumber.label" />
+            <label class="fieldlabel" py:content="fields.gidnumber.label" />
           </th>
-          <td>${user.get("gidNumber")}</td>
+          <td>${user.get("gidnumber")}</td>
         </tr>
     </table>
 
@@ -34,9 +34,9 @@
     <table class="formtable" cellpadding="2" cellspacing="0" border="0">
         <tr>
           <th>
-            <label class="fieldlabel" py:content="fields.givenName.label" />
+            <label class="fieldlabel" py:content="fields.givenname.label" />
           </th>
-          <td>${user.get("givenName")}</td>
+          <td>${user.get("givenname")}</td>
         </tr>
         <tr>
           <th>
@@ -56,9 +56,9 @@
         </tr>
         <tr>
           <th>
-            <label class="fieldlabel" py:content="fields.telephoneNumber.label" />
+            <label class="fieldlabel" py:content="fields.telephonenumber.label" />
           </th>
-          <td>${user.get("telephoneNumber")}</td>
+          <td>${user.get("telephonenumber")}</td>
         </tr>
     </table>
 
-------------- next part --------------
A non-text attachment was scrubbed...
Name: smime.p7s
Type: application/x-pkcs7-signature
Size: 2228 bytes
Desc: not available
URL: <http://listman.redhat.com/archives/freeipa-devel/attachments/20070816/6c3930e4/attachment.bin>


More information about the Freeipa-devel mailing list