[Freeipa-devel] [PATCH] split controllers out

Kevin McCarthy kmccarth at redhat.com
Fri Oct 5 00:11:52 UTC 2007


This patch _looks_ big, but in truth it's just moving a bunch of code.
The main controllers.py is too big - I should have split it up a long
time ago, so now the sooner the better.

-Kevin

-------------- next part --------------
# HG changeset patch
# User Kevin McCarthy <kmccarth at redhat.com>
# Date 1191543018 25200
# Node ID ed3b5011eae26ba896c6b438db49c7829e333e9e
# Parent  157e43b04db3a9cc23d65f814b670667c3a2b61c
Split the controllers out into separate user and group controllers.

diff -r 157e43b04db3 -r ed3b5011eae2 ipa-server/ipa-gui/ipagui/controllers.py
--- a/ipa-server/ipa-gui/ipagui/controllers.py	Thu Oct 04 14:34:49 2007 -0700
+++ b/ipa-server/ipa-gui/ipagui/controllers.py	Thu Oct 04 17:10:18 2007 -0700
@@ -1,9 +1,3 @@ import random
-import random
-from pickle import dumps, loads
-from base64 import b64encode, b64decode
-import re
-
-import os
 import cherrypy
 import turbogears
 from turbogears import controllers, expose, flash
@@ -17,79 +11,15 @@ from turbogears import identity
 
 import ipa.config
 import ipa.ipaclient
-import ipa.user
-from ipa.entity import utf8_encode_values
-import xmlrpclib
-import forms.user
-import forms.group
-from helpers import userhelper
-from ipa import ipaerror
+
+from subcontrollers.user import UserController
+from subcontrollers.group import GroupController
 
 ipa.config.init_config()
-user_new_form = forms.user.UserNewForm()
-user_edit_form = forms.user.UserEditForm()
-group_new_form = forms.group.GroupNewForm()
-group_edit_form = forms.group.GroupEditForm()
-
-password_chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
-
-client = ipa.ipaclient.IPAClient(True)
-
-user_fields = ['*', 'nsAccountLock']
-
-group_fields = ['*']
-
-def restrict_post():
-    if cherrypy.request.method != "POST":
-        turbogears.flash("This method only accepts posts")
-        raise turbogears.redirect("/")
-
-def utf8_encode(value):
-    if value != None:
-        value = value.encode('utf-8')
-    return value
-
-def sort_group_member(a, b):
-    """Comparator function used for sorting group members."""
-    if a.getValue('uid') and b.getValue('uid'):
-        if a.getValue('givenname') == b.getValue('givenname'):
-            if a.getValue('sn') == b.getValue('sn'):
-                if a.getValue('uid') == b.getValue('uid'):
-                    return 0
-                elif a.getValue('uid') < b.getValue('uid'):
-                    return -1
-                else:
-                    return 1
-            elif a.getValue('sn') < b.getValue('sn'):
-                return -1
-            else:
-                return 1
-        elif a.getValue('givenname') < b.getValue('givenname'):
-            return -1
-        else:
-            return 1
-    elif a.getValue('uid'):
-        return -1
-    elif b.getValue('uid'):
-        return 1
-    else:
-        if a.getValue('cn') == b.getValue('cn'):
-            return 0
-        elif a.getValue('cn') < b.getValue('cn'):
-            return -1
-        else:
-            return 1
-
-def sort_by_cn(a, b):
-    """Comparator function used for sorting groups."""
-    if a.getValue('cn') == b.getValue('cn'):
-        return 0
-    elif a.getValue('cn') < b.getValue('cn'):
-        return -1
-    else:
-        return 1
 
 class Root(controllers.RootController):
+    user = UserController()
+    group = GroupController()
 
     @expose(template="ipagui.templates.welcome")
     @identity.require(identity.not_anonymous())
@@ -100,875 +30,9 @@ class Root(controllers.RootController):
     @identity.require(identity.not_anonymous())
     def topsearch(self, **kw):
         if kw.get('searchtype') == "Users":
-            return self.userlist(uid=kw.get('searchvalue'))
+            return Root.user.list(uid=kw.get('searchvalue'))
         else:
-            return self.grouplist(criteria=kw.get('searchvalue'))
-
-
-
-    ########
-    # User #
-    ########
-
-    @expose("ipagui.templates.usernew")
-    @identity.require(identity.not_anonymous())
-    def usernew(self, tg_errors=None):
-        """Displays the new user form"""
-        if tg_errors:
-            turbogears.flash("There was a problem with the form!")
-
-        return dict(form=user_new_form, user={})
-
-    @expose()
-    @identity.require(identity.not_anonymous())
-    def usercreate(self, **kw):
-        """Creates a new user"""
-        restrict_post()
-        client.set_krbccache(os.environ["KRB5CCNAME"])
-        if kw.get('submit') == 'Cancel':
-            turbogears.flash("Add user cancelled")
-            raise turbogears.redirect('/userlist')
-
-        tg_errors, kw = self.usercreatevalidate(**kw)
-        if tg_errors:
-            return dict(form=user_new_form, user=kw,
-                    tg_template='ipagui.templates.usernew')
-
-        #
-        # Create the user itself
-        #
-        try:
-            new_user = ipa.user.User()
-            new_user.setValue('title', kw.get('title'))
-            new_user.setValue('givenname', kw.get('givenname'))
-            new_user.setValue('sn', kw.get('sn'))
-            new_user.setValue('cn', kw.get('cn'))
-            new_user.setValue('displayname', kw.get('displayname'))
-            new_user.setValue('initials', kw.get('initials'))
-
-            new_user.setValue('uid', kw.get('uid'))
-            new_user.setValue('loginshell', kw.get('loginshell'))
-            new_user.setValue('gecos', kw.get('gecos'))
-
-            new_user.setValue('mail', kw.get('mail'))
-            new_user.setValue('telephonenumber', kw.get('telephonenumber'))
-            new_user.setValue('facsimiletelephonenumber',
-                    kw.get('facsimiletelephonenumber'))
-            new_user.setValue('mobile', kw.get('mobile'))
-            new_user.setValue('pager', kw.get('pager'))
-            new_user.setValue('homephone', kw.get('homephone'))
-
-            new_user.setValue('street', kw.get('street'))
-            new_user.setValue('l', kw.get('l'))
-            new_user.setValue('st', kw.get('st'))
-            new_user.setValue('postalcode', kw.get('postalcode'))
-
-            new_user.setValue('ou', kw.get('ou'))
-            new_user.setValue('businesscategory', kw.get('businesscategory'))
-            new_user.setValue('description', kw.get('description'))
-            new_user.setValue('employeetype', kw.get('employeetype'))
-            # new_user.setValue('manager', kw.get('manager'))
-            new_user.setValue('roomnumber', kw.get('roomnumber'))
-            # new_user.setValue('secretary', kw.get('secretary'))
-
-            new_user.setValue('carlicense', kw.get('carlicense'))
-            new_user.setValue('labeleduri', kw.get('labeleduri'))
-
-            if kw.get('nsAccountLock'):
-                new_user.setValue('nsAccountLock', 'true')
-
-            rv = client.add_user(new_user)
-        except ipaerror.exception_for(ipaerror.LDAP_DUPLICATE):
-            turbogears.flash("Person with login '%s' already exists" %
-                    kw.get('uid'))
-            return dict(form=user_new_form, user=kw,
-                    tg_template='ipagui.templates.usernew')
-        except ipaerror.IPAError, e:
-            turbogears.flash("User add failed: " + str(e))
-            return dict(form=user_new_form, user=kw,
-                    tg_template='ipagui.templates.usernew')
-
-        #
-        # NOTE: from here on, the user account now exists.
-        #       on any error, we redirect to the _edit_ user page.
-        #       this code does data setup, similar to useredit()
-        #
-        user = client.get_user_by_uid(kw['uid'], user_fields)
-        user_dict = user.toDict()
-
-        user_groups_dicts = []
-        user_groups_data = b64encode(dumps(user_groups_dicts))
-
-        # store a copy of the original user for the update later
-        user_data = b64encode(dumps(user_dict))
-        user_dict['user_orig'] = user_data
-        user_dict['user_groups_data'] = user_groups_data
-
-        # preserve group add info in case of errors
-        user_dict['dnadd'] = kw.get('dnadd')
-        user_dict['dn_to_info_json'] = kw.get('dn_to_info_json')
-
-        #
-        # Password change
-        # TODO
-        #
-
-        #
-        # Add groups
-        #
-        failed_adds = []
-        try:
-            dnadds = kw.get('dnadd')
-            if dnadds != None:
-                if not(isinstance(dnadds,list) or isinstance(dnadds,tuple)):
-                    dnadds = [dnadds]
-                failed_adds = client.add_groups_to_user(
-                        utf8_encode_values(dnadds), user.dn)
-                kw['dnadd'] = failed_adds
-        except ipaerror.IPAError, e:
-            failed_adds = dnadds
-
-        if len(failed_adds) > 0:
-            message = "Person successfully created.<br />"
-            message += "There was an error adding groups.<br />"
-            message += "Failures have been preserved in the add/remove lists."
-            turbogears.flash(message)
-            return dict(form=user_edit_form, user=user_dict,
-                        user_groups=user_groups_dicts,
-                        tg_template='ipagui.templates.useredit')
-
-        turbogears.flash("%s added!" % kw['uid'])
-        raise turbogears.redirect('/usershow', uid=kw['uid'])
-
-    @expose("ipagui.templates.dynamiceditsearch")
-    @identity.require(identity.not_anonymous())
-    def useredit_search(self, **kw):
-        """Searches for groups and displays list of results in a table.
-           This method is used for the ajax search on the user edit page."""
-        client.set_krbccache(os.environ["KRB5CCNAME"])
-        groups = []
-        groups_counter = 0
-        searchlimit = 100
-        criteria = kw.get('criteria')
-        if criteria != None and len(criteria) > 0:
-            try:
-                groups = client.find_groups(criteria.encode('utf-8'), None,
-                        searchlimit)
-                groups_counter = groups[0]
-                groups = groups[1:]
-            except ipaerror.IPAError, e:
-                turbogears.flash("search failed: " + str(e))
-
-        return dict(users=None, groups=groups, criteria=criteria,
-                counter=groups_counter)
-
-
-    @expose("ipagui.templates.useredit")
-    @identity.require(identity.not_anonymous())
-    def useredit(self, uid, tg_errors=None):
-        """Displays the edit user form"""
-        if tg_errors:
-            turbogears.flash("There was a problem with the form!")
-
-        client.set_krbccache(os.environ["KRB5CCNAME"])
-        try:
-            user = client.get_user_by_uid(uid, user_fields)
-            user_dict = user.toDict()
-            # Edit shouldn't fill in the password field.
-            if user_dict.has_key('userpassword'):
-                del(user_dict['userpassword'])
-
-            user_groups = client.get_groups_by_member(user.dn, ['dn', 'cn'])
-            user_groups.sort(sort_by_cn)
-            user_groups_dicts = map(lambda group: group.toDict(), user_groups)
-            user_groups_data = b64encode(dumps(user_groups_dicts))
-
-            # store a copy of the original user for the update later
-            user_data = b64encode(dumps(user_dict))
-            user_dict['user_orig'] = user_data
-            user_dict['user_groups_data'] = user_groups_data
-
-            return dict(form=user_edit_form, user=user_dict,
-                    user_groups=user_groups_dicts)
-        except ipaerror.IPAError, e:
-            turbogears.flash("User edit failed: " + str(e))
-            raise turbogears.redirect('/usershow', uid=kw.get('uid'))
-
-    @expose()
-    @identity.require(identity.not_anonymous())
-    def userupdate(self, **kw):
-        """Updates an existing user"""
-        restrict_post()
-        client.set_krbccache(os.environ["KRB5CCNAME"])
-        if kw.get('submit') == 'Cancel Edit':
-            turbogears.flash("Edit user cancelled")
-            raise turbogears.redirect('/usershow', uid=kw.get('uid'))
-
-        # Decode the group data, in case we need to round trip
-        user_groups_dicts = loads(b64decode(kw.get('user_groups_data')))
-
-        tg_errors, kw = self.userupdatevalidate(**kw)
-        if tg_errors:
-            return dict(form=user_edit_form, user=kw,
-                        user_groups=user_groups_dicts,
-                        tg_template='ipagui.templates.useredit')
-
-        password_change = False
-        user_modified = False
-
-        #
-        # Update the user itself
-        #
-        try:
-            orig_user_dict = loads(b64decode(kw.get('user_orig')))
-
-            new_user = ipa.user.User(orig_user_dict)
-            new_user.setValue('title', kw.get('title'))
-            new_user.setValue('givenname', kw.get('givenname'))
-            new_user.setValue('sn', kw.get('sn'))
-            new_user.setValue('cn', kw.get('cn'))
-            new_user.setValue('displayname', kw.get('displayname'))
-            new_user.setValue('initials', kw.get('initials'))
-
-            new_user.setValue('loginshell', kw.get('loginshell'))
-            new_user.setValue('gecos', kw.get('gecos'))
-
-            new_user.setValue('mail', kw.get('mail'))
-            new_user.setValue('telephonenumber', kw.get('telephonenumber'))
-            new_user.setValue('facsimiletelephonenumber',
-                    kw.get('facsimiletelephonenumber'))
-            new_user.setValue('mobile', kw.get('mobile'))
-            new_user.setValue('pager', kw.get('pager'))
-            new_user.setValue('homephone', kw.get('homephone'))
-
-            new_user.setValue('street', kw.get('street'))
-            new_user.setValue('l', kw.get('l'))
-            new_user.setValue('st', kw.get('st'))
-            new_user.setValue('postalcode', kw.get('postalcode'))
-
-            new_user.setValue('ou', kw.get('ou'))
-            new_user.setValue('businesscategory', kw.get('businesscategory'))
-            new_user.setValue('description', kw.get('description'))
-            new_user.setValue('employeetype', kw.get('employeetype'))
-            # new_user.setValue('manager', kw.get('manager'))
-            new_user.setValue('roomnumber', kw.get('roomnumber'))
-            # new_user.setValue('secretary', kw.get('secretary'))
-
-            new_user.setValue('carlicense', kw.get('carlicense'))
-            new_user.setValue('labeleduri', kw.get('labeleduri'))
-
-
-            if kw.get('nsAccountLock'):
-                new_user.setValue('nsAccountLock', 'true')
-            else:
-                new_user.setValue('nsAccountLock', None)
-            if kw.get('editprotected') == 'true':
-                if kw.get('userpassword'):
-                    password_change = True
-                new_user.setValue('uidnumber', str(kw.get('uidnumber')))
-                new_user.setValue('gidnumber', str(kw.get('gidnumber')))
-                new_user.setValue('homedirectory', str(kw.get('homedirectory')))
-
-            rv = client.update_user(new_user)
-            #
-            # If the user update succeeds, but below operations fail, we
-            # need to make sure a subsequent submit doesn't try to update
-            # the user again.
-            #
-            user_modified = True
-            kw['user_orig'] = b64encode(dumps(new_user.toDict()))
-        except ipaerror.exception_for(ipaerror.LDAP_EMPTY_MODLIST), e:
-            # could be a password change
-            # could be groups change
-            # too much work to figure out unless someone really screams
-            pass
-        except ipaerror.IPAError, e:
-            turbogears.flash("User update failed: " + str(e))
-            return dict(form=user_edit_form, user=kw,
-                        user_groups=user_groups_dicts,
-                        tg_template='ipagui.templates.useredit')
-
-        #
-        # Password change
-        #
-        try:
-            if password_change:
-                rv = client.modifyPassword(kw['krbprincipalname'], "", kw.get('userpassword'))
-        except ipaerror.IPAError, e:
-            turbogears.flash("User password change failed: " + str(e))
-            return dict(form=user_edit_form, user=kw,
-                        user_groups=user_groups_dicts,
-                        tg_template='ipagui.templates.useredit')
-
-        #
-        # Add groups
-        #
-        failed_adds = []
-        try:
-            dnadds = kw.get('dnadd')
-            if dnadds != None:
-                if not(isinstance(dnadds,list) or isinstance(dnadds,tuple)):
-                    dnadds = [dnadds]
-                failed_adds = client.add_groups_to_user(
-                        utf8_encode_values(dnadds), new_user.dn)
-                kw['dnadd'] = failed_adds
-        except ipaerror.IPAError, e:
-            failed_adds = dnadds
-
-        #
-        # Remove groups
-        #
-        failed_dels = []
-        try:
-            dndels = kw.get('dndel')
-            if dndels != None:
-                if not(isinstance(dndels,list) or isinstance(dndels,tuple)):
-                    dndels = [dndels]
-                failed_dels = client.remove_groups_from_user(
-                        utf8_encode_values(dndels), new_user.dn)
-                kw['dndel'] = failed_dels
-        except ipaerror.IPAError, e:
-            failed_dels = dndels
-
-        if (len(failed_adds) > 0) or (len(failed_dels) > 0):
-            message = "There was an error updating groups.<br />"
-            message += "Failures have been preserved in the add/remove lists."
-            if user_modified:
-                message = "User Details successfully updated.<br />" + message
-            if password_change:
-                message = "User password successfully updated.<br />" + message
-            turbogears.flash(message)
-            return dict(form=user_edit_form, user=kw,
-                        user_groups=user_groups_dicts,
-                        tg_template='ipagui.templates.useredit')
-
-        turbogears.flash("%s updated!" % kw['uid'])
-        raise turbogears.redirect('/usershow', uid=kw['uid'])
-
-
-    @expose("ipagui.templates.userlist")
-    @identity.require(identity.not_anonymous())
-    def userlist(self, **kw):
-        """Searches for users and displays list of results"""
-        client.set_krbccache(os.environ["KRB5CCNAME"])
-        users = None
-        counter = 0
-        uid = kw.get('uid')
-        if uid != None and len(uid) > 0:
-            try:
-                users = client.find_users(uid.encode('utf-8'), None, 0, 2)
-                counter = users[0]
-                users = users[1:]
-                if counter == -1:
-                    turbogears.flash("These results are truncated.<br />" +
-                                    "Please refine your search and try again.")
-            except ipaerror.IPAError, e:
-                turbogears.flash("User list failed: " + str(e))
-                raise turbogears.redirect("/userlist")
-
-        return dict(users=users, uid=uid, fields=forms.user.UserFields())
-
-
-    @expose("ipagui.templates.usershow")
-    @identity.require(identity.not_anonymous())
-    def usershow(self, uid):
-        """Retrieve a single user for display"""
-        client.set_krbccache(os.environ["KRB5CCNAME"])
-        try:
-            user = client.get_user_by_uid(uid, user_fields)
-            user_groups = client.get_groups_by_member(user.dn, ['cn'])
-            user_groups.sort(sort_by_cn)
-            user_reports = client.get_users_by_manager(user.dn,
-                    ['givenname', 'sn', 'uid'])
-            user_reports.sort(sort_group_member)
-
-            user_manager = None
-            try:
-                if user.manager:
-                    user_manager = client.get_user_by_dn(user.manager,
-                        ['givenname', 'sn', 'uid'])
-            except ipaerror.exception_for(ipaerror.LDAP_NOT_FOUND):
-                pass
-
-            return dict(user=user.toDict(), fields=forms.user.UserFields(),
-                        user_groups=user_groups, user_reports=user_reports,
-                        user_manager=user_manager)
-        except ipaerror.IPAError, e:
-            turbogears.flash("User show failed: " + str(e))
-            raise turbogears.redirect("/")
-
-    @validate(form=user_new_form)
-    @identity.require(identity.not_anonymous())
-    def usercreatevalidate(self, tg_errors=None, **kw):
-        return tg_errors, kw
-
-    @validate(form=user_edit_form)
-    @identity.require(identity.not_anonymous())
-    def userupdatevalidate(self, tg_errors=None, **kw):
-        return tg_errors, kw
-
-    @expose()
-    def userindex(self):
-        raise turbogears.redirect("/userlist")
-
-    # @expose()
-    def generate_password(self):
-        password = ""
-        generator = random.SystemRandom()
-        for char in range(8):
-            index = generator.randint(0, len(password_chars) - 1)
-            password += password_chars[index]
-
-        return password
-
-    @expose()
-    @identity.require(identity.not_anonymous())
-    def suggest_uid(self, givenname, sn):
-        # filter illegal uid characters out
-        givenname = re.sub(r'[^a-zA-Z_\-0-9]', "", givenname)
-        sn = re.sub(r'[^a-zA-Z_\-0-9]', "", sn)
-
-        if (len(givenname) == 0) or (len(sn) == 0):
-            return ""
-
-        client.set_krbccache(os.environ["KRB5CCNAME"])
-        givenname = givenname.lower()
-        sn = sn.lower()
-
-        uid = givenname[0] + sn[:7]
-        try:
-            client.get_user_by_uid(uid)
-        except ipaerror.exception_for(ipaerror.LDAP_NOT_FOUND):
-            return uid
-
-        uid = givenname[:7] + sn[0]
-        try:
-            client.get_user_by_uid(uid)
-        except ipaerror.exception_for(ipaerror.LDAP_NOT_FOUND):
-            return uid
-
-        uid = (givenname + sn)[:8]
-        try:
-            client.get_user_by_uid(uid)
-        except ipaerror.exception_for(ipaerror.LDAP_NOT_FOUND):
-            return uid
-
-        uid = sn[:8]
-        try:
-            client.get_user_by_uid(uid)
-        except ipaerror.exception_for(ipaerror.LDAP_NOT_FOUND):
-            return uid
-
-        suffix = 2
-        template = givenname[0] + sn[:7]
-        while suffix < 20:
-            uid = template[:8 - len(str(suffix))] + str(suffix)
-            try:
-                client.get_user_by_uid(uid)
-            except ipaerror.exception_for(ipaerror.LDAP_NOT_FOUND):
-                return uid
-            suffix += 1
-
-        return ""
-
-    @expose()
-    @identity.require(identity.not_anonymous())
-    def suggest_email(self, givenname, sn):
-        # remove illegal email characters
-        givenname = re.sub(r'[^a-zA-Z0-9!#\$%\*/?\|\^\{\}`~&\'\+\-=_]', "", givenname)
-        sn = re.sub(r'[^a-zA-Z0-9!#\$%\*/?\|\^\{\}`~&\'\+\-=_]', "", sn)
-
-        if (len(givenname) == 0) or (len(sn) == 0):
-            return ""
-
-        client.set_krbccache(os.environ["KRB5CCNAME"])
-        givenname = givenname.lower()
-        sn = sn.lower()
-
-        # TODO - get from config
-        domain = "freeipa.org"
-
-        return "%s.%s@%s" % (givenname, sn, domain)
-
-
-        # TODO - mail is currently not indexed nor searchable.
-        #        implement when it's done
-        # email = givenname + "." + sn + domain
-        # users = client.find_users(email, ['mail'])
-        # if len(filter(lambda u: u['mail'] == email, users[1:])) == 0:
-        #     return email
-
-        # email = self.suggest_uid(givenname, sn) + domain
-        # users = client.find_users(email, ['mail'])
-        # if len(filter(lambda u: u['mail'] == email, users[1:])) == 0:
-        #     return email
-
-        # suffix = 2
-        # template = givenname + "." + sn
-        # while suffix < 20:
-        #     email = template + str(suffix) + domain
-        #     users = client.find_users(email, ['mail'])
-        #     if len(filter(lambda u: u['mail'] == email, users[1:])) == 0:
-        #         return email
-        #     suffix += 1
-
-        # return ""
-
-
-
-    #########
-    # Group #
-    #########
-
-    @expose("ipagui.templates.groupindex")
-    @identity.require(identity.not_anonymous())
-    def groupindex(self, tg_errors=None):
-        client.set_krbccache(os.environ["KRB5CCNAME"])
-        return dict()
-
-    @expose("ipagui.templates.groupnew")
-    @identity.require(identity.not_anonymous())
-    def groupnew(self, tg_errors=None):
-        """Displays the new group form"""
-        if tg_errors:
-            turbogears.flash("There was a problem with the form!")
-
-        client.set_krbccache(os.environ["KRB5CCNAME"])
-
-        return dict(form=group_new_form, group={})
-
-    @expose()
-    @identity.require(identity.not_anonymous())
-    def groupcreate(self, **kw):
-        """Creates a new group"""
-        restrict_post()
-        client.set_krbccache(os.environ["KRB5CCNAME"])
-
-        if kw.get('submit') == 'Cancel':
-            turbogears.flash("Add group cancelled")
-            raise turbogears.redirect('/')
-
-        tg_errors, kw = self.groupcreatevalidate(**kw)
-        if tg_errors:
-            return dict(form=group_new_form, group=kw,
-                    tg_template='ipagui.templates.groupnew')
-
-        #
-        # Create the group itself
-        #
-        try:
-            new_group = ipa.group.Group()
-            new_group.setValue('cn', kw.get('cn'))
-            new_group.setValue('description', kw.get('description'))
-
-            rv = client.add_group(new_group)
-        except ipaerror.exception_for(ipaerror.LDAP_DUPLICATE):
-            turbogears.flash("Group with name '%s' already exists" %
-                    kw.get('cn'))
-            return dict(form=group_new_form, group=kw,
-                    tg_template='ipagui.templates.groupnew')
-        except ipaerror.IPAError, e:
-            turbogears.flash("Group add failed: " + str(e) + "<br/>" + str(e.detail))
-            return dict(form=group_new_form, group=kw,
-                    tg_template='ipagui.templates.groupnew')
-
-        #
-        # NOTE: from here on, the group now exists.
-        #       on any error, we redirect to the _edit_ group page.
-        #       this code does data setup, similar to groupedit()
-        #
-        group = client.get_group_by_cn(kw['cn'], group_fields)
-        group_dict = group.toDict()
-        member_dicts = []
-
-        # store a copy of the original group for the update later
-        group_data = b64encode(dumps(group_dict))
-        member_data = b64encode(dumps(member_dicts))
-        group_dict['group_orig'] = group_data
-        group_dict['member_data'] = member_data
-
-        # preserve group add info in case of errors
-        group_dict['dnadd'] = kw.get('dnadd')
-        group_dict['dn_to_info_json'] = kw.get('dn_to_info_json')
-
-        #
-        # Add members
-        #
-        failed_adds = []
-        try:
-            dnadds = kw.get('dnadd')
-            if dnadds != None:
-                if not(isinstance(dnadds,list) or isinstance(dnadds,tuple)):
-                    dnadds = [dnadds]
-                failed_adds = client.add_members_to_group(
-                        utf8_encode_values(dnadds), group.dn)
-                kw['dnadd'] = failed_adds
-        except ipaerror.IPAError, e:
-            failed_adds = dnadds
-
-        if len(failed_adds) > 0:
-            message = "Group successfully created.<br />"
-            message += "There was an error adding group members.<br />"
-            message += "Failures have been preserved in the add/remove lists."
-            turbogears.flash(message)
-            return dict(form=group_edit_form, group=group_dict,
-                        members=member_dicts,
-                        tg_template='ipagui.templates.groupedit')
-
-        turbogears.flash("%s added!" % kw.get('cn'))
-        raise turbogears.redirect('/groupshow', cn=kw.get('cn'))
-
-    @expose("ipagui.templates.dynamiceditsearch")
-    @identity.require(identity.not_anonymous())
-    def groupedit_search(self, **kw):
-        """Searches for users+groups and displays list of results in a table.
-           This method is used for the ajax search on the group edit page."""
-        client.set_krbccache(os.environ["KRB5CCNAME"])
-        users = []
-        groups = []
-        counter = 0
-        searchlimit = 100
-        criteria = kw.get('criteria')
-        if criteria != None and len(criteria) > 0:
-            try:
-                users = client.find_users(criteria.encode('utf-8'), None, searchlimit)
-                users_counter = users[0]
-                users = users[1:]
-
-                groups = client.find_groups(criteria.encode('utf-8'), None,
-                        searchlimit)
-                groups_counter = groups[0]
-                groups = groups[1:]
-
-                if users_counter < 0 or groups_counter < 0:
-                    counter = -1
-                else:
-                    counter = users_counter + groups_counter
-            except ipaerror.IPAError, e:
-                turbogears.flash("search failed: " + str(e))
-
-        return dict(users=users, groups=groups, criteria=criteria,
-                counter=counter)
-
-
-    @expose("ipagui.templates.groupedit")
-    @identity.require(identity.not_anonymous())
-    def groupedit(self, cn, tg_errors=None):
-        """Displays the edit group form"""
-        if tg_errors:
-            turbogears.flash("There was a problem with the form!")
-
-        client.set_krbccache(os.environ["KRB5CCNAME"])
-        try:
-            group = client.get_group_by_cn(cn, group_fields)
-
-            group_dict = group.toDict()
-
-            #
-            # convert members to users, for easier manipulation on the page
-            #
-            member_dns = []
-            if group_dict.has_key('uniquemember'):
-                member_dns = group_dict.get('uniquemember')
-                # remove from dict - it's not needed for update
-                # and we are storing the members in a different form
-                del group_dict['uniquemember']
-            if not(isinstance(member_dns,list) or isinstance(member_dns,tuple)):
-                member_dns = [member_dns]
-
-            # TODO: convert this into an efficient (single) function call
-            # Note: this isn't quite right, since it can be users and groups.
-            members = map(
-                    lambda dn: client.get_user_by_dn(dn, ['dn', 'givenname', 'sn',
-                        'uid', 'cn']),
-                    member_dns)
-            members.sort(sort_group_member)
-
-            # Map users into an array of dicts, which can be serialized
-            # (so we don't have to do this on each round trip)
-            member_dicts = map(lambda member: member.toDict(), members)
-
-            # store a copy of the original group for the update later
-            group_data = b64encode(dumps(group_dict))
-            member_data = b64encode(dumps(member_dicts))
-            group_dict['group_orig'] = group_data
-            group_dict['member_data'] = member_data
-
-            return dict(form=group_edit_form, group=group_dict, members=member_dicts)
-        except ipaerror.IPAError, e:
-            turbogears.flash("Group edit failed: " + str(e))
-            raise turbogears.redirect('/groupshow', uid=cn)
-
-    @expose()
-    @identity.require(identity.not_anonymous())
-    def groupupdate(self, **kw):
-        """Updates an existing group"""
-        restrict_post()
-        client.set_krbccache(os.environ["KRB5CCNAME"])
-        if kw.get('submit') == 'Cancel Edit':
-            turbogears.flash("Edit group cancelled")
-            raise turbogears.redirect('/groupshow', cn=kw.get('cn'))
-
-        # Decode the member data, in case we need to round trip
-        member_dicts = loads(b64decode(kw.get('member_data')))
-
-
-        tg_errors, kw = self.groupupdatevalidate(**kw)
-        if tg_errors:
-            return dict(form=group_edit_form, group=kw, members=member_dicts,
-                        tg_template='ipagui.templates.groupedit')
-
-        group_modified = False
-
-        #
-        # Update group itself
-        #
-        try:
-            orig_group_dict = loads(b64decode(kw.get('group_orig')))
-
-            new_group = ipa.group.Group(orig_group_dict)
-            if new_group.description != kw.get('description'):
-                group_modified = True
-                new_group.setValue('description', kw.get('description'))
-            if kw.get('editprotected') == 'true':
-                new_gid = str(kw.get('gidnumber'))
-                if new_group.gidnumber != new_gid:
-                    group_modified = True
-                    new_group.setValue('gidnumber', new_gid)
-
-            if group_modified:
-                rv = client.update_group(new_group)
-                #
-                # If the group update succeeds, but below operations fail, we
-                # need to make sure a subsequent submit doesn't try to update
-                # the group again.
-                #
-                kw['group_orig'] = b64encode(dumps(new_group.toDict()))
-        except ipaerror.IPAError, e:
-            turbogears.flash("Group update failed: " + str(e))
-            return dict(form=group_edit_form, group=kw, members=member_dicts,
-                        tg_template='ipagui.templates.groupedit')
-
-        #
-        # Add members
-        #
-        failed_adds = []
-        try:
-            dnadds = kw.get('dnadd')
-            if dnadds != None:
-                if not(isinstance(dnadds,list) or isinstance(dnadds,tuple)):
-                    dnadds = [dnadds]
-                failed_adds = client.add_members_to_group(
-                        utf8_encode_values(dnadds), new_group.dn)
-                kw['dnadd'] = failed_adds
-        except ipaerror.IPAError, e:
-            turbogears.flash("Group update failed: " + str(e))
-            return dict(form=group_edit_form, group=kw, members=member_dicts,
-                        tg_template='ipagui.templates.groupedit')
-
-        #
-        # Remove members
-        #
-        failed_dels = []
-        try:
-            dndels = kw.get('dndel')
-            if dndels != None:
-                if not(isinstance(dndels,list) or isinstance(dndels,tuple)):
-                    dndels = [dndels]
-                failed_dels = client.remove_members_from_group(
-                        utf8_encode_values(dndels), new_group.dn)
-                kw['dndel'] = failed_dels
-        except ipaerror.IPAError, e:
-            turbogears.flash("Group update failed: " + str(e))
-            return dict(form=group_edit_form, group=kw, members=member_dicts,
-                        tg_template='ipagui.templates.groupedit')
-
-        #
-        # TODO - check failed ops to see if it's because of another update.
-        #        handle "someone else already did it" errors better - perhaps
-        #        not even as an error
-        # TODO - update the Group Members list.
-        #        (note that we have to handle the above todo first, or else
-        #         there will be an error message, but the add/del lists will
-        #         be empty)
-        #
-        if (len(failed_adds) > 0) or (len(failed_dels) > 0):
-            message = "There was an error updating group members.<br />"
-            message += "Failures have been preserved in the add/remove lists."
-            if group_modified:
-                message = "Group Details successfully updated.<br />" + message
-            turbogears.flash(message)
-            return dict(form=group_edit_form, group=kw, members=member_dicts,
-                        tg_template='ipagui.templates.groupedit')
-
-        turbogears.flash("%s updated!" % kw['cn'])
-        raise turbogears.redirect('/groupshow', cn=kw['cn'])
-
-
-    @expose("ipagui.templates.grouplist")
-    @identity.require(identity.not_anonymous())
-    def grouplist(self, **kw):
-        """Search for groups and display results"""
-        client.set_krbccache(os.environ["KRB5CCNAME"])
-        groups = None
-        # counter = 0
-        criteria = kw.get('criteria')
-        if criteria != None and len(criteria) > 0:
-            try:
-                groups = client.find_groups(criteria.encode('utf-8'), None, 0, 2)
-                counter = groups[0]
-                groups = groups[1:]
-                if counter == -1:
-                    turbogears.flash("These results are truncated.<br />" +
-                                    "Please refine your search and try again.")
-            except ipaerror.IPAError, e:
-                turbogears.flash("Find groups failed: " + str(e))
-                raise turbogears.redirect("/grouplist")
-
-        return dict(groups=groups, criteria=criteria, fields=forms.group.GroupFields())
-
-    @expose("ipagui.templates.groupshow")
-    @identity.require(identity.not_anonymous())
-    def groupshow(self, cn):
-        """Retrieve a single group for display"""
-        client.set_krbccache(os.environ["KRB5CCNAME"])
-        try:
-            group = client.get_group_by_cn(cn, group_fields)
-            group_dict = group.toDict()
-
-            #
-            # convert members to users, for display on the page
-            #
-            member_dns = []
-            if group_dict.has_key('uniquemember'):
-                member_dns = group_dict.get('uniquemember')
-            if not(isinstance(member_dns,list) or isinstance(member_dns,tuple)):
-                member_dns = [member_dns]
-
-            # TODO: convert this into an efficient (single) function call
-            # Note: this isn't quite right, since it can be users and groups.
-            members = map(
-                    lambda dn: client.get_user_by_dn(dn, ['dn', 'givenname', 'sn',
-                        'uid', 'cn']),
-                    member_dns)
-            members.sort(sort_group_member)
-            member_dicts = map(lambda member: member.toDict(), members)
-
-            return dict(group=group_dict, fields=forms.group.GroupFields(),
-                    members = member_dicts)
-        except ipaerror.IPAError, e:
-            turbogears.flash("Group show failed: " + str(e))
-            raise turbogears.redirect("/")
-
-    @validate(form=group_new_form)
-    @identity.require(identity.not_anonymous())
-    def groupcreatevalidate(self, tg_errors=None, **kw):
-        return tg_errors, kw
-
-    @validate(form=group_edit_form)
-    @identity.require(identity.not_anonymous())
-    def groupupdatevalidate(self, tg_errors=None, **kw):
-        return tg_errors, kw
+            return Root.group.list(criteria=kw.get('searchvalue'))
 
     @expose("ipagui.templates.loginfailed")
     def loginfailed(self, **kw):
