Getting LDAP synchronization production ready
authorDan Scott <dan@coffeecode.net>
Wed, 7 Sep 2011 15:34:04 +0000 (11:34 -0400)
committerDan Scott <dscott@laurentian.ca>
Mon, 12 Nov 2012 17:57:57 +0000 (12:57 -0500)
* Search for user before attempting to create the user
* Set the default expiry date by profile
* Document how we're currently populating barcodes

Signed-off-by: Dan Scott <dscott@laurentian.ca>
tools/patron-load/ldap_osrf_sync

index 8786add..5110a9f 100644 (file)
@@ -10,11 +10,26 @@ file (credentials.py) and imported to avoid storing credentials in the VCS.
    directory using the filter (createTimestamp>=time).
 
 2. For each new LDAP record, check to see if the record exists in Evergreen
-   (matching on ident_value)
+   (matching on ident_value, usrname, email).
    
    If not, create a new account with barcode.
 
-3. Dump the output of new ident_value + barcode in CSV format somewhere.
+3. Push the new barcode back into the LDAP directory.
+
+Needs to be able to find credentials.py with the following content:
+
+LDAP_HOST = 'ldap://192.168.1.106'
+LDAP_DN = 'cn=ldap_usr'
+LDAP_PW = 'password'
+
+OSRF_HTTP = 'http'
+IDL_URL = '/reports/fm_IDL.xml'
+GATEWAY_URL = '/osrf-gateway-v1'
+
+OSRF_HOST = 'localhost'
+OSRF_USER = 'admin'
+OSRF_PW = 'demo123'
+OSRF_WORK_OU = 'herb'
 """
 
 import os
@@ -72,6 +87,20 @@ class User:
             print >> sys.stderr, 'No givenName for %s' % (self.usrname)
 
         self.profile = self.get_profile()
+        self.expire_date = self.get_expiry_date()
+
+    def get_expiry_date(self):
+        """
+        Map LDAP record to Evergreen expiry dates
+        """
+
+        # Faculty and staff get a long time
+        if self.profile == 11 or self.profile == 14:
+            return '2020-09-30'
+        elif self.profile == 13 or self.profile == 12:
+            # Students get next academic year
+            return '2012-09-30'
+        return '2012-09-30'
 
     def get_identity(self):
         """
@@ -288,8 +317,8 @@ def find_new_ldap_users(con, attributes, create_date, auth):
     base_dn = 'o=lul'
     search_scope = ldap.SCOPE_SUBTREE
     ldap_filter = '(&(objectclass=lulEduPerson))'
-    ldap_filter = '(&(objectclass=lulEduPerson)(lulPrimaryAffiliation=*)(createTimestamp>=%s000000Z))' % create_date
     ldap_filter = '(&(lulStudentLevel=*))'
+    ldap_filter = '(&(objectclass=lulEduPerson)(lulPrimaryAffiliation=*)(createTimestamp>=%s))' % create_date
 
     try:
         result_id = con.search(base_dn, search_scope, ldap_filter, attributes)
@@ -299,11 +328,54 @@ def find_new_ldap_users(con, attributes, create_date, auth):
                 break
             else:
                 # dump_data(result_data)
-                create_evergreen_user(result_data[0][1], auth)
+                create_evergreen_user(auth, result_data[0][1])
     except ldap.LDAPError, exc:
         print >> sys.stderr, exc
 
-def create_evergreen_user(result_data, auth):
+def find_evergreen_user(auth, user):
+    """
+    Search for an existing user in Evergreen
+
+    Returns True if found, False if not
+    """
+
+    limit = 1
+    sort = None
+    search_ou = 1
+    include_inactive = True
+
+    print("Trying to find user: %s %s %s" % 
+        (user.ident_value, user.email, user.usrname)
+    )
+
+    by_id = osrf_request(
+        'open-ils.actor', 'open-ils.actor.patron.search.advanced',
+        auth, {'ident_value': {'value': user.ident_value, 'group': 0}}, limit,
+        sort, include_inactive, search_ou
+    ).send()
+
+    if by_id and len(by_id):
+        return True
+
+    by_email = osrf_request(
+        'open-ils.actor', 'open-ils.actor.patron.search.advanced',
+        auth, {'email': {'value': user.email}}, limit,
+        sort, include_inactive, search_ou
+    ).send()
+
+    if by_email and len(by_email):
+        return True
+
+    by_usrname = osrf_request(
+        'open-ils.actor', 'open-ils.actor.patron.search.advanced',
+        auth, {'usrname': {'value': user.usrname}}, limit,
+        sort, include_inactive, search_ou
+    ).send()
+
+    if by_usrname and len(by_usrname):
+        return True
+
+def create_evergreen_user(auth, result_data):
     """
     Map LDAP record to Evergreen user
     """
@@ -312,6 +384,11 @@ def create_evergreen_user(result_data, auth):
     if not user:
         return
 
+    found = find_evergreen_user(auth, user)
+    if found:
+        print("Found: %s" % user.usrname)
+        return
+
     newau = osrf.net_obj.new_object_from_hint('au')
 
     newau.isnew(True)
@@ -324,6 +401,11 @@ def create_evergreen_user(result_data, auth):
     newau.ident_value(user.ident_value)
     newau.home_ou(user.home_ou)
     newau.passwd(user.passwd)
+    newau.expire_date(user.expire_date)
+
+    # Workaround open-ils.actor.patron.update bug
+    newau.addresses([])
+    newau.cards([])
 
     # Create the user
     try:
@@ -339,10 +421,19 @@ def create_evergreen_user(result_data, auth):
 
     # XXX Create barcode... how?
     # Trigger on actor.usr? New custom API?
+    # Currently doing the horrible thing of:
+    # SELECT evergreen.lu_update_barcode(id)
+    #   FROM actor.usr
+    #   WHERE create_date > %s
+    #   AND barcode IS NULL
+    #   AND home_ou IN (
+    #     SELECT id FROM actor.org_unit WHERE parent_ou = 105
+    #   )
+    # ;
 
     create_stat_cats(newau, result_data)
 
-    print(newau)
+    print("Created: %s" % newau.usrname())
 
 def create_stat_cats(user, result_data):
     """
@@ -403,17 +494,20 @@ if __name__ == '__main__':
     load_idl()
 
     # Log in and get an authtoken
-    AUTHTOKEN = osrf_login(credentials.OSRF_USER, credentials.OSRF_PW)
-
-    UDATA = {
-        'mail': ['dan@example.com'],
-        'givenName':  ['Dan'],
-        'sn':  ['Scott'],
-        'lulColleagueId':  ['0123456'],
-        'lulStudentLevel':  ['GR'],
-    }
-    create_evergreen_user(UDATA, AUTHTOKEN)
-
-#    ldap_create_by_date('20110701')
+    AUTHTOKEN = osrf_login(
+        credentials.OSRF_USER, credentials.OSRF_PW, credentials.OSRF_WORK_OU
+    )
+
+#    UDATA = {
+#        'mail': ['dan@example.com'],
+#        'givenName':  ['Dan'],
+#        'sn':  ['Scott'],
+#        'lulColleagueId':  ['0123456'],
+#        'lulStudentLevel':  ['GR'],
+#    }
+#    create_evergreen_user(AUTHTOKEN, UDATA)
+
+    # XXX Pull this in from sys.argv
+    ldap_create_by_date('20110906130000Z', AUTHTOKEN)
 
 # vim: et:ts=4:sw=4:tw=78: