\n\n')
+ return ''
+ finally:
+ context.caller_stack.pop_frame()
+
+
diff --git a/Open-ILS/web/oilsweb/development.ini b/Open-ILS/web/oilsweb/development.ini
new file mode 100644
index 0000000000..b200829d86
--- /dev/null
+++ b/Open-ILS/web/oilsweb/development.ini
@@ -0,0 +1,76 @@
+#
+# oilsweb - Pylons development environment configuration
+#
+# The %(here)s variable will be replaced with the parent directory of this file
+#
+[DEFAULT]
+debug = true
+# Uncomment and replace with the address which should receive any error reports
+#email_to = you@yourdomain.com
+smtp_server = localhost
+error_email_from = paste@localhost
+
+[server:main]
+use = egg:Paste#http
+#host = 0.0.0.0
+host = 216.154.195.227
+port = 5000
+
+[app:main]
+use = egg:oilsweb
+full_stack = true
+cache_dir = %(here)s/data
+beaker.session.key = oilsweb
+beaker.session.secret = somesecret
+
+osrf_config = /openils/conf/opensrf_core.xml
+osrf_config_ctxt = config.opensrf
+oils_prefix = /oils
+oils_media_prefix = /oils/media
+oils_added_content_prefix = http://dev.gapines.org/opac/extras/ac
+oils_username = admin
+oils_password = open-ils
+oils_xsl_prefix = oilsweb/public/oils/media/xsl
+oils_xsl_acq_bib = acq-bibdata-marc.xslt
+
+
+# If you'd like to fine-tune the individual locations of the cache data dirs
+# for the Cache data, or the Session saves, un-comment the desired settings
+# here:
+#beaker.cache.data_dir = %(here)s/data/cache
+#beaker.session.data_dir = %(here)s/data/sessions
+
+# WARNING: *THE LINE BELOW MUST BE UNCOMMENTED ON A PRODUCTION ENVIRONMENT*
+# Debug mode will enable the interactive debugging tool, allowing ANYONE to
+# execute malicious code after an exception is raised.
+#set debug = false
+
+
+# Logging configuration
+[loggers]
+keys = root, oilsweb
+
+[handlers]
+keys = console
+
+[formatters]
+keys = generic
+
+[logger_root]
+level = INFO
+handlers = console
+
+[logger_oilsweb]
+level = DEBUG
+handlers =
+qualname = oilsweb
+
+[handler_console]
+class = StreamHandler
+args = (sys.stderr,)
+level = NOTSET
+formatter = generic
+
+[formatter_generic]
+format = %(asctime)s,%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
+datefmt = %H:%M:%S
diff --git a/Open-ILS/web/oilsweb/docs/index.txt b/Open-ILS/web/oilsweb/docs/index.txt
new file mode 100644
index 0000000000..00a69cc5d8
--- /dev/null
+++ b/Open-ILS/web/oilsweb/docs/index.txt
@@ -0,0 +1,12 @@
+oilsweb
++++++++
+
+This is the main index page of your documentation. It should be written in
+`reStructuredText format `_.
+
+You can generate your documentation in HTML format by running this command::
+
+ setup.py pudge
+
+For this to work you will need to download and install ``buildutils`` and
+``pudge``.
diff --git a/Open-ILS/web/oilsweb/oilsweb.egg-info/PKG-INFO b/Open-ILS/web/oilsweb/oilsweb.egg-info/PKG-INFO
new file mode 100644
index 0000000000..25517848bb
--- /dev/null
+++ b/Open-ILS/web/oilsweb/oilsweb.egg-info/PKG-INFO
@@ -0,0 +1,10 @@
+Metadata-Version: 1.0
+Name: oilsweb
+Version: 0.0.0dev
+Summary: UNKNOWN
+Home-page: UNKNOWN
+Author: UNKNOWN
+Author-email: UNKNOWN
+License: UNKNOWN
+Description: UNKNOWN
+Platform: UNKNOWN
diff --git a/Open-ILS/web/oilsweb/oilsweb.egg-info/SOURCES.txt b/Open-ILS/web/oilsweb/oilsweb.egg-info/SOURCES.txt
new file mode 100644
index 0000000000..6d9b748ca6
--- /dev/null
+++ b/Open-ILS/web/oilsweb/oilsweb.egg-info/SOURCES.txt
@@ -0,0 +1,29 @@
+MANIFEST.in
+README.txt
+setup.cfg
+setup.py
+oilsweb/__init__.py
+oilsweb/websetup.py
+oilsweb.egg-info/PKG-INFO
+oilsweb.egg-info/SOURCES.txt
+oilsweb.egg-info/dependency_links.txt
+oilsweb.egg-info/entry_points.txt
+oilsweb.egg-info/paste_deploy_config.ini_tmpl
+oilsweb.egg-info/requires.txt
+oilsweb.egg-info/top_level.txt
+oilsweb/config/__init__.py
+oilsweb/config/environment.py
+oilsweb/config/middleware.py
+oilsweb/config/routing.py
+oilsweb/controllers/__init__.py
+oilsweb/controllers/error.py
+oilsweb/controllers/template.py
+oilsweb/lib/__init__.py
+oilsweb/lib/app_globals.py
+oilsweb/lib/base.py
+oilsweb/lib/helpers.py
+oilsweb/model/__init__.py
+oilsweb/public/index.html
+oilsweb/tests/__init__.py
+oilsweb/tests/test_models.py
+oilsweb/tests/functional/__init__.py
diff --git a/Open-ILS/web/oilsweb/oilsweb.egg-info/dependency_links.txt b/Open-ILS/web/oilsweb/oilsweb.egg-info/dependency_links.txt
new file mode 100644
index 0000000000..8b13789179
--- /dev/null
+++ b/Open-ILS/web/oilsweb/oilsweb.egg-info/dependency_links.txt
@@ -0,0 +1 @@
+
diff --git a/Open-ILS/web/oilsweb/oilsweb.egg-info/entry_points.txt b/Open-ILS/web/oilsweb/oilsweb.egg-info/entry_points.txt
new file mode 100644
index 0000000000..dd90926b48
--- /dev/null
+++ b/Open-ILS/web/oilsweb/oilsweb.egg-info/entry_points.txt
@@ -0,0 +1,7 @@
+
+ [paste.app_factory]
+ main = oilsweb.config.middleware:make_app
+
+ [paste.app_install]
+ main = pylons.util:PylonsInstaller
+
\ No newline at end of file
diff --git a/Open-ILS/web/oilsweb/oilsweb.egg-info/paste_deploy_config.ini_tmpl b/Open-ILS/web/oilsweb/oilsweb.egg-info/paste_deploy_config.ini_tmpl
new file mode 100644
index 0000000000..8db796cd3f
--- /dev/null
+++ b/Open-ILS/web/oilsweb/oilsweb.egg-info/paste_deploy_config.ini_tmpl
@@ -0,0 +1,58 @@
+#
+# oilsweb - Pylons configuration
+#
+# The %(here)s variable will be replaced with the parent directory of this file
+#
+[DEFAULT]
+debug = true
+email_to = you@yourdomain.com
+smtp_server = localhost
+error_email_from = paste@localhost
+
+[server:main]
+use = egg:Paste#http
+host = 0.0.0.0
+port = 5000
+
+[app:main]
+use = egg:oilsweb
+full_stack = true
+cache_dir = %(here)s/data
+beaker.session.key = oilsweb
+beaker.session.secret = ${app_instance_secret}
+app_instance_uuid = ${app_instance_uuid}
+
+# If you'd like to fine-tune the individual locations of the cache data dirs
+# for the Cache data, or the Session saves, un-comment the desired settings
+# here:
+#beaker.cache.data_dir = %(here)s/data/cache
+#beaker.session.data_dir = %(here)s/data/sessions
+
+# WARNING: *THE LINE BELOW MUST BE UNCOMMENTED ON A PRODUCTION ENVIRONMENT*
+# Debug mode will enable the interactive debugging tool, allowing ANYONE to
+# execute malicious code after an exception is raised.
+set debug = false
+
+
+# Logging configuration
+[loggers]
+keys = root
+
+[handlers]
+keys = console
+
+[formatters]
+keys = generic
+
+[logger_root]
+level = INFO
+handlers = console
+
+[handler_console]
+class = StreamHandler
+args = (sys.stderr,)
+level = NOTSET
+formatter = generic
+
+[formatter_generic]
+format = %(asctime)s %(levelname)-5.5s [%(name)s] %(message)s
diff --git a/Open-ILS/web/oilsweb/oilsweb.egg-info/paster_plugins.txt b/Open-ILS/web/oilsweb/oilsweb.egg-info/paster_plugins.txt
new file mode 100644
index 0000000000..b3ee8d7458
--- /dev/null
+++ b/Open-ILS/web/oilsweb/oilsweb.egg-info/paster_plugins.txt
@@ -0,0 +1,3 @@
+Pylons
+WebHelpers
+PasteScript
diff --git a/Open-ILS/web/oilsweb/oilsweb.egg-info/requires.txt b/Open-ILS/web/oilsweb/oilsweb.egg-info/requires.txt
new file mode 100644
index 0000000000..a7c9299b90
--- /dev/null
+++ b/Open-ILS/web/oilsweb/oilsweb.egg-info/requires.txt
@@ -0,0 +1 @@
+Pylons>=0.9.6.1
\ No newline at end of file
diff --git a/Open-ILS/web/oilsweb/oilsweb.egg-info/top_level.txt b/Open-ILS/web/oilsweb/oilsweb.egg-info/top_level.txt
new file mode 100644
index 0000000000..94a1c0c50a
--- /dev/null
+++ b/Open-ILS/web/oilsweb/oilsweb.egg-info/top_level.txt
@@ -0,0 +1 @@
+oilsweb
diff --git a/Open-ILS/web/oilsweb/oilsweb/__init__.py b/Open-ILS/web/oilsweb/oilsweb/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/Open-ILS/web/oilsweb/oilsweb/config/__init__.py b/Open-ILS/web/oilsweb/oilsweb/config/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/Open-ILS/web/oilsweb/oilsweb/config/environment.py b/Open-ILS/web/oilsweb/oilsweb/config/environment.py
new file mode 100644
index 0000000000..848c55e004
--- /dev/null
+++ b/Open-ILS/web/oilsweb/oilsweb/config/environment.py
@@ -0,0 +1,33 @@
+"""Pylons environment configuration"""
+import os
+
+from pylons import config
+
+import oilsweb.lib.app_globals as app_globals
+import oilsweb.lib.helpers
+from oilsweb.config.routing import make_map
+
+def load_environment(global_conf, app_conf):
+ """Configure the Pylons environment via the ``pylons.config``
+ object
+ """
+ # Pylons paths
+ root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
+ paths = dict(root=root,
+ controllers=os.path.join(root, 'controllers'),
+ static_files=os.path.join(root, 'public'),
+ templates=[os.path.join(root, 'templates')])
+
+ # Initialize config with the basic options
+ config.init_app(global_conf, app_conf, package='oilsweb',
+ template_engine='mako', paths=paths)
+
+ config['routes.map'] = make_map()
+ config['pylons.g'] = app_globals.Globals()
+ config['pylons.h'] = oilsweb.lib.helpers
+
+ # Customize templating options via this variable
+ tmpl_options = config['buffet.template_options']
+
+ # CONFIGURATION OPTIONS HERE (note: all config options will override
+ # any Pylons config options)
diff --git a/Open-ILS/web/oilsweb/oilsweb/config/middleware.py b/Open-ILS/web/oilsweb/oilsweb/config/middleware.py
new file mode 100644
index 0000000000..fa98dec9f4
--- /dev/null
+++ b/Open-ILS/web/oilsweb/oilsweb/config/middleware.py
@@ -0,0 +1,57 @@
+"""Pylons middleware initialization"""
+from paste.cascade import Cascade
+from paste.registry import RegistryManager
+from paste.urlparser import StaticURLParser
+from paste.deploy.converters import asbool
+
+from pylons import config
+from pylons.error import error_template
+from pylons.middleware import error_mapper, ErrorDocuments, ErrorHandler, \
+ StaticJavascripts
+from pylons.wsgiapp import PylonsApp
+
+from oilsweb.config.environment import load_environment
+
+def make_app(global_conf, full_stack=True, **app_conf):
+ """Create a Pylons WSGI application and return it
+
+ ``global_conf``
+ The inherited configuration for this application. Normally from
+ the [DEFAULT] section of the Paste ini file.
+
+ ``full_stack``
+ Whether or not this application provides a full WSGI stack (by
+ default, meaning it handles its own exceptions and errors).
+ Disable full_stack when this application is "managed" by
+ another WSGI middleware.
+
+ ``app_conf``
+ The application's local configuration. Normally specified in the
+ [app:] section of the Paste ini file (where
+ defaults to main).
+ """
+ # Configure the Pylons environment
+ load_environment(global_conf, app_conf)
+
+ # The Pylons WSGI app
+ app = PylonsApp()
+
+ # CUSTOM MIDDLEWARE HERE (filtered by error handling middlewares)
+
+ if asbool(full_stack):
+ # Handle Python exceptions
+ app = ErrorHandler(app, global_conf, error_template=error_template,
+ **config['pylons.errorware'])
+
+ # Display error documents for 401, 403, 404 status codes (and
+ # 500 when debug is disabled)
+ app = ErrorDocuments(app, global_conf, mapper=error_mapper, **app_conf)
+
+ # Establish the Registry for this application
+ app = RegistryManager(app)
+
+ # Static files
+ javascripts_app = StaticJavascripts()
+ static_app = StaticURLParser(config['pylons.paths']['static_files'])
+ app = Cascade([static_app, javascripts_app, app])
+ return app
diff --git a/Open-ILS/web/oilsweb/oilsweb/config/routing.py b/Open-ILS/web/oilsweb/oilsweb/config/routing.py
new file mode 100644
index 0000000000..bc78800486
--- /dev/null
+++ b/Open-ILS/web/oilsweb/oilsweb/config/routing.py
@@ -0,0 +1,25 @@
+"""Routes configuration
+
+The more specific and detailed routes should be defined first so they
+may take precedent over the more generic routes. For more information
+refer to the routes manual at http://routes.groovie.org/docs/
+"""
+from pylons import config
+from routes import Mapper
+
+def make_map():
+ """Create, configure and return the routes Mapper"""
+ map = Mapper(directory=config['pylons.paths']['controllers'],
+ always_scan=config['debug'])
+
+ # The ErrorController route (handles 404/500 error pages); it should
+ # likely stay at the top, ensuring it can always be resolved
+ map.connect('error/:action/:id', controller='error')
+
+ # CUSTOM ROUTES HERE
+
+ map.connect('oils/:controller/:action')
+ #map.connect(':controller/:action/:id')
+ map.connect('*url', controller='template', action='view')
+
+ return map
diff --git a/Open-ILS/web/oilsweb/oilsweb/controllers/__init__.py b/Open-ILS/web/oilsweb/oilsweb/controllers/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/Open-ILS/web/oilsweb/oilsweb/controllers/acq.py b/Open-ILS/web/oilsweb/oilsweb/controllers/acq.py
new file mode 100644
index 0000000000..8affc7a0d0
--- /dev/null
+++ b/Open-ILS/web/oilsweb/oilsweb/controllers/acq.py
@@ -0,0 +1,76 @@
+import logging
+
+from oilsweb.lib.base import *
+import pylons, os
+import oilsweb.lib.context
+import oilsweb.lib.util
+import oilsweb.lib.acq.search
+from oilsweb.lib.context import Context, SubContext, ContextItem
+
+log = logging.getLogger(__name__)
+
+class AcqContext(SubContext):
+ ''' Define the CGI params for this application '''
+ def __init__(self):
+ self.query = ContextItem(cgi_name='acq.q')
+ self.search_class = ContextItem(cgi_name='acq.sc', multi=True)
+ self.search_source = ContextItem(cgi_name='acq.ss', multi=True)
+ self.picked_records = ContextItem(cgi_name='acq.sr', multi=True)
+
+Context.applySubContext('acq', AcqContext)
+
+
+class AcqController(BaseController):
+
+ def index(self):
+ c.oils = oilsweb.lib.context.Context.init(request)
+ return render('oils/%s/acq/index.html' % c.oils.core.skin)
+
+ def search(self):
+ c.oils = Context.init(request)
+ c.oils_z39_sources = oilsweb.lib.acq.search.fetch_z39_sources(c.oils)
+
+ sc = {}
+ for data in c.oils_z39_sources.values():
+ for key, val in data['attrs'].iteritems():
+ sc[key] = val.get('label') or key
+ c.oils_search_classes = sc
+
+ return render('oils/%s/acq/search.html' % c.oils.core.skin)
+
+
+ def pl_builder(self):
+ c.oils = oilsweb.lib.context.Context.init(request)
+ # add logic to see where we are fetching bib data from
+
+ if c.oils.acq.search_source:
+ c.oils_acq_records = self._build_z39_search(c.oils)
+
+ return render('oils/%s/acq/pl_builder.html' % c.oils.core.skin)
+
+
+
+ def _build_z39_search(self, ctx):
+
+ search = {
+ 'service' : [],
+ 'username' : [],
+ 'password' : [],
+ 'search' : {}
+ }
+
+ # collect the sources and credentials
+ for src in c.oils.acq.search_source:
+ search['service'].append(src)
+ search['username'].append("") # XXX
+ search['password'].append("") # XXX
+
+ # collect the search classes
+ for cls in c.oils.acq.search_class:
+ if request.params[cls]:
+ search['search'][cls] = request.params[cls]
+
+ return oilsweb.lib.acq.search.multi_search(ctx, search)
+
+
+
diff --git a/Open-ILS/web/oilsweb/oilsweb/controllers/error.py b/Open-ILS/web/oilsweb/oilsweb/controllers/error.py
new file mode 100644
index 0000000000..766c0447ba
--- /dev/null
+++ b/Open-ILS/web/oilsweb/oilsweb/controllers/error.py
@@ -0,0 +1,39 @@
+import os.path
+
+import paste.fileapp
+from pylons.middleware import error_document_template, media_path
+
+from oilsweb.lib.base import *
+
+class ErrorController(BaseController):
+ """Generates error documents as and when they are required.
+
+ The ErrorDocuments middleware forwards to ErrorController when error
+ related status codes are returned from the application.
+
+ This behaviour can be altered by changing the parameters to the
+ ErrorDocuments middleware in your config/middleware.py file.
+ """
+
+ def document(self):
+ """Render the error document"""
+ page = error_document_template % \
+ dict(prefix=request.environ.get('SCRIPT_NAME', ''),
+ code=request.params.get('code', ''),
+ message=request.params.get('message', ''))
+ return page
+
+ def img(self, id):
+ """Serve Pylons' stock images"""
+ return self._serve_file(os.path.join(media_path, 'img', id))
+
+ def style(self, id):
+ """Serve Pylons' stock stylesheets"""
+ return self._serve_file(os.path.join(media_path, 'style', id))
+
+ def _serve_file(self, path):
+ """Call Paste's FileApp (a WSGI application) to serve the file
+ at the specified path
+ """
+ fapp = paste.fileapp.FileApp(path)
+ return fapp(request.environ, self.start_response)
diff --git a/Open-ILS/web/oilsweb/oilsweb/controllers/template.py b/Open-ILS/web/oilsweb/oilsweb/controllers/template.py
new file mode 100644
index 0000000000..fbcbb3f66f
--- /dev/null
+++ b/Open-ILS/web/oilsweb/oilsweb/controllers/template.py
@@ -0,0 +1,27 @@
+from oilsweb.lib.base import *
+
+class TemplateController(BaseController):
+
+ def view(self, url):
+ """By default, the final controller tried to fulfill the request
+ when no other routes match. It may be used to display a template
+ when all else fails, e.g.::
+
+ def view(self, url):
+ return render('/%s' % url)
+
+ Or if you're using Mako and want to explicitly send a 404 (Not
+ Found) response code when the requested template doesn't exist::
+
+ import mako.exceptions
+
+ def view(self, url):
+ try:
+ return render('/%s' % url)
+ except mako.exceptions.TopLevelLookupException:
+ abort(404)
+
+ By default this controller aborts the request with a 404 (Not
+ Found)
+ """
+ abort(404)
diff --git a/Open-ILS/web/oilsweb/oilsweb/lib/__init__.py b/Open-ILS/web/oilsweb/oilsweb/lib/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/Open-ILS/web/oilsweb/oilsweb/lib/acq/__init__.py b/Open-ILS/web/oilsweb/oilsweb/lib/acq/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/Open-ILS/web/oilsweb/oilsweb/lib/acq/search.py b/Open-ILS/web/oilsweb/oilsweb/lib/acq/search.py
new file mode 100644
index 0000000000..a21225b1e4
--- /dev/null
+++ b/Open-ILS/web/oilsweb/oilsweb/lib/acq/search.py
@@ -0,0 +1,44 @@
+import os
+import oilsweb.lib.context
+import osrf.ses
+import osrf.xml_obj
+import oils.const
+import osrf.log
+
+EG_Z39_SEARCH = 'open-ils.search.z3950.search_class'
+_z_sources = None
+
+def fetch_z39_sources(ctx):
+ global _z_sources
+ if _z_sources:
+ return _z_sources
+ _z_sources = osrf.ses.AtomicRequest(
+ 'open-ils.search',
+ 'open-ils.search.z3950.retrieve_services', ctx.core.authtoken)
+ return _z_sources
+
+def flatten_record(marcxml):
+ import pylons
+ xslFile = os.path.join(os.getcwd(), pylons.config['oils_xsl_prefix'], pylons.config['oils_xsl_acq_bib'])
+ xformed = oilsweb.lib.util.apply_xsl(marcxml, xslFile)
+ return osrf.xml_obj.XMLFlattener(xformed).parse()
+
+def multi_search(ctx, search):
+ ses = osrf.ses.ClientSession(oils.const.OILS_APP_SEARCH)
+ req = ses.request(EG_Z39_SEARCH, ctx.core.authtoken, search)
+ osrf.log.log_debug("sending " + unicode(search))
+
+ results = []
+ while not req.complete:
+ resp = req.recv(60)
+ if not resp:
+ break
+ res = resp.content()
+ for rec in res['records']:
+ rec['extracts'] = flatten_record(rec['marcxml'])
+ results.append(res)
+
+ osrf.log.log_debug("got " + unicode(results))
+ return results
+
+
diff --git a/Open-ILS/web/oilsweb/oilsweb/lib/app_globals.py b/Open-ILS/web/oilsweb/oilsweb/lib/app_globals.py
new file mode 100644
index 0000000000..77ad4eddd9
--- /dev/null
+++ b/Open-ILS/web/oilsweb/oilsweb/lib/app_globals.py
@@ -0,0 +1,14 @@
+"""The application's Globals object"""
+from pylons import config
+import oilsweb.lib.util
+
+class Globals(object):
+ """Globals acts as a container for objects available throughout the
+ life of the application
+ """
+
+ def __init__(self):
+ #oilsweb.lib.util.childInit()
+ self.oils_authtoken = None
+
+
diff --git a/Open-ILS/web/oilsweb/oilsweb/lib/base.py b/Open-ILS/web/oilsweb/oilsweb/lib/base.py
new file mode 100644
index 0000000000..4381f60bda
--- /dev/null
+++ b/Open-ILS/web/oilsweb/oilsweb/lib/base.py
@@ -0,0 +1,27 @@
+"""The base Controller API
+
+Provides the BaseController class for subclassing, and other objects
+utilized by Controllers.
+"""
+from pylons import c, cache, config, g, request, response, session
+from pylons.controllers import WSGIController
+from pylons.controllers.util import abort, etag_cache, redirect_to
+from pylons.decorators import jsonify, validate
+from pylons.i18n import _, ungettext, N_
+from pylons.templating import render
+
+import oilsweb.lib.helpers as h
+import oilsweb.model as model
+
+class BaseController(WSGIController):
+
+ def __call__(self, environ, start_response):
+ """Invoke the Controller"""
+ # WSGIController.__call__ dispatches to the Controller method
+ # the request is routed to. This routing information is
+ # available in environ['pylons.routes_dict']
+ return WSGIController.__call__(self, environ, start_response)
+
+# Include the '_' function in the public names
+__all__ = [__name for __name in locals().keys() if not __name.startswith('_') \
+ or __name == '_']
diff --git a/Open-ILS/web/oilsweb/oilsweb/lib/context.py b/Open-ILS/web/oilsweb/oilsweb/lib/context.py
new file mode 100644
index 0000000000..30c33fc63e
--- /dev/null
+++ b/Open-ILS/web/oilsweb/oilsweb/lib/context.py
@@ -0,0 +1,99 @@
+from oilsweb.lib.util import childInit
+import pylons.config
+import cgi
+
+_context = None
+_subContexts = {}
+
+class ContextItem(object):
+ def __init__(self, **kwargs):
+ self.app = None
+ self.name = kwargs.get('name')
+ self.cgi_name = kwargs.get('cgi_name')
+ self.default_value = kwargs.get('default_value')
+ self.qname = None
+ self.multi = kwargs.get('multi')
+
+class Context(object):
+ def __init__(self):
+ self._fields = []
+
+ def wrap(self):
+ return {'oils': self}
+
+ def applySubContext(self, app, subContext):
+ setattr(self, app, subContext)
+
+ def make_query_string(self):
+ q = ''
+ for f in self._fields:
+ if f.cgi_name:
+ val = getattr(getattr(self, f.app), f.name)
+ if val != f.default_value:
+ if isinstance(val, list):
+ for v in val:
+ q += f.cgi_name+'='+cgi.escape(v)+'&'
+ else:
+ q += f.cgi_name+'='+cgi.escape(val)+'&'
+ if len(q) > 0: q = q[:-1] # strip the trailing &
+ return q
+
+ @staticmethod
+ def applySubContext(app, ctx):
+ global _subContexts
+ _subContexts[app] = ctx
+
+ @staticmethod
+ def getContext():
+ global _context
+ return _context
+
+ @staticmethod
+ def init(req):
+ global _context, _subContexts
+ c = _context = Context()
+ childInit()
+
+ for app, ctx in _subContexts.iteritems():
+ ctx = ctx()
+ setattr(c, app, ctx)
+ for name in ctx._fields():
+ item = getattr(ctx, name)
+ item.app = app
+ item.name = name
+ c._fields.append(item)
+ if item.cgi_name and item.cgi_name in req.params:
+ if item.multi:
+ setattr(getattr(c, app), name, req.params.getall(item.cgi_name))
+ else:
+ setattr(getattr(c, app), name, req.params[item.cgi_name])
+ else:
+ setattr(getattr(c, app), name, item.default_value)
+
+ # store the metatdata at _
+ setattr(getattr(c, app), "%s_" % name, item)
+
+ c.core.prefix = pylons.config['oils_prefix']
+ c.core.media_prefix = pylons.config['oils_media_prefix']
+ c.core.ac_prefix = pylons.config['oils_added_content_prefix']
+
+ c.core.skin = 'default' # XXX
+ c.core.theme = 'default' # XXX
+
+ return c
+
+
+class SubContext(object):
+ def _fields(self):
+ return [ f for f in dir(self) if f[0:1] != '_' ]
+
+class CoreContext(SubContext):
+ def __init__(self):
+ self.prefix = ContextItem()
+ self.media_prefix = ContextItem()
+ self.ac_prefix = ContextItem()
+ self.skin = ContextItem()
+ self.theme = ContextItem()
+ self.authtoken = ContextItem(cgi_name='ses')
+Context.applySubContext('core', CoreContext)
+
diff --git a/Open-ILS/web/oilsweb/oilsweb/lib/helpers.py b/Open-ILS/web/oilsweb/oilsweb/lib/helpers.py
new file mode 100644
index 0000000000..0eb7c8fcca
--- /dev/null
+++ b/Open-ILS/web/oilsweb/oilsweb/lib/helpers.py
@@ -0,0 +1,6 @@
+"""Helper functions
+
+Consists of functions to typically be used within templates, but also
+available to Controllers. This module is available to both as 'h'.
+"""
+from webhelpers import *
diff --git a/Open-ILS/web/oilsweb/oilsweb/lib/util.py b/Open-ILS/web/oilsweb/oilsweb/lib/util.py
new file mode 100644
index 0000000000..a9aa4d5bcf
--- /dev/null
+++ b/Open-ILS/web/oilsweb/oilsweb/lib/util.py
@@ -0,0 +1,43 @@
+import pylons.config
+import libxml2, libxslt
+import oils.utils.utils
+
+WEB_ROOT='oils'
+
+
+def makeTemplatePath(ctx, tail):
+ return '%s/%s/%s' % (WEB_ROOT, ctx.core.skin, tail)
+
+def childInit():
+ ''' Global child-init handler.
+
+ 1. Connects to the OpenSRF network. Note that the OpenSRF
+ layer ensures that there is only one connection per thread.
+ 2. Parses the IDL file '''
+ import osrf.system, osrf.set, oils.utils.idl, oils.utils.csedit, osrf.cache
+ osrf.system.connect(pylons.config['osrf_config'], pylons.config['osrf_config_ctxt'])
+ oils.utils.idl.oilsParseIDL()
+ oils.utils.csedit.oilsLoadCSEditor()
+
+ # live in opensrf somewhere
+ servers = osrf.set.get('cache.global.servers.server')
+ if not isinstance(servers, list):
+ servers = [servers]
+ osrf.cache.CacheClient.connect(servers)
+
+
+
+_parsedSheets = {}
+def apply_xsl(xmlStr, xslFile, xslParams={}):
+ doc = libxml2.parseDoc(xmlStr)
+ stylesheet = _parsedSheets.get(xslFile)
+
+ if not stylesheet:
+ styledoc = _parsedSheets.get(xslFile) or libxml2.parseFile(xslFile)
+ stylesheet = libxslt.parseStylesheetDoc(styledoc)
+ _parsedSheets[xslFile] = stylesheet
+
+ result = stylesheet.applyStylesheet(doc, xslParams)
+ return stylesheet.saveResultToString(result)
+
+
diff --git a/Open-ILS/web/oilsweb/oilsweb/model/__init__.py b/Open-ILS/web/oilsweb/oilsweb/model/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/Open-ILS/web/oilsweb/oilsweb/public/index.html b/Open-ILS/web/oilsweb/oilsweb/public/index.html
new file mode 100644
index 0000000000..defce375d3
--- /dev/null
+++ b/Open-ILS/web/oilsweb/oilsweb/public/index.html
@@ -0,0 +1,108 @@
+
+
+
+ Pylons Default Page
+
+
+
+
+
Welcome to your Pylons Web Application
+
+
Weren't expecting to see this page?
+
+
The oilsweb/public/ directory is searched for static files
+ before your controllers are run. Remove this file (oilsweb/public/index.html)
+ and edit the routes in oilsweb/config/routing.py to point the
+ root path to a 'hello' controller we'll create below:
+
You're now ready to start creating your own web application. To create a 'hello' controller,
+ run the following command in your project's root directory:
+
+oilsweb$ paster controller hello
+
+
+ This generates the following the following code in oilsweb/controllers/hello.py:
+
This controller simply prints out 'Hello World' to the browser. Pylons' default routes
+ automatically set up this controller to respond at the /hello URL.
+ With the additional route described above, this controller will also respond at the
+ root path.
+
+
+
Using a template
+
To call a template and do something a little more complex, this following example
+ shows how to print out some request information from a
+ Mako template.
+
+
Create a serverinfo.mako file in your project's oilsweb/templates/
+ directory with the following contents:
+
+
+<h2>
+Server info for ${request.host}
+</h2>
+
+<p>
+The URL you called: ${h.url_for()}
+</p>
+
+<p>
+The name you set: ${c.name}
+</p>
+
+<p>The WSGI environ:<br />
+<pre>${c.pretty_environ}</pre>
+</p>
+
+
+Then add the following to your 'hello' controller class:
+