diff -r 157e43b04db3 -r ed3b5011eae2 ipa-server/ipa-gui/ipagui/subcontrollers/__init__.py
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ipa-server/ipa-gui/ipagui/subcontrollers/__init__.py	Thu Oct 04 17:10:18 2007 -0700
@@ -0,0 +1,1 @@
+# __init__.py
diff -r 157e43b04db3 -r ed3b5011eae2 ipa-server/ipa-gui/ipagui/subcontrollers/group.py
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ipa-server/ipa-gui/ipagui/subcontrollers/group.py	Thu Oct 04 17:10:18 2007 -0700
@@ -0,0 +1,386 @@
+import os
+from pickle import dumps, loads
+from base64 import b64encode, b64decode
+
+import cherrypy
+import turbogears
+from turbogears import controllers, expose, flash
+from turbogears import validators, validate
+from turbogears import widgets, paginate
+from turbogears import error_handler
+from turbogears import identity
+
+from ipacontroller import IPAController
+import ipa.config
+import ipa.ipaclient
+import ipa.group
+from ipa.entity import utf8_encode_values
+from ipa import ipaerror
+import ipagui.forms.group
+
+ipa.config.init_config()
+client = ipa.ipaclient.IPAClient(True)
+
+group_new_form = ipagui.forms.group.GroupNewForm()
+group_edit_form = ipagui.forms.group.GroupEditForm()
+
+group_fields = ['*']
+
+class GroupController(IPAController):
+
+
+    #########
+    # Group #
+    #########
+
+    @expose("ipagui.templates.groupindex")
+    @identity.require(identity.not_anonymous())
+    def index(self, tg_errors=None):
+        client.set_krbccache(os.environ["KRB5CCNAME"])
+        return dict()
+
+    @expose("ipagui.templates.groupnew")
+    @identity.require(identity.not_anonymous())
+    def new(self, tg_errors=None):
+        """Displays the new group form"""
+        if tg_errors:
+            turbogears.flash("There was a problem with the form!")
+
+        client.set_krbccache(os.environ["KRB5CCNAME"])
+
+        return dict(form=group_new_form, group={})
+
+    @expose()
+    @identity.require(identity.not_anonymous())
+    def create(self, **kw):
+        """Creates a new group"""
+        self.restrict_post()
+        client.set_krbccache(os.environ["KRB5CCNAME"])
+
+        if kw.get('submit') == 'Cancel':
+            turbogears.flash("Add group cancelled")
+            raise turbogears.redirect('/')
+
+        tg_errors, kw = self.groupcreatevalidate(**kw)
+        if tg_errors:
+            return dict(form=group_new_form, group=kw,
+                    tg_template='ipagui.templates.groupnew')
+
+        #
+        # Create the group itself
+        #
+        try:
+            new_group = ipa.group.Group()
+            new_group.setValue('cn', kw.get('cn'))
+            new_group.setValue('description', kw.get('description'))
+
+            rv = client.add_group(new_group)
+        except ipaerror.exception_for(ipaerror.LDAP_DUPLICATE):
+            turbogears.flash("Group with name '%s' already exists" %
+                    kw.get('cn'))
+            return dict(form=group_new_form, group=kw,
+                    tg_template='ipagui.templates.groupnew')
+        except ipaerror.IPAError, e:
+            turbogears.flash("Group add failed: " + str(e) + "<br/>" + str(e.detail))
+            return dict(form=group_new_form, group=kw,
+                    tg_template='ipagui.templates.groupnew')
+
+        #
+        # NOTE: from here on, the group now exists.
+        #       on any error, we redirect to the _edit_ group page.
+        #       this code does data setup, similar to groupedit()
+        #
+        group = client.get_group_by_cn(kw['cn'], group_fields)
+        group_dict = group.toDict()
+        member_dicts = []
+
+        # store a copy of the original group for the update later
+        group_data = b64encode(dumps(group_dict))
+        member_data = b64encode(dumps(member_dicts))
+        group_dict['group_orig'] = group_data
+        group_dict['member_data'] = member_data
+
+        # preserve group add info in case of errors
+        group_dict['dnadd'] = kw.get('dnadd')
+        group_dict['dn_to_info_json'] = kw.get('dn_to_info_json')
+
+        #
+        # Add members
+        #
+        failed_adds = []
+        try:
+            dnadds = kw.get('dnadd')
+            if dnadds != None:
+                if not(isinstance(dnadds,list) or isinstance(dnadds,tuple)):
+                    dnadds = [dnadds]
+                failed_adds = client.add_members_to_group(
+                        utf8_encode_values(dnadds), group.dn)
+                kw['dnadd'] = failed_adds
+        except ipaerror.IPAError, e:
+            failed_adds = dnadds
+
+        if len(failed_adds) > 0:
+            message = "Group successfully created.<br />"
+            message += "There was an error adding group members.<br />"
+            message += "Failures have been preserved in the add/remove lists."
+            turbogears.flash(message)
+            return dict(form=group_edit_form, group=group_dict,
+                        members=member_dicts,
+                        tg_template='ipagui.templates.groupedit')
+
+        turbogears.flash("%s added!" % kw.get('cn'))
+        raise turbogears.redirect('/group/show', cn=kw.get('cn'))
+
+    @expose("ipagui.templates.dynamiceditsearch")
+    @identity.require(identity.not_anonymous())
+    def edit_search(self, **kw):
+        """Searches for users+groups and displays list of results in a table.
+           This method is used for the ajax search on the group edit page."""
+        client.set_krbccache(os.environ["KRB5CCNAME"])
+        users = []
+        groups = []
+        counter = 0
+        searchlimit = 100
+        criteria = kw.get('criteria')
+        if criteria != None and len(criteria) > 0:
+            try:
+                users = client.find_users(criteria.encode('utf-8'), None, searchlimit)
+                users_counter = users[0]
+                users = users[1:]
+
+                groups = client.find_groups(criteria.encode('utf-8'), None,
+                        searchlimit)
+                groups_counter = groups[0]
+                groups = groups[1:]
+
+                if users_counter < 0 or groups_counter < 0:
+                    counter = -1
+                else:
+                    counter = users_counter + groups_counter
+            except ipaerror.IPAError, e:
+                turbogears.flash("search failed: " + str(e))
+
+        return dict(users=users, groups=groups, criteria=criteria,
+                counter=counter)
+
+
+    @expose("ipagui.templates.groupedit")
+    @identity.require(identity.not_anonymous())
+    def edit(self, cn, tg_errors=None):
+        """Displays the edit group form"""
+        if tg_errors:
+            turbogears.flash("There was a problem with the form!")
+
+        client.set_krbccache(os.environ["KRB5CCNAME"])
+        try:
+            group = client.get_group_by_cn(cn, group_fields)
+
+            group_dict = group.toDict()
+
+            #
+            # convert members to users, for easier manipulation on the page
+            #
+            member_dns = []
+            if group_dict.has_key('uniquemember'):
+                member_dns = group_dict.get('uniquemember')
+                # remove from dict - it's not needed for update
+                # and we are storing the members in a different form
+                del group_dict['uniquemember']
+            if not(isinstance(member_dns,list) or isinstance(member_dns,tuple)):
+                member_dns = [member_dns]
+
+            # TODO: convert this into an efficient (single) function call
+            # Note: this isn't quite right, since it can be users and groups.
+            members = map(
+                    lambda dn: client.get_user_by_dn(dn, ['dn', 'givenname', 'sn',
+                        'uid', 'cn']),
+                    member_dns)
+            members.sort(self.sort_group_member)
+
+            # Map users into an array of dicts, which can be serialized
+            # (so we don't have to do this on each round trip)
+            member_dicts = map(lambda member: member.toDict(), members)
+
+            # store a copy of the original group for the update later
+            group_data = b64encode(dumps(group_dict))
+            member_data = b64encode(dumps(member_dicts))
+            group_dict['group_orig'] = group_data
+            group_dict['member_data'] = member_data
+
+            return dict(form=group_edit_form, group=group_dict, members=member_dicts)
+        except ipaerror.IPAError, e:
+            turbogears.flash("Group edit failed: " + str(e))
+            raise turbogears.redirect('/group/show', uid=cn)
+
+    @expose()
+    @identity.require(identity.not_anonymous())
+    def update(self, **kw):
+        """Updates an existing group"""
+        self.restrict_post()
+        client.set_krbccache(os.environ["KRB5CCNAME"])
+        if kw.get('submit') == 'Cancel Edit':
+            turbogears.flash("Edit group cancelled")
+            raise turbogears.redirect('/group/show', cn=kw.get('cn'))
+
+        # Decode the member data, in case we need to round trip
+        member_dicts = loads(b64decode(kw.get('member_data')))
+
+
+        tg_errors, kw = self.groupupdatevalidate(**kw)
+        if tg_errors:
+            return dict(form=group_edit_form, group=kw, members=member_dicts,
+                        tg_template='ipagui.templates.groupedit')
+
+        group_modified = False
+
+        #
+        # Update group itself
+        #
+        try:
+            orig_group_dict = loads(b64decode(kw.get('group_orig')))
+
+            new_group = ipa.group.Group(orig_group_dict)
+            if new_group.description != kw.get('description'):
+                group_modified = True
+                new_group.setValue('description', kw.get('description'))
+            if kw.get('editprotected') == 'true':
+                new_gid = str(kw.get('gidnumber'))
+                if new_group.gidnumber != new_gid:
+                    group_modified = True
+                    new_group.setValue('gidnumber', new_gid)
+
+            if group_modified:
+                rv = client.update_group(new_group)
+                #
+                # If the group update succeeds, but below operations fail, we
+                # need to make sure a subsequent submit doesn't try to update
+                # the group again.
+                #
+                kw['group_orig'] = b64encode(dumps(new_group.toDict()))
+        except ipaerror.IPAError, e:
+            turbogears.flash("Group update failed: " + str(e))
+            return dict(form=group_edit_form, group=kw, members=member_dicts,
+                        tg_template='ipagui.templates.groupedit')
+
+        #
+        # Add members
+        #
+        failed_adds = []
+        try:
+            dnadds = kw.get('dnadd')
+            if dnadds != None:
+                if not(isinstance(dnadds,list) or isinstance(dnadds,tuple)):
+                    dnadds = [dnadds]
+                failed_adds = client.add_members_to_group(
+                        utf8_encode_values(dnadds), new_group.dn)
+                kw['dnadd'] = failed_adds
+        except ipaerror.IPAError, e:
+            turbogears.flash("Group update failed: " + str(e))
+            return dict(form=group_edit_form, group=kw, members=member_dicts,
+                        tg_template='ipagui.templates.groupedit')
+
+        #
+        # Remove members
+        #
+        failed_dels = []
+        try:
+            dndels = kw.get('dndel')
+            if dndels != None:
+                if not(isinstance(dndels,list) or isinstance(dndels,tuple)):
+                    dndels = [dndels]
+                failed_dels = client.remove_members_from_group(
+                        utf8_encode_values(dndels), new_group.dn)
+                kw['dndel'] = failed_dels
+        except ipaerror.IPAError, e:
+            turbogears.flash("Group update failed: " + str(e))
+            return dict(form=group_edit_form, group=kw, members=member_dicts,
+                        tg_template='ipagui.templates.groupedit')
+
+        #
+        # TODO - check failed ops to see if it's because of another update.
+        #        handle "someone else already did it" errors better - perhaps
+        #        not even as an error
+        # TODO - update the Group Members list.
+        #        (note that we have to handle the above todo first, or else
+        #         there will be an error message, but the add/del lists will
+        #         be empty)
+        #
+        if (len(failed_adds) > 0) or (len(failed_dels) > 0):
+            message = "There was an error updating group members.<br />"
+            message += "Failures have been preserved in the add/remove lists."
+            if group_modified:
+                message = "Group Details successfully updated.<br />" + message
+            turbogears.flash(message)
+            return dict(form=group_edit_form, group=kw, members=member_dicts,
+                        tg_template='ipagui.templates.groupedit')
+
+        turbogears.flash("%s updated!" % kw['cn'])
+        raise turbogears.redirect('/group/show', cn=kw['cn'])
+
+
+    @expose("ipagui.templates.grouplist")
+    @identity.require(identity.not_anonymous())
+    def list(self, **kw):
+        """Search for groups and display results"""
+        client.set_krbccache(os.environ["KRB5CCNAME"])
+        groups = None
+        # counter = 0
+        criteria = kw.get('criteria')
+        if criteria != None and len(criteria) > 0:
+            try:
+                groups = client.find_groups(criteria.encode('utf-8'), None, 0, 2)
+                counter = groups[0]
+                groups = groups[1:]
+                if counter == -1:
+                    turbogears.flash("These results are truncated.<br />" +
+                                    "Please refine your search and try again.")
+            except ipaerror.IPAError, e:
+                turbogears.flash("Find groups failed: " + str(e))
+                raise turbogears.redirect("/group/list")
+
+        return dict(groups=groups, criteria=criteria,
+                    fields=ipagui.forms.group.GroupFields())
+
+    @expose("ipagui.templates.groupshow")
+    @identity.require(identity.not_anonymous())
+    def show(self, cn):
+        """Retrieve a single group for display"""
+        client.set_krbccache(os.environ["KRB5CCNAME"])
+        try:
+            group = client.get_group_by_cn(cn, group_fields)
+            group_dict = group.toDict()
+
+            #
+            # convert members to users, for display on the page
+            #
+            member_dns = []
+            if group_dict.has_key('uniquemember'):
+                member_dns = group_dict.get('uniquemember')
+            if not(isinstance(member_dns,list) or isinstance(member_dns,tuple)):
+                member_dns = [member_dns]
+
+            # TODO: convert this into an efficient (single) function call
+            # Note: this isn't quite right, since it can be users and groups.
+            members = map(
+                    lambda dn: client.get_user_by_dn(dn, ['dn', 'givenname', 'sn',
+                        'uid', 'cn']),
+                    member_dns)
+            members.sort(self.sort_group_member)
+            member_dicts = map(lambda member: member.toDict(), members)
+
+            return dict(group=group_dict, fields=ipagui.forms.group.GroupFields(),
+                    members = member_dicts)
+        except ipaerror.IPAError, e:
+            turbogears.flash("Group show failed: " + str(e))
+            raise turbogears.redirect("/")
+
+    @validate(form=group_new_form)
+    @identity.require(identity.not_anonymous())
+    def groupcreatevalidate(self, tg_errors=None, **kw):
+        return tg_errors, kw
+
+    @validate(form=group_edit_form)
+    @identity.require(identity.not_anonymous())
+    def groupupdatevalidate(self, tg_errors=None, **kw):
+        return tg_errors, kw
+
diff -r 157e43b04db3 -r ed3b5011eae2 ipa-server/ipa-gui/ipagui/subcontrollers/ipacontroller.py
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ipa-server/ipa-gui/ipagui/subcontrollers/ipacontroller.py	Thu Oct 04 17:10:18 2007 -0700
@@ -0,0 +1,58 @@
+import cherrypy
+import turbogears
+from turbogears import controllers, expose, flash
+from turbogears import validators, validate
+from turbogears import widgets, paginate
+from turbogears import error_handler
+from turbogears import identity
+
+class IPAController(controllers.Controller):
+    def restrict_post(self):
+        if cherrypy.request.method != "POST":
+            turbogears.flash("This method only accepts posts")
+            raise turbogears.redirect("/")
+
+    def utf8_encode(self, value):
+        if value != None:
+            value = value.encode('utf-8')
+        return value
+
+    def sort_group_member(self, a, b):
+        """Comparator function used for sorting group members."""
+        if a.getValue('uid') and b.getValue('uid'):
+            if a.getValue('givenname') == b.getValue('givenname'):
+                if a.getValue('sn') == b.getValue('sn'):
+                    if a.getValue('uid') == b.getValue('uid'):
+                        return 0
+                    elif a.getValue('uid') < b.getValue('uid'):
+                        return -1
+                    else:
+                        return 1
+                elif a.getValue('sn') < b.getValue('sn'):
+                    return -1
+                else:
+                    return 1
+            elif a.getValue('givenname') < b.getValue('givenname'):
+                return -1
+            else:
+                return 1
+        elif a.getValue('uid'):
+            return -1
+        elif b.getValue('uid'):
+            return 1
+        else:
+            if a.getValue('cn') == b.getValue('cn'):
+                return 0
+            elif a.getValue('cn') < b.getValue('cn'):
+                return -1
+            else:
+                return 1
+
+    def sort_by_cn(self, a, b):
+        """Comparator function used for sorting groups."""
+        if a.getValue('cn') == b.getValue('cn'):
+            return 0
+        elif a.getValue('cn') < b.getValue('cn'):
+            return -1
+        else:
+            return 1
diff -r 157e43b04db3 -r ed3b5011eae2 ipa-server/ipa-gui/ipagui/subcontrollers/user.py
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ipa-server/ipa-gui/ipagui/subcontrollers/user.py	Thu Oct 04 17:10:18 2007 -0700
@@ -0,0 +1,537 @@
+import os
+import re
+import random
+from pickle import dumps, loads
+from base64 import b64encode, b64decode
+
+import cherrypy
+import turbogears
+from turbogears import controllers, expose, flash
+from turbogears import validators, validate
+from turbogears import widgets, paginate
+from turbogears import error_handler
+from turbogears import identity
+
+from ipacontroller import IPAController
+import ipa.config
+import ipa.ipaclient
+import ipa.user
+from ipa.entity import utf8_encode_values
+from ipa import ipaerror
+import ipagui.forms.user
+
+ipa.config.init_config()
+client = ipa.ipaclient.IPAClient(True)
+
+password_chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
+
+user_new_form = ipagui.forms.user.UserNewForm()
+user_edit_form = ipagui.forms.user.UserEditForm()
+
+user_fields = ['*', 'nsAccountLock']
+
+class UserController(IPAController):
+
+    @expose()
+    def index(self):
+        raise turbogears.redirect("/user/list")
+
+    @expose("ipagui.templates.usernew")
+    @identity.require(identity.not_anonymous())
+    def new(self, tg_errors=None):
+        """Displays the new user form"""
+        if tg_errors:
+            turbogears.flash("There was a problem with the form!")
+
+        return dict(form=user_new_form, user={})
+
+    @expose()
+    @identity.require(identity.not_anonymous())
+    def create(self, **kw):
+        """Creates a new user"""
+        self.restrict_post()
+        client.set_krbccache(os.environ["KRB5CCNAME"])
+        if kw.get('submit') == 'Cancel':
+            turbogears.flash("Add user cancelled")
+            raise turbogears.redirect('/user/list')
+
+        tg_errors, kw = self.usercreatevalidate(**kw)
+        if tg_errors:
+            return dict(form=user_new_form, user=kw,
+                    tg_template='ipagui.templates.usernew')
+
+        #
+        # Create the user itself
+        #
+        try:
+            new_user = ipa.user.User()
+            new_user.setValue('title', kw.get('title'))
+            new_user.setValue('givenname', kw.get('givenname'))
+            new_user.setValue('sn', kw.get('sn'))
+            new_user.setValue('cn', kw.get('cn'))
+            new_user.setValue('displayname', kw.get('displayname'))
+            new_user.setValue('initials', kw.get('initials'))
+
+            new_user.setValue('uid', kw.get('uid'))
+            new_user.setValue('loginshell', kw.get('loginshell'))
+            new_user.setValue('gecos', kw.get('gecos'))
+
+            new_user.setValue('mail', kw.get('mail'))
+            new_user.setValue('telephonenumber', kw.get('telephonenumber'))
+            new_user.setValue('facsimiletelephonenumber',
+                    kw.get('facsimiletelephonenumber'))
+            new_user.setValue('mobile', kw.get('mobile'))
+            new_user.setValue('pager', kw.get('pager'))
+            new_user.setValue('homephone', kw.get('homephone'))
+
+            new_user.setValue('street', kw.get('street'))
+            new_user.setValue('l', kw.get('l'))
+            new_user.setValue('st', kw.get('st'))
+            new_user.setValue('postalcode', kw.get('postalcode'))
+
+            new_user.setValue('ou', kw.get('ou'))
+            new_user.setValue('businesscategory', kw.get('businesscategory'))
+            new_user.setValue('description', kw.get('description'))
+            new_user.setValue('employeetype', kw.get('employeetype'))
+            # new_user.setValue('manager', kw.get('manager'))
+            new_user.setValue('roomnumber', kw.get('roomnumber'))
+            # new_user.setValue('secretary', kw.get('secretary'))
+
+            new_user.setValue('carlicense', kw.get('carlicense'))
+            new_user.setValue('labeleduri', kw.get('labeleduri'))
+
+            if kw.get('nsAccountLock'):
+                new_user.setValue('nsAccountLock', 'true')
+
+            rv = client.add_user(new_user)
+        except ipaerror.exception_for(ipaerror.LDAP_DUPLICATE):
+            turbogears.flash("Person with login '%s' already exists" %
+                    kw.get('uid'))
+            return dict(form=user_new_form, user=kw,
+                    tg_template='ipagui.templates.usernew')
+        except ipaerror.IPAError, e:
+            turbogears.flash("User add failed: " + str(e))
+            return dict(form=user_new_form, user=kw,
+                    tg_template='ipagui.templates.usernew')
+
+        #
+        # NOTE: from here on, the user account now exists.
+        #       on any error, we redirect to the _edit_ user page.
+        #       this code does data setup, similar to useredit()
+        #
+        user = client.get_user_by_uid(kw['uid'], user_fields)
+        user_dict = user.toDict()
+
+        user_groups_dicts = []
+        user_groups_data = b64encode(dumps(user_groups_dicts))
+
+        # store a copy of the original user for the update later
+        user_data = b64encode(dumps(user_dict))
+        user_dict['user_orig'] = user_data
+        user_dict['user_groups_data'] = user_groups_data
+
+        # preserve group add info in case of errors
+        user_dict['dnadd'] = kw.get('dnadd')
+        user_dict['dn_to_info_json'] = kw.get('dn_to_info_json')
+
+        #
+        # Password change
+        # TODO
+        #
+
+        #
+        # Add groups
+        #
+        failed_adds = []
+        try:
+            dnadds = kw.get('dnadd')
+            if dnadds != None:
+                if not(isinstance(dnadds,list) or isinstance(dnadds,tuple)):
+                    dnadds = [dnadds]
+                failed_adds = client.add_groups_to_user(
+                        utf8_encode_values(dnadds), user.dn)
+                kw['dnadd'] = failed_adds
+        except ipaerror.IPAError, e:
+            failed_adds = dnadds
+
+        if len(failed_adds) > 0:
+            message = "Person successfully created.<br />"
+            message += "There was an error adding groups.<br />"
+            message += "Failures have been preserved in the add/remove lists."
+            turbogears.flash(message)
+            return dict(form=user_edit_form, user=user_dict,
+                        user_groups=user_groups_dicts,
+                        tg_template='ipagui.templates.useredit')
+
+        turbogears.flash("%s added!" % kw['uid'])
+        raise turbogears.redirect('/user/show', uid=kw['uid'])
+
+    @expose("ipagui.templates.dynamiceditsearch")
+    @identity.require(identity.not_anonymous())
+    def edit_search(self, **kw):
+        """Searches for groups and displays list of results in a table.
+           This method is used for the ajax search on the user edit page."""
+        client.set_krbccache(os.environ["KRB5CCNAME"])
+        groups = []
+        groups_counter = 0
+        searchlimit = 100
+        criteria = kw.get('criteria')
+        if criteria != None and len(criteria) > 0:
+            try:
+                groups = client.find_groups(criteria.encode('utf-8'), None,
+                        searchlimit)
+                groups_counter = groups[0]
+                groups = groups[1:]
+            except ipaerror.IPAError, e:
+                turbogears.flash("search failed: " + str(e))
+
+        return dict(users=None, groups=groups, criteria=criteria,
+                counter=groups_counter)
+
+
+    @expose("ipagui.templates.useredit")
+    @identity.require(identity.not_anonymous())
+    def edit(self, uid, tg_errors=None):
+        """Displays the edit user form"""
+        if tg_errors:
+            turbogears.flash("There was a problem with the form!")
+
+        client.set_krbccache(os.environ["KRB5CCNAME"])
+        try:
+            user = client.get_user_by_uid(uid, user_fields)
+            user_dict = user.toDict()
+            # Edit shouldn't fill in the password field.
+            if user_dict.has_key('userpassword'):
+                del(user_dict['userpassword'])
+
+            user_groups = client.get_groups_by_member(user.dn, ['dn', 'cn'])
+            user_groups.sort(self.sort_by_cn)
+            user_groups_dicts = map(lambda group: group.toDict(), user_groups)
+            user_groups_data = b64encode(dumps(user_groups_dicts))
+
+            # store a copy of the original user for the update later
+            user_data = b64encode(dumps(user_dict))
+            user_dict['user_orig'] = user_data
+            user_dict['user_groups_data'] = user_groups_data
+
+            return dict(form=user_edit_form, user=user_dict,
+                    user_groups=user_groups_dicts)
+        except ipaerror.IPAError, e:
+            turbogears.flash("User edit failed: " + str(e))
+            raise turbogears.redirect('/user/show', uid=kw.get('uid'))
+
+    @expose()
+    @identity.require(identity.not_anonymous())
+    def update(self, **kw):
+        """Updates an existing user"""
+        self.restrict_post()
+        client.set_krbccache(os.environ["KRB5CCNAME"])
+        if kw.get('submit') == 'Cancel Edit':
+            turbogears.flash("Edit user cancelled")
+            raise turbogears.redirect('/user/show', uid=kw.get('uid'))
+
+        # Decode the group data, in case we need to round trip
+        user_groups_dicts = loads(b64decode(kw.get('user_groups_data')))
+
+        tg_errors, kw = self.userupdatevalidate(**kw)
+        if tg_errors:
+            return dict(form=user_edit_form, user=kw,
+                        user_groups=user_groups_dicts,
+                        tg_template='ipagui.templates.useredit')
+
+        password_change = False
+        user_modified = False
+
+        #
+        # Update the user itself
+        #
+        try:
+            orig_user_dict = loads(b64decode(kw.get('user_orig')))
+
+            new_user = ipa.user.User(orig_user_dict)
+            new_user.setValue('title', kw.get('title'))
+            new_user.setValue('givenname', kw.get('givenname'))
+            new_user.setValue('sn', kw.get('sn'))
+            new_user.setValue('cn', kw.get('cn'))
+            new_user.setValue('displayname', kw.get('displayname'))
+            new_user.setValue('initials', kw.get('initials'))
+
+            new_user.setValue('loginshell', kw.get('loginshell'))
+            new_user.setValue('gecos', kw.get('gecos'))
+
+            new_user.setValue('mail', kw.get('mail'))
+            new_user.setValue('telephonenumber', kw.get('telephonenumber'))
+            new_user.setValue('facsimiletelephonenumber',
+                    kw.get('facsimiletelephonenumber'))
+            new_user.setValue('mobile', kw.get('mobile'))
+            new_user.setValue('pager', kw.get('pager'))
+            new_user.setValue('homephone', kw.get('homephone'))
+
+            new_user.setValue('street', kw.get('street'))
+            new_user.setValue('l', kw.get('l'))
+            new_user.setValue('st', kw.get('st'))
+            new_user.setValue('postalcode', kw.get('postalcode'))
+
+            new_user.setValue('ou', kw.get('ou'))
+            new_user.setValue('businesscategory', kw.get('businesscategory'))
+            new_user.setValue('description', kw.get('description'))
+            new_user.setValue('employeetype', kw.get('employeetype'))
+            # new_user.setValue('manager', kw.get('manager'))
+            new_user.setValue('roomnumber', kw.get('roomnumber'))
+            # new_user.setValue('secretary', kw.get('secretary'))
+
+            new_user.setValue('carlicense', kw.get('carlicense'))
+            new_user.setValue('labeleduri', kw.get('labeleduri'))
+
+
+            if kw.get('nsAccountLock'):
+                new_user.setValue('nsAccountLock', 'true')
+            else:
+                new_user.setValue('nsAccountLock', None)
+            if kw.get('editprotected') == 'true':
+                if kw.get('userpassword'):
+                    password_change = True
+                new_user.setValue('uidnumber', str(kw.get('uidnumber')))
+                new_user.setValue('gidnumber', str(kw.get('gidnumber')))
+                new_user.setValue('homedirectory', str(kw.get('homedirectory')))
+
+            rv = client.update_user(new_user)
+            #
+            # If the user update succeeds, but below operations fail, we
+            # need to make sure a subsequent submit doesn't try to update
+            # the user again.
+            #
+            user_modified = True
+            kw['user_orig'] = b64encode(dumps(new_user.toDict()))
+        except ipaerror.exception_for(ipaerror.LDAP_EMPTY_MODLIST), e:
+            # could be a password change
+            # could be groups change
+            # too much work to figure out unless someone really screams
+            pass
+        except ipaerror.IPAError, e:
+            turbogears.flash("User update failed: " + str(e))
+            return dict(form=user_edit_form, user=kw,
+                        user_groups=user_groups_dicts,
+                        tg_template='ipagui.templates.useredit')
+
+        #
+        # Password change
+        #
+        try:
+            if password_change:
+                rv = client.modifyPassword(kw['krbprincipalname'], "", kw.get('userpassword'))
+        except ipaerror.IPAError, e:
+            turbogears.flash("User password change failed: " + str(e))
+            return dict(form=user_edit_form, user=kw,
+                        user_groups=user_groups_dicts,
+                        tg_template='ipagui.templates.useredit')
+
+        #
+        # Add groups
+        #
+        failed_adds = []
+        try:
+            dnadds = kw.get('dnadd')
+            if dnadds != None:
+                if not(isinstance(dnadds,list) or isinstance(dnadds,tuple)):
+                    dnadds = [dnadds]
+                failed_adds = client.add_groups_to_user(
+                        utf8_encode_values(dnadds), new_user.dn)
+                kw['dnadd'] = failed_adds
+        except ipaerror.IPAError, e:
+            failed_adds = dnadds
+
+        #
+        # Remove groups
+        #
+        failed_dels = []
+        try:
+            dndels = kw.get('dndel')
+            if dndels != None:
+                if not(isinstance(dndels,list) or isinstance(dndels,tuple)):
+                    dndels = [dndels]
+                failed_dels = client.remove_groups_from_user(
+                        utf8_encode_values(dndels), new_user.dn)
+                kw['dndel'] = failed_dels
+        except ipaerror.IPAError, e:
+            failed_dels = dndels
+
+        if (len(failed_adds) > 0) or (len(failed_dels) > 0):
+            message = "There was an error updating groups.<br />"
+            message += "Failures have been preserved in the add/remove lists."
+            if user_modified:
+                message = "User Details successfully updated.<br />" + message
+            if password_change:
+                message = "User password successfully updated.<br />" + message
+            turbogears.flash(message)
+            return dict(form=user_edit_form, user=kw,
+                        user_groups=user_groups_dicts,
+                        tg_template='ipagui.templates.useredit')
+
+        turbogears.flash("%s updated!" % kw['uid'])
+        raise turbogears.redirect('/user/show', uid=kw['uid'])
+
+
+    @expose("ipagui.templates.userlist")
+    @identity.require(identity.not_anonymous())
+    def list(self, **kw):
+        """Searches for users and displays list of results"""
+        client.set_krbccache(os.environ["KRB5CCNAME"])
+        users = None
+        counter = 0
+        uid = kw.get('uid')
+        if uid != None and len(uid) > 0:
+            try:
+                users = client.find_users(uid.encode('utf-8'), None, 0, 2)
+                counter = users[0]
+                users = users[1:]
+                if counter == -1:
+                    turbogears.flash("These results are truncated.<br />" +
+                                    "Please refine your search and try again.")
+            except ipaerror.IPAError, e:
+                turbogears.flash("User list failed: " + str(e))
+                raise turbogears.redirect("/user/list")
+
+        return dict(users=users, uid=uid, fields=ipagui.forms.user.UserFields())
+
+
+    @expose("ipagui.templates.usershow")
+    @identity.require(identity.not_anonymous())
+    def show(self, uid):
+        """Retrieve a single user for display"""
+        client.set_krbccache(os.environ["KRB5CCNAME"])
+        try:
+            user = client.get_user_by_uid(uid, user_fields)
+            user_groups = client.get_groups_by_member(user.dn, ['cn'])
+            user_groups.sort(self.sort_by_cn)
+            user_reports = client.get_users_by_manager(user.dn,
+                    ['givenname', 'sn', 'uid'])
+            user_reports.sort(self.sort_group_member)
+
+            user_manager = None
+            try:
+                if user.manager:
+                    user_manager = client.get_user_by_dn(user.manager,
+                        ['givenname', 'sn', 'uid'])
+            except ipaerror.exception_for(ipaerror.LDAP_NOT_FOUND):
+                pass
+
+            return dict(user=user.toDict(), fields=ipagui.forms.user.UserFields(),
+                        user_groups=user_groups, user_reports=user_reports,
+                        user_manager=user_manager)
+        except ipaerror.IPAError, e:
+            turbogears.flash("User show failed: " + str(e))
+            raise turbogears.redirect("/")
+
+    @validate(form=user_new_form)
+    @identity.require(identity.not_anonymous())
+    def usercreatevalidate(self, tg_errors=None, **kw):
+        return tg_errors, kw
+
+    @validate(form=user_edit_form)
+    @identity.require(identity.not_anonymous())
+    def userupdatevalidate(self, tg_errors=None, **kw):
+        return tg_errors, kw
+
+    # @expose()
+    def generate_password(self):
+        password = ""
+        generator = random.SystemRandom()
+        for char in range(8):
+            index = generator.randint(0, len(password_chars) - 1)
+            password += password_chars[index]
+
+        return password
+
+    @expose()
+    @identity.require(identity.not_anonymous())
+    def suggest_uid(self, givenname, sn):
+        # filter illegal uid characters out
+        givenname = re.sub(r'[^a-zA-Z_\-0-9]', "", givenname)
+        sn = re.sub(r'[^a-zA-Z_\-0-9]', "", sn)
+
+        if (len(givenname) == 0) or (len(sn) == 0):
+            return ""
+
+        client.set_krbccache(os.environ["KRB5CCNAME"])
+        givenname = givenname.lower()
+        sn = sn.lower()
+
+        uid = givenname[0] + sn[:7]
+        try:
+            client.get_user_by_uid(uid)
+        except ipaerror.exception_for(ipaerror.LDAP_NOT_FOUND):
+            return uid
+
+        uid = givenname[:7] + sn[0]
+        try:
+            client.get_user_by_uid(uid)
+        except ipaerror.exception_for(ipaerror.LDAP_NOT_FOUND):
+            return uid
+
+        uid = (givenname + sn)[:8]
+        try:
+            client.get_user_by_uid(uid)
+        except ipaerror.exception_for(ipaerror.LDAP_NOT_FOUND):
+            return uid
+
+        uid = sn[:8]
+        try:
+            client.get_user_by_uid(uid)
+        except ipaerror.exception_for(ipaerror.LDAP_NOT_FOUND):
+            return uid
+
+        suffix = 2
+        template = givenname[0] + sn[:7]
+        while suffix < 20:
+            uid = template[:8 - len(str(suffix))] + str(suffix)
+            try:
+                client.get_user_by_uid(uid)
+            except ipaerror.exception_for(ipaerror.LDAP_NOT_FOUND):
+                return uid
+            suffix += 1
+
+        return ""
+
+    @expose()
+    @identity.require(identity.not_anonymous())
+    def suggest_email(self, givenname, sn):
+        # remove illegal email characters
+        givenname = re.sub(r'[^a-zA-Z0-9!#\$%\*/?\|\^\{\}`~&\'\+\-=_]', "", givenname)
+        sn = re.sub(r'[^a-zA-Z0-9!#\$%\*/?\|\^\{\}`~&\'\+\-=_]', "", sn)
+
+        if (len(givenname) == 0) or (len(sn) == 0):
+            return ""
+
+        client.set_krbccache(os.environ["KRB5CCNAME"])
+        givenname = givenname.lower()
+        sn = sn.lower()
+
+        # TODO - get from config
+        domain = "freeipa.org"
+
+        return "%s.%s@%s" % (givenname, sn, domain)
+
+
+        # TODO - mail is currently not indexed nor searchable.
+        #        implement when it's done
+        # email = givenname + "." + sn + domain
+        # users = client.find_users(email, ['mail'])
+        # if len(filter(lambda u: u['mail'] == email, users[1:])) == 0:
+        #     return email
+
+        # email = self.suggest_uid(givenname, sn) + domain
+        # users = client.find_users(email, ['mail'])
+        # if len(filter(lambda u: u['mail'] == email, users[1:])) == 0:
+        #     return email
+
+        # suffix = 2
+        # template = givenname + "." + sn
+        # while suffix < 20:
+        #     email = template + str(suffix) + domain
+        #     users = client.find_users(email, ['mail'])
+        #     if len(filter(lambda u: u['mail'] == email, users[1:])) == 0:
+        #         return email
+        #     suffix += 1
+
+        # return ""
diff -r 157e43b04db3 -r ed3b5011eae2 ipa-server/ipa-gui/ipagui/templates/groupedit.kid
--- a/ipa-server/ipa-gui/ipagui/templates/groupedit.kid	Thu Oct 04 14:34:49 2007 -0700
+++ b/ipa-server/ipa-gui/ipagui/templates/groupedit.kid	Thu Oct 04 17:10:18 2007 -0700
@@ -16,6 +16,6 @@
     <h2>Edit Group</h2>
   </div>
 
