[Freeipa-devel] [PATCH] split user edit form out

Kevin McCarthy kmccarth at redhat.com
Tue Aug 14 16:51:32 UTC 2007


Resending.  As near as I can tell this email somehow never made it to
the list.  Sorry if it's a dup.

-Kevin


----- Forwarded message from Kevin McCarthy <kmccarth at redhat.com> -----

Date: Fri, 10 Aug 2007 16:33:34 -0700
From: Kevin McCarthy <kmccarth at redhat.com>
To: freeipa-devel at redhat.com
Subject: [PATCH] split user edit form out
Message-ID: <20070810233334.GJ28334 at moon.usersys.redhat.com>
User-Agent: Mutt/1.5.16 (2007-06-09)

This patch splits the user edit and create forms.  It adds css for
required fields, and also a fix to make the edit form fields persist on
validation error.
-------------- next part --------------
# HG changeset patch
# User Kevin McCarthy <kmccarth at redhat.com>
# Date 1186788719 25200
# Node ID b530219c9afe7799d4ec49437f8c39622411793e
# Parent  50e8f67f0989c7f05d0d178dd85687ca4f2f76a7
Split userform into edit and new forms.
(They will likely diverge so no sense forcing them together).
Add css for required fields.
Add "_orig" hidden fields to the edit form in prep for sending only modified
fields.

diff -r 50e8f67f0989 -r b530219c9afe ipa-server/ipa-gui/ipagui/controllers.py
--- a/ipa-server/ipa-gui/ipagui/controllers.py	Fri Aug 10 17:05:55 2007 -0700
+++ b/ipa-server/ipa-gui/ipagui/controllers.py	Fri Aug 10 16:31:59 2007 -0700
@@ -7,7 +7,6 @@ from turbogears import error_handler
 # from model import *
 # import logging
 # log = logging.getLogger("ipagui.controllers")
-# import ipa.rpcclient
 import ipa.config
 import ipa.ipaclient
 import ipa.user
@@ -15,7 +14,8 @@ import forms.user
 import forms.user
 
 ipa.config.init_config()
-user_form = forms.user.UserFormWidget()
+user_new_form = forms.user.UserNewForm()
+user_edit_form = forms.user.UserEditForm()
 
 client = ipa.ipaclient.IPAClient(True)
 client.set_principal("test at FREEIPA.ORG")
@@ -32,8 +32,12 @@ def user_to_hash(user):
         'sn'        : user.getValue('sn'),
         'mail'      : user.getValue('mail'),
         'telephoneNumber': user.getValue('telephoneNumber'),
-        'uidNumber': user.getValue('uidNumber'),
-        'gidNumber': user.getValue('gidNumber'),
+        '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'),
             }
 
 class Root(controllers.RootController):
@@ -53,7 +57,7 @@ class Root(controllers.RootController):
         if tg_errors:
             turbogears.flash("There was a problem with the form!")
 
-        return dict(form=user_form)
+        return dict(form=user_new_form)
 
     @expose()
     def usercreate(self, **kw):
@@ -63,12 +67,11 @@ class Root(controllers.RootController):
             turbogears.flash("Add user cancelled")
             raise turbogears.redirect('/userlist')
 
-        tg_errors, kw = self.uservalidate(**kw)
+        tg_errors, kw = self.usercreatevalidate(**kw)
         if tg_errors:
-            return dict(form=user_form, tg_template='ipagui.templates.usernew')
+            return dict(form=user_new_form, tg_template='ipagui.templates.usernew')
 
         try:
-            # rv = ipa.rpcclient.add_user(kw)
             newuser = ipa.user.User(None)
             newuser.setValue('uid', kw['uid'])
             newuser.setValue('givenName', kw['givenName'])
@@ -87,7 +90,7 @@ class Root(controllers.RootController):
             raise turbogears.redirect('/usershow', uid=kw['uid'])
         except xmlrpclib.Fault, f:
             turbogears.flash("User add failed: " + str(f.faultString))
-            return dict(form=user_form, tg_template='ipagui.templates.usernew')
+            return dict(form=user_new_form, tg_template='ipagui.templates.usernew')
 
 
     @expose("ipagui.templates.useredit")
@@ -96,9 +99,8 @@ class Root(controllers.RootController):
         if tg_errors:
             turbogears.flash("There was a problem with the form!")
 
-        # user = ipa.rpcclient.get_user(uid)
         user = client.get_user(uid)
-        return dict(form=user_form, user=user_to_hash(user))
+        return dict(form=user_edit_form, user=user_to_hash(user))
 
     @expose()
     def userupdate(self, **kw):
@@ -108,24 +110,24 @@ class Root(controllers.RootController):
             turbogears.flash("Edit user cancelled")
             raise turbogears.redirect('/usershow', uid=kw.get('uid'))
 
-        tg_errors, kw = self.uservalidate(**kw)
+        tg_errors, kw = self.userupdatevalidate(**kw)
         if tg_errors:
-            return dict(form=user_form, user={}, tg_template='ipagui.templates.useredit')
+            return dict(form=user_edit_form, user=kw,
+                        tg_template='ipagui.templates.useredit')
 
         try:
-            # rv = ipa.rpcclient.add_user(kw)
             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))
-            return dict(form=user_form, user={}, tg_template='ipagui.templates.useredit')
+            return dict(form=user_edit_form, user=kw,
+                        tg_template='ipagui.templates.useredit')
 
 
     @expose("ipagui.templates.userlist")
     @paginate('users', limit=3, allow_limit_override=True)
     def userlist(self):
         """Retrieve a list of all users and display them in one huge list"""
-        # users = ipa.rpcclient.get_all_users()
         users = client.get_all_users()
         return dict(users=users)
 
@@ -134,15 +136,18 @@ class Root(controllers.RootController):
     def usershow(self, uid):
         """Retrieve a single user for display"""
         try:
-            # user = ipa.rpcclient.get_user(uid)
             user = client.get_user(uid)
             return dict(user=user_to_hash(user))
         except xmlrpclib.Fault, f:
             turbogears.flash("User show failed: " + str(f.faultString))
             raise turbogears.redirect("/")
 
-    @validate(form=user_form)
-    def uservalidate(self, tg_errors=None, **kw):
+    @validate(form=user_new_form)
+    def usercreatevalidate(self, tg_errors=None, **kw):
+        return tg_errors, kw
+
+    @validate(form=user_edit_form)
+    def userupdatevalidate(self, tg_errors=None, **kw):
         return tg_errors, kw
 
     @expose()
diff -r 50e8f67f0989 -r b530219c9afe ipa-server/ipa-gui/ipagui/forms/user.py
--- a/ipa-server/ipa-gui/ipagui/forms/user.py	Fri Aug 10 17:05:55 2007 -0700
+++ b/ipa-server/ipa-gui/ipagui/forms/user.py	Fri Aug 10 16:31:59 2007 -0700
@@ -19,26 +19,48 @@ class UserFields():
     #  validators.PhoneNumber may be a bit too picky, requiring an area code
     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")
 
-class UserFormWidget(widgets.Form):
+
+class UserNewForm(widgets.Form):
     params = ['user']
-#     fields = [UserFields.uid, UserFields.userPassword, UserFields.givenName,
-#               UserFields.sn, UserFields.mail]
+
     fields = [UserFields.uid, UserFields.givenName,
               UserFields.uidNumber, UserFields.gidNumber,
-               UserFields.sn, UserFields.mail]
+              UserFields.sn, UserFields.mail]
 
     def __init__(self, *args, **kw):
-        super(UserFormWidget,self).__init__(*args, **kw)
-        (self.template_c, self.template) = widgets.meta.load_kid_template("ipagui.templates.userform")
+        super(UserNewForm,self).__init__(*args, **kw)
+        (self.template_c, self.template) = widgets.meta.load_kid_template("ipagui.templates.usernewform")
         self.user = UserFields
 
     def update_params(self, params):
-        super(UserFormWidget,self).update_params(params)
+        super(UserNewForm,self).update_params(params)
         params['has_foo'] = self.has_foo
 
     def has_foo(self):
         return False
+
+
+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]
+
+    def __init__(self, *args, **kw):
+        super(UserEditForm,self).__init__(*args, **kw)
+        (self.template_c, self.template) = widgets.meta.load_kid_template("ipagui.templates.usereditform")
+        self.user = UserFields
+
 
 # TODO - add dynamic field retrieval:
 #      myfields=[]
diff -r 50e8f67f0989 -r b530219c9afe ipa-server/ipa-gui/ipagui/static/css/style.css
--- a/ipa-server/ipa-gui/ipagui/static/css/style.css	Fri Aug 10 17:05:55 2007 -0700
+++ b/ipa-server/ipa-gui/ipagui/static/css/style.css	Fri Aug 10 16:31:59 2007 -0700
@@ -144,3 +144,7 @@ body {
     color: red;
     font-weight: bold;
 }
