thanks to dbs, much better opensrf interaction for update
authorartunit <artunit@6d9bc8c9-1ec2-4278-b937-99fde70a366f>
Wed, 23 Mar 2011 03:20:57 +0000 (03:20 +0000)
committerartunit <artunit@6d9bc8c9-1ec2-4278-b937-99fde70a366f>
Wed, 23 Mar 2011 03:20:57 +0000 (03:20 +0000)
git-svn-id: svn://svn.open-ils.org/ILS-Contrib/servres/trunk@1278 6d9bc8c9-1ec2-4278-b937-99fde70a366f

conifer/libsystems/evergreen/opensrf.py
conifer/syrup/views/items.py

index a1c704f..501a325 100644 (file)
@@ -1,39 +1,70 @@
 # session-based opensrf calls go here
+# thanks to dan scott for sorting out the python integration
 
-from conifer.libsystems import marcxml as M
-from conifer.libsystems.evergreen import item_status as I
-from conifer.libsystems.evergreen.support import initialize, E1
 from datetime import date
 from django.conf import settings
-import hashlib
 import os
 import re
 import traceback
 
-def auth_token(username, password, org, workstation):
-    try:
-       authtoken = None
-       payload = E1(settings.OPENSRF_AUTHENTICATE_INIT, username)
-       pw = hashlib.md5(password).hexdigest()
-       pw = hashlib.md5(payload + pw).hexdigest()
-       authinfo = E1(settings.OPENSRF_AUTHENTICATE,{"password":pw, "type":"staff", 
-               "org": org, "username":username,
-               "workstation":workstation})
-       if authinfo:
-               payload = authinfo.get("payload")
-               authtoken = payload.get("authtoken")
-    except:
-           print "authentication problem: ", username
-            print "*** print_exc:"
-            traceback.print_exc()
-            pass          # fail silently in production 
-            return None
+import oils.event
+import oils.utils.idl
+import oils.utils.utils
+import osrf.gateway
+import osrf.json
+import sys
+import tempfile
+import urllib2
+
+class AuthException(Exception):
+    """
+    Exceptions for authentication events
+    """
+
+    def __init__(self, msg=''):
+        """
+        Initialize the authentication exception
+        """
+        Exception.__init__(self)
+        self.msg = msg
+
+    def __str__(self):
+        """
+        Stringify the authentication exception
+        """
+        return 'AuthException: %s' % self.msg
 
+def auth_token(username, password, workstation):
+    authtoken = None
+    seed = request(
+       'open-ils.auth', 
+       'open-ils.auth.authenticate.init', username).send()
+
+    # generate the hashed password
+    password = oils.utils.utils.md5sum(seed + oils.utils.utils.md5sum(password))
+       
+    result = request(
+       'open-ils.auth',
+       'open-ils.auth.authenticate.complete', {
+       'workstation' : workstation,
+       'username' : username,
+       'password' : password,
+       'type' : 'staff' 
+       }).send()
+       
+    evt = oils.event.Event.parse_event(result)
+    if evt and not evt.success:
+       print "authentication problem: ", AuthException(evt.text_code)
+       return None
+
+    authtoken = result['payload']['authtoken']
     return authtoken
 
 def session_cleanup(authtoken):
     try:
-       payload = E1(settings.OPENSRF_CLEANUP, authtoken)
+       result = request(
+               'open-ils.auth', 
+               'open-ils.auth.session.delete', authtoken).send()
     except:
            print "session problem: ", authtoken
             print "*** print_exc:"
@@ -43,55 +74,121 @@ def session_cleanup(authtoken):
         
     return True
 
-def evergreen_item_update(barcode, callno, modifier, desk):
+def load_idl():
+    """
+    Loads the fieldmapper IDL, registering class hints for the defined objects
+
+    We use a temporary file to store the IDL each time load_idl()
+    is invoked to ensure that the IDL is in sync with the target
+    server. One could a HEAD request to do some smarter caching,
+    perhaps.
+    """
+    
+    parser = oils.utils.idl.IDLParser()
+    idlfile = tempfile.TemporaryFile()
+
+    # Get the fm_IDL.xml file from the server
+    try:
+        idl = urllib2.urlopen('%s://%s/%s' % 
+            (settings.OSRF_HTTP, settings.EVERGREEN_GATEWAY_SERVER, settings.IDL_URL)
+        )
+        idlfile.write(idl.read())
+        # rewind to the beginning of the file
+        idlfile.seek(0)
+
+    #no pass on these, updates are too critical to ever be out of sync
+    except urllib2.URLError, exc:
+        print("Could not open URL to read IDL: %s", exc.code)
+
+    except IOError, exc:
+        print("Could not write IDL to file: %s", exc.code)
+
+    # parse the IDL
+    parser.set_IDL(idlfile)
+    parser.parse_IDL()
+
+def request(service, method, *args):
+    """
+    Make a JSON request to the OpenSRF gateway
+
+    This is as simple as it gets. Atomic requests will require a bit
+    more effort.
+    """
+
+    req = osrf.gateway.JSONGatewayRequest(service, method, *args)
+
+    # The gateway URL ensures we're using JSON v1, not v0
+    req.setPath(settings.GATEWAY_URL)
+    return req
+
+def ils_item_update(barcode, callno, modifier, location):
     try:
-        token = auth_token(settings.OPENSRF_STAFF_USERID, settings.OPENSRF_STAFF_PW,
-                settings.OPENSRF_STAFF_ORG, settings.OPENSRF_STAFF_WORKSTATION)
-
-        null = None
-        true = True
-        false = False
-        barcode_copy = E1(settings.OPENSRF_CN_BARCODE, token, barcode);
-
-        copy = None
-        volumeinfo = None
-
-        if barcode_copy:
-                volumeinfo = barcode_copy.get("volume")
-                if volumeinfo:
-                        volume = volumeinfo['__p']
-                        if volume and volume[7] != callno:
-                                volume[0] = []
-                                volume[7] = str(callno)
-                               vol_len = len(volume) - 1
-                               volume[vol_len] = str(volume[vol_len])
-                               # ok, this is bad, need to find what these values are
-                               for i in range(0, 4):
-                                       volume.append(None)
-                                volume.append('1')
-                                # print "volume", volume
-                                updaterec = E1(settings.OPENSRF_VOLUME_UPDATE,
-                                        token, [{"__c":"acn","__p":volume}], false,
-                                        {"auto_merge_vols":false})
-                               # print "update", updaterec
-                copy = barcode_copy.get("copy")
-                if copy:
-                        # print "copy", copy
-                        detailid = copy['__p'][21]
-                        details = E1(settings.OPENSRF_FLESHEDCOPY_CALL, [detailid])
-                        if details and (details[0]['__p'][7] != modifier or details[0]['__p'][23] != desk):
-                                details[0]['__p'][7] = str(modifier)
-                                details[0]['__p'][23] = str(desk)
-                               # ditto here too, need to find what these values are
-                               for i in range(0, 6):
-                                       details[0]['__p'].append(None)
-                                details[0]['__p'].append('1')
-
-                                print "details", details
-                                updaterec = E1(settings.OPENSRF_BATCH_UPDATE, token, details,true)
-                                # print "updaterec", updaterec
-
-        session_cleanup(token)
+       item_changed = False
+       callno_changed = False
+
+       # Set the host for our requests
+       osrf.gateway.GatewayRequest.setDefaultHost(settings.EVERGREEN_GATEWAY_SERVER)
+
+       # Pull all of our object definitions together
+       load_idl()
+
+       # We get our copy object
+       req = request('open-ils.search', 
+               'open-ils.search.asset.copy.fleshed2.find_by_barcode', 
+               barcode)
+       barcode_copy = req.send()
+
+       # are there changes?
+       if barcode_copy.location().id != location or barcode_copy.circ_modifier != modifier:
+               item_changed = True 
+
+       # And our call number object
+        req = request('open-ils.search', 
+               'open-ils.search.asset.call_number.retrieve', 
+               barcode_copy.call_number())
+       call_num = req.send()
+
+       # are there changes?
+       if call_num.label() != callno:
+               callno_changed = True
+
+       # there might be nothing to do
+       if not item_changed and not callno_changed:
+               return True
+               
+       # ok, we are going to update, first we authenticate
+        authtoken = auth_token(settings.OPENSRF_STAFF_USERID, 
+               settings.OPENSRF_STAFF_PW,
+                settings.OPENSRF_STAFF_WORKSTATION)
+
+       # item changes first, location and circ modifier
+       if authtoken and item_changed:
+               barcode_copy.location().id(location);
+               barcode_copy.circ_modifier(modifier);
+               barcode_copy.ischanged(True)
+
+               acp = [barcode_copy]
+               req = request('open-ils.cat', 
+                       'open-ils.cat.asset.copy.fleshed.batch.update',
+                       authtoken, acp, False, None)
+               result = req.send()
+               # print "item result", result
+
+       # on to call number
+       if authtoken and callno_changed:
+               call_num.label(callno)
+               call_num.ischanged(True)
+
+               # volume.fleshed.batch.update expects an array of call number objects 
+               acn = [call_num]
+               req = request('open-ils.cat', 
+                       'open-ils.cat.asset.volume.fleshed.batch.update', 
+                       authtoken, acn, False, None)
+               result = req.send()
+               # print "callno result", result
+        
+       #clean up session
+       session_cleanup(authtoken)
     except:
             print "item update problem"
             print "*** print_exc:"
index 5dec0eb..d1ba3ce 100644 (file)
@@ -361,6 +361,7 @@ def item_add_cat_search(request, site_id, item_id):
        eg_modifier = None
        eg_desk = None
 
+       #TODO: use python bindings for these interactions
        bar_num=request.POST.get('bc')
        if bar_num and settings.OPENSRF_STAFF_USERID:
                bc = bar_num
@@ -456,7 +457,7 @@ def item_edit(request, site_id, item_id):
                update_status = True
 
                if update_option == 'Cat': 
-                       update_status = evergreen_item_update(item.barcode, item.orig_callno, 
+                       update_status = ils_item_update(item.barcode, item.orig_callno, 
                                modifier_option, location_option)
 
                #leave values alone if update failed