-  ${form.display(action="groupupdate", value=group, members=members)}
+  ${form.display(action=tg.url('/group/update'), value=group, members=members)}
 </body>
 </html>
diff -r 157e43b04db3 -r ed3b5011eae2 ipa-server/ipa-gui/ipagui/templates/groupeditform.kid
--- a/ipa-server/ipa-gui/ipagui/templates/groupeditform.kid	Thu Oct 04 14:34:49 2007 -0700
+++ b/ipa-server/ipa-gui/ipagui/templates/groupeditform.kid	Thu Oct 04 17:10:18 2007 -0700
@@ -23,7 +23,7 @@ from ipagui.helpers import ipahelper
   <script type="text/javascript" charset="utf-8"
     src="${tg.url('/static/javascript/dynamicedit.js')}"></script>
 
-  <?python searchurl = tg.url('/groupedit_search') ?>
+  <?python searchurl = tg.url('/group/edit_search') ?>
 
   <script type="text/javascript">
     function toggleProtectedFields(checkbox) {
diff -r 157e43b04db3 -r ed3b5011eae2 ipa-server/ipa-gui/ipagui/templates/grouplayout.kid
--- a/ipa-server/ipa-gui/ipagui/templates/grouplayout.kid	Thu Oct 04 14:34:49 2007 -0700
+++ b/ipa-server/ipa-gui/ipagui/templates/grouplayout.kid	Thu Oct 04 17:10:18 2007 -0700
@@ -14,9 +14,9 @@
 
 <!--      <div id="sidebar">
           <h2>Tools</h2>
-          <a href="${tg.url('/groupindex')}">Add Group</a><br/>
-          <a href="${tg.url('/groupindex')}">Find Group</a><br/>
-          <a href="${tg.url('/groupindex')}">List Groups</a><br/>
+          <a href="${tg.url('/group/index')}">Add Group</a><br/>
+          <a href="${tg.url('/group/index')}">Find Group</a><br/>
+          <a href="${tg.url('/group/index')}">List Groups</a><br/>
       </div> -->
 </body>
 
diff -r 157e43b04db3 -r ed3b5011eae2 ipa-server/ipa-gui/ipagui/templates/grouplist.kid
--- a/ipa-server/ipa-gui/ipagui/templates/grouplist.kid	Thu Oct 04 14:34:49 2007 -0700
+++ b/ipa-server/ipa-gui/ipagui/templates/grouplist.kid	Thu Oct 04 17:10:18 2007 -0700
@@ -8,7 +8,7 @@
 <body>
     <script type="text/javascript" charset="utf-8" src="${tg.url('/static/javascript/tablekit.js')}"></script>
     <div id="search">
-        <form action="${tg.url('/grouplist')}" method="get">
+        <form action="${tg.url('/group/list')}" method="get">
             <input id="criteria" type="text" name="criteria" value="${criteria}" />
             <input type="submit" value="Find Groups"/>
         </form>
@@ -32,7 +32,7 @@
           <tbody>
             <tr py:for="group in groups">
                 <td>
-                    <a href="${tg.url('/groupshow',cn=group.cn)}">${group.cn}</a>
+                    <a href="${tg.url('/group/show',cn=group.cn)}">${group.cn}</a>
                 </td>
                 <td>
                     ${group.description}
diff -r 157e43b04db3 -r ed3b5011eae2 ipa-server/ipa-gui/ipagui/templates/groupnew.kid
--- a/ipa-server/ipa-gui/ipagui/templates/groupnew.kid	Thu Oct 04 14:34:49 2007 -0700
+++ b/ipa-server/ipa-gui/ipagui/templates/groupnew.kid	Thu Oct 04 17:10:18 2007 -0700
@@ -8,6 +8,6 @@
 <body>
     <h2>Add Group</h2>
 
-    ${form.display(action="groupcreate", value=group)}
+    ${form.display(action=tg.url('/group/create'), value=group)}
 </body>
 </html>
diff -r 157e43b04db3 -r ed3b5011eae2 ipa-server/ipa-gui/ipagui/templates/groupnewform.kid
--- a/ipa-server/ipa-gui/ipagui/templates/groupnewform.kid	Thu Oct 04 14:34:49 2007 -0700
+++ b/ipa-server/ipa-gui/ipagui/templates/groupnewform.kid	Thu Oct 04 17:10:18 2007 -0700
@@ -18,7 +18,7 @@ from ipagui.helpers import ipahelper
   <script type="text/javascript" charset="utf-8"
     src="${tg.url('/static/javascript/dynamicedit.js')}"></script>
 
-  <?python searchurl = tg.url('/groupedit_search') ?>
+  <?python searchurl = tg.url('/group/edit_search') ?>
 
   <script type="text/javascript">
     function doSearch() {
diff -r 157e43b04db3 -r ed3b5011eae2 ipa-server/ipa-gui/ipagui/templates/groupshow.kid
--- a/ipa-server/ipa-gui/ipagui/templates/groupshow.kid	Thu Oct 04 14:34:49 2007 -0700
+++ b/ipa-server/ipa-gui/ipagui/templates/groupshow.kid	Thu Oct 04 17:10:18 2007 -0700
@@ -7,7 +7,7 @@
 </head>
 <body>
 <?python
-edit_url = tg.url('/groupedit', cn=group.get('cn'))
+edit_url = tg.url('/group/edit', cn=group.get('cn'))
 ?>
     <h2>View Group</h2>
 
@@ -48,12 +48,12 @@ edit_url = tg.url('/groupedit', cn=group
           member_cn = "%s %s" % (member.get('givenName', ''), member.get('sn', ''))
           member_desc = "(%s)" % member_uid
           member_type = "user"
-          view_url = tg.url('usershow', uid=member_uid)
+          view_url = tg.url('/user/show', uid=member_uid)
       else:
           member_cn = "%s" % member.get('cn')
           member_desc = "[group]"
           member_type = "group"
-          view_url = tg.url('groupshow', cn=member_cn)
+          view_url = tg.url('/group/show', cn=member_cn)
       ?>
       <span py:if='member_type == "user"'>
         <a href="${view_url}"
diff -r 157e43b04db3 -r ed3b5011eae2 ipa-server/ipa-gui/ipagui/templates/master.kid
--- a/ipa-server/ipa-gui/ipagui/templates/master.kid	Thu Oct 04 14:34:49 2007 -0700
+++ b/ipa-server/ipa-gui/ipagui/templates/master.kid	Thu Oct 04 17:10:18 2007 -0700
@@ -66,12 +66,12 @@
       <div id="sidebar">
         <h2>Tasks</h2>
         <p>
-        <a href="${tg.url('/usernew')}">Add Person</a><br/>
-        <a href="${tg.url('/userlist')}">Find People</a><br/>
+        <a href="${tg.url('/user/new')}">Add Person</a><br/>
+        <a href="${tg.url('/user/list')}">Find People</a><br/>
         </p>
         <p>
-        <a href="${tg.url('/groupnew')}">Add Group</a><br/>
-        <a href="${tg.url('/grouplist')}">Find Groups</a><br/>
+        <a href="${tg.url('/group/new')}">Add Group</a><br/>
+        <a href="${tg.url('/group/list')}">Find Groups</a><br/>
         </p>
         <p>
         <a href="${tg.url('/')}">Manage Policy</a><br/>
diff -r 157e43b04db3 -r ed3b5011eae2 ipa-server/ipa-gui/ipagui/templates/useredit.kid
--- a/ipa-server/ipa-gui/ipagui/templates/useredit.kid	Thu Oct 04 14:34:49 2007 -0700
+++ b/ipa-server/ipa-gui/ipagui/templates/useredit.kid	Thu Oct 04 17:10:18 2007 -0700
@@ -35,6 +35,6 @@ else:
         Password has expired
     </div>
 
-     ${form.display(action="userupdate", value=user, user_groups=user_groups)}
+     ${form.display(action=tg.url('/user/update'), value=user, user_groups=user_groups)}
 </body>
 </html>
diff -r 157e43b04db3 -r ed3b5011eae2 ipa-server/ipa-gui/ipagui/templates/usereditform.kid
--- a/ipa-server/ipa-gui/ipagui/templates/usereditform.kid	Thu Oct 04 14:34:49 2007 -0700
+++ b/ipa-server/ipa-gui/ipagui/templates/usereditform.kid	Thu Oct 04 17:10:18 2007 -0700
@@ -24,7 +24,7 @@ from ipagui.helpers import ipahelper
   <script type="text/javascript" charset="utf-8"
     src="${tg.url('/static/javascript/dynamicedit.js')}"></script>
 
-  <?python searchurl = tg.url('/useredit_search') ?>
+  <?python searchurl = tg.url('/user/edit_search') ?>
 
   <script type="text/javascript">
     function toggleProtectedFields(checkbox) {
@@ -196,7 +196,7 @@ from ipagui.helpers import ipahelper
           <span id="password_text">********</span>
           <input id="genpassword_button" type="button" value="Generate Password"
               disabled="true"
-              onclick="new Ajax.Request('${tg.url('/generate_password')}',
+              onclick="new Ajax.Request('${tg.url('/user/generate_password')}',
                 {
                   method: 'get',
                   onSuccess: function(transport) {
diff -r 157e43b04db3 -r ed3b5011eae2 ipa-server/ipa-gui/ipagui/templates/userlayout.kid
--- a/ipa-server/ipa-gui/ipagui/templates/userlayout.kid	Thu Oct 04 14:34:49 2007 -0700
+++ b/ipa-server/ipa-gui/ipagui/templates/userlayout.kid	Thu Oct 04 17:10:18 2007 -0700
@@ -14,8 +14,8 @@
 
 <!--      <div id="sidebar">
           <h2>Tools</h2>
-          <a href="${tg.url('/usernew')}">Add Person</a><br/>
-          <a href="${tg.url('/userlist')}">Find People</a><br/>
+          <a href="${tg.url('/user/new')}">Add Person</a><br/>
+          <a href="${tg.url('/user/list')}">Find People</a><br/>
       </div> -->
 </body>
 
diff -r 157e43b04db3 -r ed3b5011eae2 ipa-server/ipa-gui/ipagui/templates/userlist.kid
--- a/ipa-server/ipa-gui/ipagui/templates/userlist.kid	Thu Oct 04 14:34:49 2007 -0700
+++ b/ipa-server/ipa-gui/ipagui/templates/userlist.kid	Thu Oct 04 17:10:18 2007 -0700
@@ -8,7 +8,7 @@
 <body>
     <script type="text/javascript" charset="utf-8" src="${tg.url('/static/javascript/tablekit.js')}"></script>
     <div id="search">
-        <form action="${tg.url('/userlist')}" method="get">
+        <form action="${tg.url('/user/list')}" method="get">
             <input id="uid" type="text" name="uid" value="${uid}" />
             <input type="submit" value="Find People"/>
         </form>
@@ -38,7 +38,7 @@
           <tbody>
             <tr py:for="user in users">
                 <td>
-                    <a href="${tg.url('/usershow',uid=user.uid)}"
+                    <a href="${tg.url('/user/show',uid=user.uid)}"
                     >${user.givenName} ${user.sn}</a>
                     (${user.uid})
                 </td>
diff -r 157e43b04db3 -r ed3b5011eae2 ipa-server/ipa-gui/ipagui/templates/usernew.kid
--- a/ipa-server/ipa-gui/ipagui/templates/usernew.kid	Thu Oct 04 14:34:49 2007 -0700
+++ b/ipa-server/ipa-gui/ipagui/templates/usernew.kid	Thu Oct 04 17:10:18 2007 -0700
@@ -8,6 +8,6 @@
 <body>
     <h2>Add Person</h2>
 
-    ${form.display(action="usercreate", value=user)}
+    ${form.display(action=tg.url("/user/create"), value=user)}
 </body>
 </html>
diff -r 157e43b04db3 -r ed3b5011eae2 ipa-server/ipa-gui/ipagui/templates/usernewform.kid
--- a/ipa-server/ipa-gui/ipagui/templates/usernewform.kid	Thu Oct 04 14:34:49 2007 -0700
+++ b/ipa-server/ipa-gui/ipagui/templates/usernewform.kid	Thu Oct 04 17:10:18 2007 -0700
@@ -18,7 +18,7 @@ from ipagui.helpers import ipahelper
   <script type="text/javascript" charset="utf-8"
     src="${tg.url('/static/javascript/dynamicedit.js')}"></script>
 
-  <?python searchurl = tg.url('/useredit_search') ?>
+  <?python searchurl = tg.url('/user/edit_search') ?>
 
   <script type="text/javascript">
     function doSearch() {
@@ -123,7 +123,7 @@ from ipagui.helpers import ipahelper
               }
 
               if ((uid.value == "") || (uid.value == uid_suggest)) {
-                new Ajax.Request('${tg.url('/suggest_uid')}', {
+                new Ajax.Request('${tg.url('/user/suggest_uid')}', {
                     method: 'get',
                     parameters: {'givenname': givenname.value, 'sn': sn.value},
                     onSuccess: function(transport) {
@@ -135,7 +135,7 @@ from ipagui.helpers import ipahelper
               }
 
               if ((mail.value == "") || (mail.value == mail_suggest)) {
-                new Ajax.Request('${tg.url('/suggest_email')}', {
+                new Ajax.Request('${tg.url('/user/suggest_email')}', {
                     method: 'get',
                     parameters: {'givenname': givenname.value, 'sn': sn.value},
                     onSuccess: function(transport) {
@@ -230,7 +230,7 @@ from ipagui.helpers import ipahelper
 
           <!--
           <input type="button" value="Generate Password"
-              onclick="new Ajax.Request('${tg.url('/generate_password')}',
+              onclick="new Ajax.Request('${tg.url('/user/generate_password')}',
                 {
                   method: 'get',
                   onSuccess: function(transport) {
diff -r 157e43b04db3 -r ed3b5011eae2 ipa-server/ipa-gui/ipagui/templates/usershow.kid
--- a/ipa-server/ipa-gui/ipagui/templates/usershow.kid	Thu Oct 04 14:34:49 2007 -0700
+++ b/ipa-server/ipa-gui/ipagui/templates/usershow.kid	Thu Oct 04 17:10:18 2007 -0700
@@ -7,7 +7,7 @@
 </head>
 <body>
 <?python
-edit_url = tg.url('/useredit', uid=user.get('uid'))
+edit_url = tg.url('/user/edit', uid=user.get('uid'))
 ?>
     <h2>View Person</h2>
 
@@ -218,7 +218,7 @@ else:
             Manager:
           </th>
           <td>
-            <a href="${tg.url('/usershow', uid=user_manager.uid)}"
+            <a href="${tg.url('/user/show', uid=user_manager.uid)}"
               >${user_manager.givenname} ${user_manager.sn}</a>
           </td>
         </tr>
@@ -254,13 +254,13 @@ else:
 
     <div class="formsection" py:if='len(user_reports) > 0'>Direct Reports</div>
     <div py:for="report in user_reports">
-      <a href="${tg.url('/usershow', uid=report.uid)}"
+      <a href="${tg.url('/user/show', uid=report.uid)}"
         >${report.givenname} ${report.sn}</a>
     </div>
 
     <div class="formsection">Groups</div>
     <div py:for="group in user_groups">
-      <a href="${tg.url('/groupshow', cn=group.cn)}">${group.cn}</a>
+      <a href="${tg.url('/group/show', cn=group.cn)}">${group.cn}</a>
     </div>
 
     <br/>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: smime.p7s
Type: application/x-pkcs7-signature
Size: 4054 bytes
Desc: not available
URL: <http://listman.redhat.com/archives/freeipa-devel/attachments/20071004/2a01d3bf/attachment.bin>


More information about the Freeipa-devel mailing list