+
+.requiredfield {
+    background: #eebbbb;
+}
diff -r 50e8f67f0989 -r b530219c9afe ipa-server/ipa-gui/ipagui/templates/usereditform.kid
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ipa-server/ipa-gui/ipagui/templates/usereditform.kid	Fri Aug 10 16:31:59 2007 -0700
@@ -0,0 +1,124 @@
+<div xmlns:py="http://purl.org/kid/ns#"
+  class="simpleroster">
+  <form action="${action}" name="${name}" method="${method}" class="tableform">
+
+
+  <div py:for="field in hidden_fields"
+    py:replace="field.display(value_for(field), **params_for(field))" 
+    />
+
+    <div class="formsection">Account Details</div>
+    <table class="formtable" cellpadding="2" cellspacing="0" border="0">
+      <tr>
+        <th>
+          <label class="fieldlabel" for="${user.uid.field_id}"
+            py:content="user.uid.label" />
+        </th>
+        <td>
+          ${value_for(user.uid)}
+        </td>
+      </tr>
+
+<!--      <tr>
+        <th>
+          <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')" />
+        </td>
+      </tr> -->
+
+      <tr>
+        <th>
+          <label class="fieldlabel" for="${user.uidNumber.field_id}"
+            py:content="user.uidNumber.label" />
+        </th>
+        <td>
+          ${value_for(user.uidNumber)}
+        </td>
+      </tr>
+
+      <tr>
+        <th>
+          <label class="fieldlabel" for="${user.gidNumber.field_id}"
+            py:content="user.gidNumber.label" />
+        </th>
+        <td>
+          ${value_for(user.gidNumber)}
+        </td>
+      </tr>
+    </table>
+
+    <div class="formsection">Identity Details</div>
+    <table class="formtable" cellpadding="2" cellspacing="0" border="0">
+      <tr>
+        <th>
+          <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')" />
+
+        </td>
+      </tr>
+
+      <tr>
+        <th>
+          <label class="fieldlabel" for="${user.sn.field_id}"
+            py:content="user.sn.label" />
+        </th>
+        <td>
+          <span py:replace="user.sn.display(value_for(user.sn))" />
+          <span py:if="tg.errors.get('sn')" class="fielderror"
+              py:content="tg.errors.get('sn')" />
+        </td>
+      </tr>
+    </table>
+
+    <div class="formsection">Contact Details</div>
+    <table class="formtable" cellpadding="2" cellspacing="0" border="0">
+      <tr>
+        <th>
+          <label class="fieldlabel" for="${user.mail.field_id}"
+            py:content="user.mail.label" />
+        </th>
+        <td>
+          <span py:replace="user.mail.display(value_for(user.mail))" />
+          <span py:if="tg.errors.get('mail')" class="fielderror"
+              py:content="tg.errors.get('mail')" />
+        </td>
+      </tr>
+      <tr>
+        <th>
+          <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')" />
+        </td>
+      </tr>
+    </table>
+
+    <table class="formtable" cellpadding="2" cellspacing="0" border="0">
+      <tr>
+        <th>
+          <br />
+          <input type="submit" class="submitbutton" name="submit" value="Submit"/>
+        </th>
+        <td>
+          <br />
+          <input type="submit" class="submitbutton" name="submit" value="Cancel" />
+        </td>
+        <td></td>
+      </tr>
+    </table>
+
+  </form>
+</div>
diff -r 50e8f67f0989 -r b530219c9afe ipa-server/ipa-gui/ipagui/templates/userform.kid
--- a/ipa-server/ipa-gui/ipagui/templates/userform.kid	Fri Aug 10 17:05:55 2007 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,125 +0,0 @@
-<div xmlns:py="http://purl.org/kid/ns#"
-  class="simpleroster">
-  <form action="${action}" name="${name}" method="${method}" class="tableform">
-
-    <div class="formsection">Account Details</div>
-    <table class="formtable" cellpadding="2" cellspacing="0" border="0">
-      <tr>
-        <th>
-          <label class="fieldlabel" for="${user.uid.field_id}"
-            py:content="user.uid.label" />
-        </th>
-        <td>
-          <span py:replace="user.uid.display(value_for(user.uid))" />
-          <span py:if="tg.errors.get('uid')" class="fielderror"
-              py:content="tg.errors.get('uid')" />
-        </td>
-      </tr>
-
-<!--      <tr>
-        <th>
-          <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')" />
-        </td>
-      </tr> -->
-
-      <tr>
-        <th>
-          <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')" />
-        </td>
-      </tr>
-
-      <tr>
-        <th>
-          <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')" />
-        </td>
-      </tr>
-    </table>
-
-    <div class="formsection">Identity Details</div>
-    <table class="formtable" cellpadding="2" cellspacing="0" border="0">
-      <tr>
-        <th>
-          <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')" />
-
-        </td>
-      </tr>
-
-      <tr>
-        <th>
-          <label class="fieldlabel" for="${user.sn.field_id}"
-            py:content="user.sn.label" />
-        </th>
-        <td>
-          <span py:replace="user.sn.display(value_for(user.sn))" />
-          <span py:if="tg.errors.get('sn')" class="fielderror"
-              py:content="tg.errors.get('sn')" />
-        </td>
-      </tr>
-    </table>
-
-    <div class="formsection">Contact Details</div>
-    <table class="formtable" cellpadding="2" cellspacing="0" border="0">
-      <tr>
-        <th>
-          <label class="fieldlabel" for="${user.mail.field_id}"
-            py:content="user.mail.label" />
-        </th>
-        <td>
-          <span py:replace="user.mail.display(value_for(user.mail))" />
-          <span py:if="tg.errors.get('mail')" class="fielderror"
-              py:content="tg.errors.get('mail')" />
-        </td>
-      </tr>
-      <tr>
-        <th>
-          <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')" />
-        </td>
-      </tr>
-    </table>
-
-    <table class="formtable" cellpadding="2" cellspacing="0" border="0">
-      <tr>
-        <th>
-          <br />
-          <input type="submit" class="submitbutton" name="submit" value="Submit"/>
-        </th>
-        <td>
-          <br />
-          <input type="submit" class="submitbutton" name="submit" value="Cancel" />
-        </td>
-        <td></td>
-      </tr>
-    </table>
-
-  </form>
-</div>
diff -r 50e8f67f0989 -r b530219c9afe ipa-server/ipa-gui/ipagui/templates/usernewform.kid
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ipa-server/ipa-gui/ipagui/templates/usernewform.kid	Fri Aug 10 16:31:59 2007 -0700
@@ -0,0 +1,125 @@
+<div xmlns:py="http://purl.org/kid/ns#"
+  class="simpleroster">
+  <form action="${action}" name="${name}" method="${method}" class="tableform">
+
+    <div class="formsection">Account Details</div>
+    <table class="formtable" cellpadding="2" cellspacing="0" border="0">
+      <tr>
+        <th>
+          <label class="fieldlabel" for="${user.uid.field_id}"
+            py:content="user.uid.label" />
+        </th>
+        <td>
+          <span py:replace="user.uid.display(value_for(user.uid))" />
+          <span py:if="tg.errors.get('uid')" class="fielderror"
+              py:content="tg.errors.get('uid')" />
+        </td>
+      </tr>
+
+<!--      <tr>
+        <th>
+          <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')" />
+        </td>
+      </tr> -->
+
+      <tr>
+        <th>
+          <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')" />
+        </td>
+      </tr>
+
+      <tr>
+        <th>
+          <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')" />
+        </td>
+      </tr>
+    </table>
+
+    <div class="formsection">Identity Details</div>
+    <table class="formtable" cellpadding="2" cellspacing="0" border="0">
+      <tr>
+        <th>
+          <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')" />
+
+        </td>
+      </tr>
+
+      <tr>
+        <th>
+          <label class="fieldlabel" for="${user.sn.field_id}"
+            py:content="user.sn.label" />
+        </th>
+        <td>
+          <span py:replace="user.sn.display(value_for(user.sn))" />
+          <span py:if="tg.errors.get('sn')" class="fielderror"
+              py:content="tg.errors.get('sn')" />
+        </td>
+      </tr>
+    </table>
+
+    <div class="formsection">Contact Details</div>
+    <table class="formtable" cellpadding="2" cellspacing="0" border="0">
+      <tr>
+        <th>
+          <label class="fieldlabel" for="${user.mail.field_id}"
+            py:content="user.mail.label" />
+        </th>
+        <td>
+          <span py:replace="user.mail.display(value_for(user.mail))" />
+          <span py:if="tg.errors.get('mail')" class="fielderror"
+              py:content="tg.errors.get('mail')" />
+        </td>
+      </tr>
+      <tr>
+        <th>
+          <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')" />
+        </td>
+      </tr>
+    </table>
+
+    <table class="formtable" cellpadding="2" cellspacing="0" border="0">
+      <tr>
+        <th>
+          <br />
+          <input type="submit" class="submitbutton" name="submit" value="Submit"/>
+        </th>
+        <td>
+          <br />
+          <input type="submit" class="submitbutton" name="submit" value="Cancel" />
+        </td>
+        <td></td>
+      </tr>
+    </table>
+
+  </form>
+</div>
-------------- 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/20070814/2c4d07cd/attachment.bin>


More information about the Freeipa-devel mailing list