--- /dev/null
+# -----------------------------------------------------------------------
+# Copyright (C) 2007 Georgia Public Library Service
+# Bill Erickson <billserickson@gmail.com>
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+# -----------------------------------------------------------------------
+
+
+OILS_NS_OBJ='http://open-ils.org/spec/opensrf/IDL/objects/v1'
+OILS_NS_PERSIST='http://open-ils.org/spec/opensrf/IDL/persistance/v1'
+OILS_NS_REPORTER='http://open-ils.org/spec/opensrf/IDL/reporter/v1'
+
+OILS_APP_CSTORE='open-ils.cstore'
+
--- /dev/null
+# -----------------------------------------------------------------------
+# Copyright (C) 2007 Georgia Public Library Service
+# Bill Erickson <billserickson@gmail.com>
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+# -----------------------------------------------------------------------
+
+from osrf.log import *
+from osrf.system import osrfConnect
+from oils.utils.idl import oilsParseIDL
+from oils.utils.csedit import oilsLoadCSEditor
+
+def oilsConnect(config):
+ """Connects to the opensrf network, parses the IDL file, and loads the CSEditor"""
+ osrfLogInfo("oilsConnect(): connecting with config %s" % config)
+ osrfConnect(config)
+ oilsParseIDL()
+ oilsLoadCSEditor()
--- /dev/null
+# -----------------------------------------------------------------------
+# Copyright (C) 2007 Georgia Public Library Service
+# Bill Erickson <billserickson@gmail.com>
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+# -----------------------------------------------------------------------
+
+from osrf.log import *
+from osrf.json import *
+from oils.utils.utils import replace
+from oils.utils.idl import oilsGetIDLParser
+from osrf.ses import osrfClientSession
+from oils.const import *
+import re
+
+ACTIONS = ['create', 'retrieve', 'update', 'delete', 'search']
+
+class CSEditor(object):
+ def __init__(self, **args):
+
+ self.app = args.get('app', OILS_APP_CSTORE)
+ self.authtoken = args.get('authtoken', args.get('auth'))
+ self.requestor = args.get('requestor')
+ self.connect = args.get('connect')
+ self.xact = args.get('xact')
+ self.__session = None
+
+ def die_event(self):
+ pass
+ def checkauth(self):
+ pass
+
+
+ # -------------------------------------------------------------------------
+ # Creates a session if one does not already exist. If necessary, connects
+ # to the remote service and starts a transaction
+ # -------------------------------------------------------------------------
+ def session(self, ses=None):
+ if not self.__session:
+ self.__session = osrfClientSession(self.app)
+
+ if self.connect or self.xact:
+ self.log(osrfLogDebug,'connecting to ' + self.app)
+ self.__session.connect()
+
+ if self.xact:
+ self.log(osrfLogInfo, "starting new db transaction")
+ self.request(self.app + '.transaction.begin')
+
+ return self.__session
+
+
+ # -------------------------------------------------------------------------
+ # Logs string with some meta info
+ # -------------------------------------------------------------------------
+ def log(self, func, string):
+ s = "editor[";
+ if self.xact: s += "1|"
+ else: s += "0|"
+ if self.requestor: s += str(self.requestor.id())
+ else: s += "0"
+ s += "]"
+ func("%s %s" % (s, string))
+
+
+ # -------------------------------------------------------------------------
+ # Rolls back the existing db transaction
+ # -------------------------------------------------------------------------
+ def rollback(self):
+ if self.__session and self.xact:
+ self.log(osrfLogInfo, "rolling back db transaction")
+ self.request(self.app + '.transaction.rollback')
+ self.disconnect()
+
+ # -------------------------------------------------------------------------
+ # Commits the existing db transaction
+ # -------------------------------------------------------------------------
+ def commit(self):
+ if self.__session and self.xact:
+ self.log(osrfLogInfo, "comitting db transaction")
+ self.request(self.app + '.transaction.commit')
+ self.disconnect()
+
+
+ # -------------------------------------------------------------------------
+ # Disconnects from the remote service
+ # -------------------------------------------------------------------------
+ def disconnect(self):
+ if self.__session:
+ self.__session.disconnect()
+ self.__session = None
+
+
+ # -------------------------------------------------------------------------
+ # Sends a request
+ # -------------------------------------------------------------------------
+ def request(self, method, params=[]):
+
+ # XXX improve param logging here
+
+ self.log(osrfLogInfo, "request %s %s" % (method, str(params)))
+
+ if self.xact and self.session().state != OSRF_APP_SESSION_CONNECTED:
+ self.log(osrfLogErr, "csedit lost it's connection!")
+
+ val = None
+
+ try:
+ req = self.session().request2(method, params)
+ resp = req.recv()
+ val = resp.content()
+
+ except Exception, e:
+ self.log(osrfLogErr, "request error: %s" % str(e))
+ raise e
+
+ return val
+
+
+ # -------------------------------------------------------------------------
+ # Returns true if our requestor is allowed to perform the request action
+ # 'org' defaults to the requestors ws_ou
+ # -------------------------------------------------------------------------
+ def allowed(self, perm, org=None):
+ pass
+
+
+ def runMethod(self, action, type, arg, options={}):
+
+ method = "%s.direct.%s.%s" % (self.app, type, action)
+
+ if options.get('idlist'):
+ method = replace(method, 'search', 'id_list')
+ del options['idlist']
+
+ if action == 'search':
+ method = replace(method, '$', '.atomic')
+
+ params = [arg];
+ if len(options.keys()):
+ params.append(options)
+
+ val = self.request( method, params )
+
+ return val
+
+
+
+# -------------------------------------------------------------------------
+# Creates a class method for each action on each type of fieldmapper object
+# -------------------------------------------------------------------------
+def oilsLoadCSEditor():
+ obj = oilsGetIDLParser().IDLObject
+
+ for k, fm in obj.iteritems():
+ for action in ACTIONS:
+
+ fmname = replace(fm['fieldmapper'], '::', '_')
+ type = replace(fm['fieldmapper'], '::', '.')
+ name = "%s_%s" % (action, fmname)
+
+ str = 'def %s(self, arg, **options):\n' % name
+ str += '\treturn self.runMethod("%s", "%s", arg, dict(options))\n' % (action, type)
+ str += 'setattr(CSEditor, "%s", %s)' % (name, name)
+
+ exec(str)
+
--- /dev/null
+# -----------------------------------------------------------------------
+# Copyright (C) 2007 Georgia Public Library Service
+# Bill Erickson <billserickson@gmail.com>
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+# -----------------------------------------------------------------------
+
+from osrf.json import *
+from osrf.log import *
+from osrf.set import osrfSettingsValue
+
+import sys, libxml2, osrf.conf, string
+from oils.const import OILS_NS_OBJ, OILS_NS_PERSIST, OILS_NS_REPORTER
+
+__global_parser = None
+
+def oilsParseIDL():
+ global __global_parser
+ idlParser = oilsIDLParser();
+ idlParser.setIDL(osrfSettingsValue('IDL'))
+ idlParser.parseIDL()
+ __global_parser = idlParser
+
+def oilsGetIDLParser():
+ global __global_parser
+ return __global_parser
+
+class oilsIDLParser(object):
+
+ def __init__(self):
+ self.IDLObject = {}
+
+ def setIDL(self, file):
+ osrfLogInfo("setting IDL file to " + file)
+ self.idlFile = file
+
+ def parseIDL(self):
+ """Parses the IDL file and builds class objects"""
+
+ doc = libxml2.parseFile(self.idlFile)
+ root = doc.children
+ child = root.children
+
+ while child:
+
+ if child.type == 'element':
+
+ # -----------------------------------------------------------------------
+ # 'child' is the main class node for a fieldmapper class.
+ # It has 'fields' and 'links' nodes as children.
+ # -----------------------------------------------------------------------
+
+ id = child.prop('id')
+ self.IDLObject[id] = {}
+ obj = self.IDLObject[id]
+ obj['fields'] = []
+
+ obj['controller'] = child.prop('controller')
+ obj['fieldmapper'] = child.nsProp('fieldmapper', OILS_NS_OBJ)
+ obj['virtual'] = child.nsProp('virtual', OILS_NS_PERSIST)
+ obj['rpt_label'] = child.nsProp('label', OILS_NS_REPORTER)
+
+ class_node = child.children
+ #osrfLogInternal("parseIDL(): parsing class %s" % id)
+
+ keys = []
+ while class_node:
+ if class_node.type == 'element':
+ if class_node.name == 'fields':
+ keys = self.parseFields(id, class_node)
+ class_node = class_node.next
+
+ #obj['fields'] = keys
+ osrfNetworkRegisterHint(id, keys, 'array' )
+
+ child = child.next
+
+ doc.freeDoc()
+
+
+ def parseFields(self, cls, fields):
+ """Takes the fields node and parses the included field elements"""
+
+ field = fields.children
+ keys = []
+ idlobj = self.IDLObject[cls]
+
+ while field:
+ if field.type == 'element':
+ keys.append(None)
+ field = field.next
+
+ field = fields.children
+ while field:
+ obj = {}
+ if field.type == 'element':
+ name = field.prop('name')
+ position = int(field.nsProp('array_position', OILS_NS_OBJ))
+ obj['name'] = name
+
+ try:
+ keys[position] = name
+ except Exception, e:
+ osrfLogErr("parseFields(): position out of range. pos=%d : key-size=%d" % (position, len(keys)))
+ raise e
+
+ virtual = field.nsProp('virtual', OILS_NS_PERSIST)
+ obj['rpt_label'] = field.nsProp('label', OILS_NS_REPORTER)
+ obj['rpt_dtype'] = field.nsProp('datatype', OILS_NS_REPORTER)
+ obj['rpt_select'] = field.nsProp('selector', OILS_NS_REPORTER)
+
+ if virtual == string.lower('true'):
+ obj['virtual'] = True
+ else:
+ obj['virtual'] = False
+
+ idlobj['fields'].append(obj)
+
+ field = field.next
+
+ return keys
+
+
+
+
--- /dev/null
+# -----------------------------------------------------------------------
+# Copyright (C) 2007 Georgia Public Library Service
+# Bill Erickson <billserickson@gmail.com>
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+# -----------------------------------------------------------------------
+
+import re
+
+# -----------------------------------------------------------------------
+# Grab-bag of general utility functions
+# -----------------------------------------------------------------------
+
+
+# -----------------------------------------------------------------------
+# more succinct search/replace call
+# -----------------------------------------------------------------------
+def replace(str, pattern, replace):
+ return re.compile(pattern).sub(replace, str)
+
+
+
+
+