#################################################
#
# ldap_wu
# $Id: ldap_wu.py,v 1.3 2005/06/02 09:16:39 cvs Exp $
#
# create_workgroups
# generates a set of mxmWorkgroup directories,
# creates users in GRUF and also groups 
# according to the structure provided by
# an LDAP server the BACH team runs.
#
# This setup allows users to share objects
# as groups, or on user level.
# 
# mxmWorkgroup must be installed before this
# script will work.
#
# GPL 2004, by Georg Gogo. BERNHARD
# gogo@bluedynamics.com
#
#################################################


import sys
import ldap


# This is the main function that should be called from 
# within a plone instance, at the object that is container
# for the Workgroup Objects. Add it as External Method in
# the portal_skins/custon folder, run it by calling it
# from the URL of the desired Container and make sure
# that security permissions disallow anonymous users
# to invoke the script.


LDAP_SERVER = "monty.wu-wien.ac.at"


def create_workgroups(self):


    # This method returns all departments matching
    # a certain filter.

    def get_deps(filter=None):
        # filter example: "uid=w*"
    
        # connect to monty
        server = LDAP_SERVER 
        l = ldap.open(server)
    
        # credentials
        adm = "uid=ldapsearch,ou=admins,dc=wu-wien,dc=ac,dc=at"
        ret = l.simple_bind(adm, "nobodyknows")
    
        # search query
        base = "ou=departments,dc=wu-wien,dc=ac,dc=at" # All departments
        retrieve_attrs = None
        
        # start the query
        result_id = l.search(base, ldap.SCOPE_SUBTREE, filter, retrieve_attrs)
    
        # retrieve results
        timeout = 0         # no timeout
        result_set = []
        while 1:
            result_type, result_data = l.result(result_id, timeout)
            if (result_data == []):
                break
            else:
                if result_type == ldap.RES_SEARCH_ENTRY:
                    result_set = result_set + result_data
                if len(result_set) == 0:
                    print "No Results."
    
        # Prepare the result
        res = []
        for item in result_set:
            try:
                #print item
                list = item[0].split(',')
                key = "departmentNumber="
                deps = []
                for l in list :
                    if l[:len(key)] == key :
                        dep = l[len(key):]
                        deps.append(dep)
            except :
                print "ERROR."
                raise
            deps.reverse()
            res.append([deps, item[1]['description'][0]])
    
        return res
 


    # This method returns a list of all users that are
    # members of a certain department / that match with 
    # the given filter.
 
    def get_users(filter):
        # connect
        server = LDAP_SERVER
        l = ldap.open(server)
    
        # credentials
        adm = "uid=ldapsearch,ou=admins,dc=wu-wien,dc=ac,dc=at"
        ret = l.simple_bind(adm, "nobodyknows")
    
        # search query
        base = "ou=users,dc=wu-wien,dc=ac,dc=at" # schraenkt auf den subtree users ein
        retrieve_attrs = None
        result_id = l.search(base, ldap.SCOPE_SUBTREE, filter, retrieve_attrs)
    
        # retrieve
        timeout = 0         # no timeout
        result_set = []
    
        while 1:
            result_type, result_data = l.result(result_id, timeout)
    
            if (result_data == []):
                break
            else:
                if result_type == ldap.RES_SEARCH_ENTRY:
                    result_set = result_set + result_data
    
                if len(result_set) == 0:
                    print "No Results."
    
        uids = []
        for rec in result_set:
            try:
                uid = rec[1]['uid'][0]
                sn = rec[1]['sn'][0]
                gn = rec[1]['givenName'][0]


                print "sn:", sn, "gn:", gn

                depnum = rec[1]['departmentNumber'][0]
                name = sn + " " + gn 
    #            print "%9s: %s, %s" % (uid,
    #                                   sn.encode('latin-1'),
    #                                   gn.encode('latin-1'))
                uids.append([uid, depnum, name])
    
            except KeyError:
                pass
            
        return uids



    # This method sets local roles for the users,
    # the created Workgroups will provide local roles
    # 'per user', to force administrators to add or
    # remove Workgroup Members as users, not as a whole group.

    def addLocalRole(obj, userid, role):
        """ add a local role for a user """
        roles = list(obj.get_local_roles_for_userid(userid))
        if role not in roles:
            roles.append(role)
            obj.manage_setLocalRoles(userid, roles)


# main

    context = self

    try :
      from Products.CMFPlone.PloneFolder import PloneFolder
      home = PloneFolder(id='departments', title='WU-Departments') 
      context._setObject('deps', home)
      print "Departments Folder added"
    except :
      print "Departments folder exception caught, continuing at context level."
#      raise 
    
    home = context
    REQUEST = self.REQUEST
    print "ldap_wu is starting to build tree at", repr(home)
    
    userfolder = getattr(context, 'acl_users')
    print "userfolder==", repr(userfolder)
#    print "dir(userfolder)==", repr(dir(userfolder))

    dep_list = get_deps(filter='departmentNumber=*')
#    print "dep_list==", repr(dep_list)

    for dep in dep_list :
      
      print "Department:", repr(dep)

      spot = home
      for d in dep[0] :

#        print "iteration d ==", repr(d)

        if hasattr(spot, d) :
          # Workgroup is already present, so change to it
          spot = getattr(spot, d)
        else :
          # Create Workgroup
          spot.invokeFactory(type_name="Workgroup", id=d, title=dep[1])

          # Change to it
          spot = spot[d]

          workgroup = getattr(spot, d)
          print 'Created new Workgroup: ', repr(workgroup)
          workgroup.description = dep[1]

          # Prepare name for acl_users group
          groupname = dep[1]
 
          # Create acl_users Group
          print "Creating Group %s." % (groupname)
          userfolder.userFolderAddGroup( groupname, roles=[], )

          # Grab the Group object
          group = userfolder.getGroup( groupname, prefixed=0)
          print "Group Object is", repr(group)

          # Collect all users of that department
          users = get_users(filter='departmentNumber=%s' % d)
          for user in users :

            print "User:", repr(user)

            # Prepare User
            REQUEST.set('username',user[0]) 
            REQUEST.set('password', user[0])
            REQUEST.set('confirm', user[0])
            REQUEST.set('email', user[0]+'@'+'wu-wien.ac.at')
            REQUEST.set('mail_me', 0)
            REQUEST.set('fullname', user[2])
            print "Registering user", repr(REQUEST.get('fullname', '')) 
            print "u:", repr(REQUEST.get('username', ''))
            print "p:", repr(REQUEST.get('password', ''))
            print "e:", repr(REQUEST.get('email', ''))

            # Create User
            try :
                context.portal_registration.addMember(id = REQUEST.get('username',''), 
                                                      password = REQUEST.get('password',''),
                                                      properties=REQUEST,)
                print "User %s created." % (user[0])

                # Add user to Group
                userobject = userfolder.getUser(REQUEST.get('username',''))
                userfolder.changeUser(user=REQUEST.get('username',''), groups = [groupname,], roles = ['Member',], REQUEST=REQUEST, )
                print "User added to group %s" % (groupname)

            except Exception, e:
                print "Creation of user %s FAILED: %s" % (REQUEST.get('username',''), e)
                raise

            # Add user to Workgroup
            workgroup = spot.getWorkgroup()
            workgroup.addGroupmembersById([user[0]])

            # Apply local role on user: GroupMember and Owner
            addLocalRole(spot, user[0], 'GroupMember')
            addLocalRole(spot, user[0], 'Owner')
    
    return "Done"
