From 73a819f877b138e0874cad26993b0ac30a18f6e0 Mon Sep 17 00:00:00 2001 From: phasefx Date: Sat, 31 Jan 2009 21:16:31 +0000 Subject: [PATCH] Merged revisions 11987-11992,11995,11998,12001-12007,12010-12011,12014-12019,12022 via svnmerge from svn://svn.open-ils.org/ILS/trunk ........ r11987 | miker | 2009-01-26 21:15:09 -0500 (Mon, 26 Jan 2009) | 1 line initial single-event firing module ........ r11988 | miker | 2009-01-26 21:15:47 -0500 (Mon, 26 Jan 2009) | 1 line more states available to events ........ r11989 | miker | 2009-01-26 21:21:33 -0500 (Mon, 26 Jan 2009) | 1 line throw errors when we cannot update the event state ........ r11990 | miker | 2009-01-26 21:23:18 -0500 (Mon, 26 Jan 2009) | 1 line for now use die instead of throw ........ r11991 | dbs | 2009-01-26 22:28:14 -0500 (Mon, 26 Jan 2009) | 2 lines Add a little sample of geospatial data for FGDC/CSDGM transform fun ........ r11992 | dbs | 2009-01-26 22:33:32 -0500 (Mon, 26 Jan 2009) | 3 lines We need to expose vandelay and permacrud as public services. Sort the list of public services so it's easy to skim through. ........ r11995 | dbs | 2009-01-26 23:30:46 -0500 (Mon, 26 Jan 2009) | 2 lines Fix regression that prevents anyone from viewing reports ........ r11998 | dbs | 2009-01-27 08:39:52 -0500 (Tue, 27 Jan 2009) | 1 line Second part of fix for viewing reports, related to r11995 ........ r12001 | miker | 2009-01-27 20:44:05 -0500 (Tue, 27 Jan 2009) | 1 line add specialized module namespace overrides ........ r12002 | miker | 2009-01-27 20:44:48 -0500 (Tue, 27 Jan 2009) | 1 line refactor the general object layout; use fleshing where possible ........ r12003 | miker | 2009-01-27 20:46:14 -0500 (Tue, 27 Jan 2009) | 1 line Add some basic dummy handlers (fourtytwo, NOOP_True and NOOP_False) for each module type ........ r12004 | miker | 2009-01-27 20:59:53 -0500 (Tue, 27 Jan 2009) | 1 line allow either fleshed or unfleshed module objects ........ r12005 | miker | 2009-01-27 21:01:24 -0500 (Tue, 27 Jan 2009) | 1 line remove (now) needless fleshing ........ r12006 | miker | 2009-01-27 21:17:38 -0500 (Tue, 27 Jan 2009) | 1 line example validators; adding noop modules to the schema creation script ........ r12007 | miker | 2009-01-28 14:02:01 -0500 (Wed, 28 Jan 2009) | 1 line can not retrieve an object before we create it ... doh! (thanks, Laura, for catching this) ........ r12010 | miker | 2009-01-29 10:27:50 -0500 (Thu, 29 Jan 2009) | 1 line always assume disconnect succeeds ... for now ........ r12011 | phasefx | 2009-01-29 14:11:55 -0500 (Thu, 29 Jan 2009) | 1 line this file doesn't follow the convention used elsewhere.. so wrong path to this object ........ r12014 | miker | 2009-01-29 15:02:17 -0500 (Thu, 29 Jan 2009) | 1 line output the deleted column from fast-extract; use said column in marc_add_ids ........ r12015 | miker | 2009-01-29 15:05:29 -0500 (Thu, 29 Jan 2009) | 1 line good-ify the output xml ........ r12016 | miker | 2009-01-30 16:36:44 -0500 (Fri, 30 Jan 2009) | 1 line adding support for jump attribute, for remote indirection; fixing incorrect comment ........ r12017 | miker | 2009-01-30 16:37:59 -0500 (Fri, 30 Jan 2009) | 1 line adding Scott's dump_idl utility, and adding jump support; makefile support for dump_idl ........ r12018 | miker | 2009-01-30 16:38:47 -0500 (Fri, 30 Jan 2009) | 1 line asva needs the jump attribute to from question to survey to owner ........ r12019 | miker | 2009-01-30 18:02:18 -0500 (Fri, 30 Jan 2009) | 1 line teaching the pcrud personallity of cstore how to use the jump attr in permacrud action context elements ........ r12022 | miker | 2009-01-31 15:50:17 -0500 (Sat, 31 Jan 2009) | 1 line adding jump attr to the xsd; adding jump to asva ........ git-svn-id: svn://svn.open-ils.org/ILS/branches/staff-client-experiment@12023 dcc99617-32d9-48b4-a31d-7c20da2025e4 --- Open-ILS/examples/fm_IDL.xml | 16 + Open-ILS/examples/opensrf_core.xml.example | 12 +- Open-ILS/examples/permacrud.xsd | 1 + Open-ILS/src/c-apps/Makefile.am | 6 +- Open-ILS/src/c-apps/dump_idl.c | 412 +++++++++++++++++++++ Open-ILS/src/c-apps/oils_cstore.c | 53 ++- Open-ILS/src/c-apps/oils_idl-core.c | 5 +- Open-ILS/src/extras/fast-extract | 6 +- Open-ILS/src/extras/import/marc_add_ids | 7 +- .../OpenILS/Application/Trigger/Cleanup.pm | 5 + .../OpenILS/Application/Trigger/Collector.pm | 3 + .../perlmods/OpenILS/Application/Trigger/Event.pm | 377 +++++++++++++++++++ .../OpenILS/Application/Trigger/ModRunner.pm | 38 +- .../OpenILS/Application/Trigger/Reactor.pm | 5 + .../OpenILS/Application/Trigger/Validator.pm | 29 ++ Open-ILS/src/sql/Pg/400.schema.action_trigger.sql | 14 +- Open-ILS/tests/datasets/README | 1 + Open-ILS/tests/datasets/map_data.mrc | 1 + Open-ILS/web/js/dojo/openils/PermaCrud.js | 4 +- Open-ILS/web/reports/oils_rpt_common.xhtml | 1 + Open-ILS/web/reports/oils_rpt_folder_window.js | 2 +- 21 files changed, 968 insertions(+), 30 deletions(-) create mode 100644 Open-ILS/src/c-apps/dump_idl.c create mode 100644 Open-ILS/src/perlmods/OpenILS/Application/Trigger/Cleanup.pm create mode 100644 Open-ILS/src/perlmods/OpenILS/Application/Trigger/Collector.pm create mode 100644 Open-ILS/src/perlmods/OpenILS/Application/Trigger/Event.pm create mode 100644 Open-ILS/src/perlmods/OpenILS/Application/Trigger/Reactor.pm create mode 100644 Open-ILS/src/perlmods/OpenILS/Application/Trigger/Validator.pm create mode 100644 Open-ILS/tests/datasets/map_data.mrc diff --git a/Open-ILS/examples/fm_IDL.xml b/Open-ILS/examples/fm_IDL.xml index cad2d63c3a..e90a6c1a7a 100644 --- a/Open-ILS/examples/fm_IDL.xml +++ b/Open-ILS/examples/fm_IDL.xml @@ -672,6 +672,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + @@ -681,6 +682,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + @@ -3307,6 +3309,20 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + + + + + + + + + + + + + + diff --git a/Open-ILS/examples/opensrf_core.xml.example b/Open-ILS/examples/opensrf_core.xml.example index 9b9ecd9645..889e525452 100644 --- a/Open-ILS/examples/opensrf_core.xml.example +++ b/Open-ILS/examples/opensrf_core.xml.example @@ -19,15 +19,17 @@ Example OpenSRF bootstrap configuration file for Evergreen opensrf.math - open-ils.cat - open-ils.supercat - open-ils.search - open-ils.circ open-ils.actor open-ils.auth - open-ils.fielder + open-ils.cat + open-ils.circ open-ils.collections + open-ils.fielder + open-ils.permacrud open-ils.reporter + open-ils.search + open-ils.supercat + open-ils.vandelay diff --git a/Open-ILS/examples/permacrud.xsd b/Open-ILS/examples/permacrud.xsd index d819ae05fd..451ac4b8f2 100644 --- a/Open-ILS/examples/permacrud.xsd +++ b/Open-ILS/examples/permacrud.xsd @@ -34,6 +34,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + diff --git a/Open-ILS/src/c-apps/Makefile.am b/Open-ILS/src/c-apps/Makefile.am index 69b3fc1d47..b8e6d1c50e 100644 --- a/Open-ILS/src/c-apps/Makefile.am +++ b/Open-ILS/src/c-apps/Makefile.am @@ -7,11 +7,15 @@ AM_CFLAGS = $(DEF_CFLAGS) -DOSRF_LOG_PARAMS -I@top_srcdir@/include/ AM_LDFLAGS = $(DEF_LDFLAGS) -L$(DBI_LIBS) -lopensrf -bin_PROGRAMS = oils_dataloader +bin_PROGRAMS = oils_dataloader dump_idl oils_dataloader_SOURCES = oils_dataloader.c oils_dataloader_LDFLAGS = $(AM_LDFLAGS) -loils_idl oils_dataloader_DEPENDENCIES = liboils_idl.la liboils_utils.la +dump_idl_SOURCES = dump_idl.c +dump_idl_LDFLAGS = $(AM_LDFLAGS) -loils_idl +dump_idl_DEPENDENCIES = liboils_idl.la liboils_utils.la + lib_LTLIBRARIES = liboils_idl.la liboils_utils.la oils_cstore.la oils_rstore.la oils_pcrud.la oils_auth.la liboils_idl_la_SOURCES = oils_idl-core.c diff --git a/Open-ILS/src/c-apps/dump_idl.c b/Open-ILS/src/c-apps/dump_idl.c new file mode 100644 index 0000000000..3c8c36017e --- /dev/null +++ b/Open-ILS/src/c-apps/dump_idl.c @@ -0,0 +1,412 @@ +/* +* C Implementation: dump_idl +* +* Description: +* +* +* Author: Scott McKellar , (C) 2009 +* +* Copyright: See COPYING file that comes with this distribution +* +*/ + +#include +#include +#include +#include +#include + +static void dump_idl( osrfHash* IDLHash ); +static void dump_class( osrfHash* class_hash, const char* class_name ); +static void dump_fields( osrfHash* field_hash ); +static void dump_one_field( osrfHash* field_hash, const char* field_name ); +static void dump_links( osrfHash* links_hash ); +static void dump_one_link( osrfHash* link_hash, const char* link_name ); +static void dump_permacrud( osrfHash* pcrud_hash ); +static void dump_action( osrfHash* action_hash, const char* action_name ); +static void dump_foreign_context( osrfHash* fc_hash ); +static void dump_fc_class( osrfHash* fc_class_hash, const char* class_name ); +static void dump_string_array( + osrfStringArray* sarr, const char* name, const char* indent ); + +int main( int argc, char* argv[] ) { + int rc = 0; + + // Suppress informational messages + osrfLogSetLevel( OSRF_LOG_WARNING ); + + // Get name of IDL file, if specified on command line + const char* IDL_filename = NULL; + int filename_expected = 0; // boolean + int i; + for( i = 1; i < argc; ++i ) { + const char* arg = argv[ i ]; + printf( "%s\n", arg ); + if( filename_expected ) { + IDL_filename = arg; + filename_expected = 0; + } else { + if( '-' == arg[ 0 ] && 'f' == arg[1] ) { + if( IDL_filename ) { + fprintf( stderr, "Only one IDL file may be specified\n" ); + return 1; + } else { + if( arg[ 2 ] ) + IDL_filename = arg + 2; + else + filename_expected = 1; + } + } + else + break; + } + } + + if( filename_expected ) { + fprintf( stderr, "IDL filename expected on command line, not found\n" ); + return 1; + } + + // No filename? Look in the environment + if( !IDL_filename ) + IDL_filename = getenv( "OILS_IDL_FILENAME" ); + + // Still no filename? Apply a default + if( !IDL_filename ) + IDL_filename = "/openils/conf/fm_IDL.xml"; + + printf( "IDL filename: %s\n", IDL_filename ); + + osrfHash* IDL = oilsIDLInit( IDL_filename ); + if( NULL == IDL ) { + fputs( "Failed to build IDL\n", stderr ); + rc = 1; + } + + if( i >= argc ) + // No classes specified? Dump them all + dump_idl( IDL ); + else do { + // Dump the requested classes + dump_class( osrfHashGet( IDL, argv[ i ] ), argv[ i ] ); + ++i; + } while( i < argc ); + + return rc; +} + +static void dump_idl( osrfHash* IDLHash ) { + if( NULL == IDLHash ) + return; + + if( 0 == osrfHashGetCount( IDLHash ) ) + return; + + osrfHashIterator* iter = osrfNewHashIterator( IDLHash ); + osrfHash* class_hash = NULL; + + // Dump each class + for( ;; ) { + class_hash = osrfHashIteratorNext( iter ); + if( class_hash ) + dump_class( class_hash, osrfHashIteratorKey( iter ) ); + else + break; + } + + osrfHashIteratorFree( iter ); +} + +static void dump_class( osrfHash* class_hash, const char* class_name ) +{ + if( !class_hash || !class_name ) + return; + + if( 0 == osrfHashGetCount( class_hash ) ) + return; + + printf( "Class %s\n", class_name ); + const char* indent = " "; + + osrfHashIterator* iter = osrfNewHashIterator( class_hash ); + + // Dump each attribute, etc. of the class hash + for( ;; ) { + void* class_attr = osrfHashIteratorNext( iter ); + if( class_attr ) { + const char* attr_name = osrfHashIteratorKey( iter ); + if( !strcmp( attr_name, "classname" ) ) + printf( "%s%s: %s\n", indent, attr_name, (char*) class_attr ); + else if( !strcmp( attr_name, "fieldmapper" ) ) + printf( "%s%s: %s\n", indent, attr_name, (char*) class_attr ); + else if( !strcmp( attr_name, "tablename" ) ) + printf( "%s%s: %s\n", indent, attr_name, (char*) class_attr ); + else if( !strcmp( attr_name, "virtual" ) ) + printf( "%s%s: %s\n", indent, attr_name, (char*) class_attr ); + else if( !strcmp( attr_name, "controller" ) ) + dump_string_array( (osrfStringArray*) class_attr, attr_name, indent ); + else if( !strcmp( attr_name, "fields" ) ) + dump_fields( (osrfHash*) class_attr ); + else if( !strcmp( attr_name, "links" ) ) + dump_links( (osrfHash*) class_attr ); + else if( !strcmp( attr_name, "primarykey" ) ) + printf( "%s%s: %s\n", indent, attr_name, (char*) class_attr ); + else if( !strcmp( attr_name, "sequence" ) ) + printf( "%s%s: %s\n", indent, attr_name, (char*) class_attr ); + else if( !strcmp( attr_name, "permacrud" ) ) + dump_permacrud( (osrfHash*) class_attr ); + else if( !strcmp( attr_name, "source_definition" ) ) + printf( "%s%s:\n%s\n", indent, attr_name, (char*) class_attr ); + else + printf( "%s%s (unknown)\n", indent, attr_name ); + } else + break; + } +} + +static void dump_fields( osrfHash* fields_hash ) { + if( NULL == fields_hash ) + return; + + if( 0 == osrfHashGetCount( fields_hash ) ) + return; + + fputs( " fields\n", stdout ); + + osrfHashIterator* iter = osrfNewHashIterator( fields_hash ); + osrfHash* fields_attr = NULL; + + // Dump each field + for( ;; ) { + fields_attr = osrfHashIteratorNext( iter ); + if( fields_attr ) + dump_one_field( fields_attr, osrfHashIteratorKey( iter ) ); + else + break; + } + + osrfHashIteratorFree( iter ); +} + +static void dump_one_field( osrfHash* field_hash, const char* field_name ) { + if( !field_hash || !field_name ) + return; + + if( 0 == osrfHashGetCount( field_hash ) ) + return; + + printf( " %s\n", field_name ); + + osrfHashIterator* iter = osrfNewHashIterator( field_hash ); + const char* field_attr = NULL; + const char* indent = " "; + + // Dump each field attribute + for( ;; ) { + field_attr = osrfHashIteratorNext( iter ); + if( field_attr ) + printf( "%s%s: %s\n", indent, osrfHashIteratorKey( iter ), field_attr ); + else + break; + } + + osrfHashIteratorFree( iter ); +} + +static void dump_links( osrfHash* links_hash ) { + if( NULL == links_hash ) + return; + + if( 0 == osrfHashGetCount( links_hash ) ) + return; + + fputs( " links\n", stdout ); + + osrfHashIterator* iter = osrfNewHashIterator( links_hash ); + osrfHash* links_attr = NULL; + + // Dump each link + for( ;; ) { + links_attr = osrfHashIteratorNext( iter ); + if( links_attr ) + dump_one_link( links_attr, osrfHashIteratorKey( iter ) ); + else + break; + } + + osrfHashIteratorFree( iter ); +} + +static void dump_one_link( osrfHash* link_hash, const char* link_name ) { + if( !link_hash || !link_name ) + return; + + if( 0 == osrfHashGetCount( link_hash ) ) + return; + + printf( " %s\n", link_name ); + + osrfHashIterator* iter = osrfNewHashIterator( link_hash ); + const void* link_attr = NULL; + const char* indent = " "; + + // Dump each link attribute + for( ;; ) { + link_attr = osrfHashIteratorNext( iter ); + if( link_attr ) { + const char* link_attr_name = osrfHashIteratorKey( iter ); + if( !strcmp( link_attr_name, "reltype" ) ) + printf( "%s%s: %s\n", indent, link_attr_name, (char*) link_attr ); + else if( !strcmp( link_attr_name, "key" ) ) + printf( "%s%s: %s\n", indent, link_attr_name, (char*) link_attr ); + else if( !strcmp( link_attr_name, "class" ) ) + printf( "%s%s: %s\n", indent, link_attr_name, (char*) link_attr ); + else if( !strcmp( link_attr_name, "map" ) ) + dump_string_array( (osrfStringArray*) link_attr, link_attr_name, indent ); + else if( !strcmp( link_attr_name, "field" ) ) + printf( "%s%s: %s\n", indent, link_attr_name, (char*) link_attr ); + else + printf( "%s%s (unknown)\n", indent, link_attr_name ); + } else + break; + } + + osrfHashIteratorFree( iter ); +} + +static void dump_permacrud( osrfHash* pcrud_hash ) { + if( NULL == pcrud_hash ) + return; + + if( 0 == osrfHashGetCount( pcrud_hash ) ) + return; + + fputs( " permacrud\n", stdout ); + + osrfHashIterator* iter = osrfNewHashIterator( pcrud_hash ); + osrfHash* pcrud_attr = NULL; + + // Dump each action + for( ;; ) { + pcrud_attr = osrfHashIteratorNext( iter ); + if( pcrud_attr ) + dump_action( pcrud_attr, osrfHashIteratorKey( iter ) ); + else + break; + } + + osrfHashIteratorFree( iter ); +} + +static void dump_action( osrfHash* action_hash, const char* action_name ) { + if( !action_hash || !action_name ) + return; + + if( 0 == osrfHashGetCount( action_hash ) ) + return; + + printf( " %s\n", action_name ); + + osrfHashIterator* iter = osrfNewHashIterator( action_hash ); + void* action_attr = NULL; + const char* indent = " "; + + // Dump each attribute of the action + for( ;; ) { + action_attr = osrfHashIteratorNext( iter ); + if( action_attr ) { + const char* attr_name = osrfHashIteratorKey( iter ); + if( !strcmp( attr_name, "permission" ) ) + dump_string_array( action_attr, attr_name, indent ); + else if( !strcmp( attr_name, "global_required" ) ) + printf( "%s%s: %s\n", indent, attr_name, (char*) action_attr ); + else if( !strcmp( attr_name, "local_context" ) ) + dump_string_array( action_attr, attr_name, indent ); + else if( !strcmp( attr_name, "foreign_context" ) ) + dump_foreign_context( action_attr ); + else + printf( "%s%s (unknown)\n", indent, attr_name ); + } else + break; + } + + osrfHashIteratorFree( iter ); +} + +static void dump_foreign_context( osrfHash* fc_hash ) { + if( !fc_hash ) + return; + + if( 0 == osrfHashGetCount( fc_hash ) ) + return; + + fputs( " foreign_context\n", stdout ); + + osrfHashIterator* iter = osrfNewHashIterator( fc_hash ); + osrfHash* fc_attr = NULL; + + // Dump each foreign context attribute + for( ;; ) { + fc_attr = osrfHashIteratorNext( iter ); + if( fc_attr ) + dump_fc_class( (osrfHash*) fc_attr, osrfHashIteratorKey( iter ) ); + else + break; + } + + osrfHashIteratorFree( iter ); +} + +static void dump_fc_class( osrfHash* fc_class_hash, const char* class_name ) +{ + if( ! fc_class_hash ) + return; + + if( 0 == osrfHashGetCount( fc_class_hash ) ) + return; + + printf( " %s\n", class_name ); + + osrfHashIterator* iter = osrfNewHashIterator( fc_class_hash ); + void* fc_class_attr = NULL; + const char* indent = " "; + + // Dump each foreign context attribute + for( ;; ) { + fc_class_attr = osrfHashIteratorNext( iter ); + if( fc_class_attr ) { + const char* fc_class_attr_name = osrfHashIteratorKey( iter ); + if( !strcmp( fc_class_attr_name, "field" ) ) + printf( "%s%s: %s\n", indent, fc_class_attr_name, (const char*) fc_class_attr ); + else if( !strcmp( fc_class_attr_name, "fkey" ) ) + printf( "%s%s: %s\n", indent, fc_class_attr_name, (const char*) fc_class_attr ); + else if( !strcmp( fc_class_attr_name, "jump" ) ) + dump_string_array( (osrfStringArray*) fc_class_attr, fc_class_attr_name, indent ); + else if( !strcmp( fc_class_attr_name, "context" ) ) + dump_string_array( (osrfStringArray*) fc_class_attr, fc_class_attr_name, indent ); + else + printf( "%s%s\n", indent, fc_class_attr_name ); + } else + break; + } + + osrfHashIteratorFree( iter ); +} + +static void dump_string_array( + osrfStringArray* sarr, const char* name, const char* indent ) { + if( !sarr || !name || !indent ) + return; + + int size = sarr->size; + + // Ignore an empty array + if( 0 == size ) + return; + + printf( "%s%s (string array)\n", indent, name ); + + int i; + for( i = 0; i < size; ++i ) + printf( "%s\t%s\n", indent, osrfStringArrayGetString( sarr, i ) ); +} diff --git a/Open-ILS/src/c-apps/oils_cstore.c b/Open-ILS/src/c-apps/oils_cstore.c index cf56c8c293..c93da144af 100644 --- a/Open-ILS/src/c-apps/oils_cstore.c +++ b/Open-ILS/src/c-apps/oils_cstore.c @@ -874,12 +874,13 @@ static int verifyObjectPCRUD ( osrfMethodContext* ctx, const jsonObject* obj ) osrfHash* meta = (osrfHash*) ctx->method->userData; osrfHash* class = osrfHashGet( meta, "class" ); char* method_type = strdup( osrfHashGet(meta, "methodtype") ); - int fetch = 1; + int fetch = 0; if ( ( *method_type == 's' || *method_type == 'i' ) ) { free(method_type); - method_type = strdup("retrieve"); - fetch = 0; // don't go to the db for the object for retrieve-type methods + method_type = strdup("retrieve"); // search and id_list are equivelant to retrieve for this + } else if ( *method_type == 'u' || *method_type == 'd' ) { + fetch = 1; // MUST go to the db for the object for update and delete } osrfHash* pcrud = osrfHashGet( osrfHashGet(class, "permacrud"), method_type ); @@ -1059,11 +1060,44 @@ static int verifyObjectPCRUD ( osrfMethodContext* ctx, const jsonObject* obj ) &err ); - jsonObject* _fparam = jsonObjectGetIndex(_list, 0); - + jsonObject* _fparam = jsonObjectClone(jsonObjectGetIndex(_list, 0)); + jsonObjectFree(_tmp_params); + jsonObjectFree(_list); + + osrfStringArray* jump_list = osrfHashGet(fcontext, "jump"); + + if (_fparam && jump_list) { + char* flink = NULL; + int k = 0; + while ( (flink = osrfStringArrayGetString(jump_list, k++)) && _fparam ) { + free(foreign_pkey_value); + + osrfHash* foreign_link_hash = oilsIDLFindPath( "/%s/links/%s", _fparam->classname, flink ); + + foreign_pkey_value = oilsFMGetString(_fparam, flink); + foreign_pkey = osrfHashGet( foreign_link_hash, "key" ); + + _tmp_params = jsonParseStringFmt( + "[{\"%s\":\"%s\"}]", + foreign_pkey, + foreign_pkey_value + ); + + _list = doFieldmapperSearch( + ctx, + osrfHashGet( oilsIDL(), osrfHashGet( foreign_link_hash, "class" ) ), + _tmp_params, + &err + ); + + _fparam = jsonObjectClone(jsonObjectGetIndex(_list, 0)); + jsonObjectFree(_tmp_params); + jsonObjectFree(_list); + } + } + + if (!_fparam) { - jsonObjectFree(_tmp_params); - jsonObjectFree(_list); growing_buffer* msg = buffer_init(128); buffer_fadd( @@ -1091,7 +1125,6 @@ static int verifyObjectPCRUD ( osrfMethodContext* ctx, const jsonObject* obj ) return 0; } - jsonObjectFree(_tmp_params); free(foreign_pkey_value); int j = 0; @@ -1106,8 +1139,8 @@ static int verifyObjectPCRUD ( osrfMethodContext* ctx, const jsonObject* obj ) osrfStringArrayGetString(context_org_array, context_org_array->size - 1) ); } - - jsonObjectFree(_list); + + jsonObjectFree(_fparam); } osrfStringArrayFree(class_list); diff --git a/Open-ILS/src/c-apps/oils_idl-core.c b/Open-ILS/src/c-apps/oils_idl-core.c index 19240d3b48..f1b8b42ad3 100644 --- a/Open-ILS/src/c-apps/oils_idl-core.c +++ b/Open-ILS/src/c-apps/oils_idl-core.c @@ -329,6 +329,9 @@ osrfHash* oilsIDLInit( const char* idl_filename ) { osrfHashSet( _tmp_fcontext, osrfHashGet(_flink, "field"), "fkey" ); osrfHashSet( _tmp_fcontext, osrfHashGet(_flink, "key"), "field" ); + if( (prop_str = (char*)xmlGetNoNsProp(_f, BAD_CAST "jump")) ) + osrfHashSet( _tmp_fcontext, osrfStringArrayTokenize( prop_str, '.' ), "jump" ); + // Tokenize field attribute into an osrfStringArray const char * field_list = (char*) xmlGetProp(_f, BAD_CAST "field"); if( field_list ) @@ -345,7 +348,7 @@ osrfHash* oilsIDLInit( const char* idl_filename ) { if( (prop_str = (char*)xmlGetNoNsProp(_f, BAD_CAST "field") )) { char* map_list = strdup( prop_str ); osrfLogDebug(OSRF_LOG_MARK, - "Permacrud foreign context field list is %s", prop_str ); + "Permacrud local context field list is %s", prop_str ); if (strlen( map_list ) > 0) { char* st_tmp = NULL; diff --git a/Open-ILS/src/extras/fast-extract b/Open-ILS/src/extras/fast-extract index 4c59642a2d..79bf8fb078 100755 --- a/Open-ILS/src/extras/fast-extract +++ b/Open-ILS/src/extras/fast-extract @@ -18,12 +18,13 @@ binmode(STDOUT, ':utf8'); $| = 1; -my ($config, $delim, $after) = ('SYSCONFDIR/opensrf_core.xml', ' | '); +my ($config, $delim, $after,$deleted) = ('SYSCONFDIR/opensrf_core.xml', ' | '); GetOptions( "after=s" => \$after, "boostrap=s" => \$config, "delimiter=s" => \$delim, + "include-deleted" => \$deleted, ); OpenSRF::System->bootstrap_client( config_file => $config ); @@ -49,6 +50,7 @@ my $dbh = DBI->connect($dsn,$db_user,$db_pw, {AutoCommit => 1, pg_enable_utf8 => my $SQL = 'SELECT id FROM biblio.record_entry WHERE id > 0'; $SQL .= " AND edit_date > '$after'" if ($after); +$SQL .= " AND deleted IS FALSE" if (!$deleted); my $ids = $dbh->selectcol_arrayref($SQL); @@ -63,6 +65,6 @@ SQL for my $id ( @$ids ) { my $row = $dbh->selectrow_hashref( $SQL, {}, $id ); - print "$$row{id}$delim$$row{tnc_source}$delim$$row{tcn_value}$delim$$row{marc}\n"; + print "$$row{deleted}$delim$$row{id}$delim$$row{tnc_source}$delim$$row{tcn_value}$delim$$row{marc}\n"; } diff --git a/Open-ILS/src/extras/import/marc_add_ids b/Open-ILS/src/extras/import/marc_add_ids index a4ac669f27..6ddb38da0d 100755 --- a/Open-ILS/src/extras/import/marc_add_ids +++ b/Open-ILS/src/extras/import/marc_add_ids @@ -38,6 +38,8 @@ for (@fields) { $partcount++; } +print ''; + my $count = 0; while (<>) { chomp; @@ -48,6 +50,7 @@ while (<>) { ($partlist{tcn_value} = $values[ $partmap{tcn_value}]) =~ s/^\s*//o if ($part eq 'tcn_value'); ($partlist{tcn_source} = $values[ $partmap{tcn_source}]) =~ s/^\s*//o if ($part eq 'tcn_source'); ($partlist{id} = $values[ $partmap{id}]) =~ s/^\s*//o if ($part eq 'id'); + ($partlist{deleted} = $values[ $partmap{deleted}]) =~ s/^\s*//o if ($part eq 'deleted'); $partlist{marc} = $values[ $partmap{marc}] if ($part eq 'marc'); $partlist{tcn_value} =~ s/\s*$//o if ($part eq 'tcn_value'); @@ -88,7 +91,7 @@ while (<>) { } } - if ($set_as_deleted) { + if ($set_as_deleted && $partlist{deleted} eq 't') { my $leader = $r->leader(); if (length($leader)>4) { substr($leader,5,1,"d"); @@ -98,6 +101,7 @@ while (<>) { my $x = $r->as_xml_record; $x =~ s/\n//gso; + $x =~ s/^<[^>]>//o; print $x."\n"; $count++; print STDERR "\r$count" unless ($quiet || $count % 100); @@ -107,4 +111,5 @@ while (<>) { }; } +print ''; diff --git a/Open-ILS/src/perlmods/OpenILS/Application/Trigger/Cleanup.pm b/Open-ILS/src/perlmods/OpenILS/Application/Trigger/Cleanup.pm new file mode 100644 index 0000000000..1b7e18505f --- /dev/null +++ b/Open-ILS/src/perlmods/OpenILS/Application/Trigger/Cleanup.pm @@ -0,0 +1,5 @@ +package OpenILS::Application::Trigger::Cleanup; +sub fourty_two { return 42 } +sub NOOP_True { return 1 } +sub NOOP_False { return 0 } +1; diff --git a/Open-ILS/src/perlmods/OpenILS/Application/Trigger/Collector.pm b/Open-ILS/src/perlmods/OpenILS/Application/Trigger/Collector.pm new file mode 100644 index 0000000000..e0ba462fe1 --- /dev/null +++ b/Open-ILS/src/perlmods/OpenILS/Application/Trigger/Collector.pm @@ -0,0 +1,3 @@ +package OpenILS::Application::Trigger::Collector; +sub fourty_two { return 42 } +1; diff --git a/Open-ILS/src/perlmods/OpenILS/Application/Trigger/Event.pm b/Open-ILS/src/perlmods/OpenILS/Application/Trigger/Event.pm new file mode 100644 index 0000000000..c2df13232f --- /dev/null +++ b/Open-ILS/src/perlmods/OpenILS/Application/Trigger/Event.pm @@ -0,0 +1,377 @@ +package OpenILS::Application::Trigger::Event; +use OpenSRF::EX qw/:try/; + +use OpenSRF::Utils::Logger qw/:level/; + +use OpenILS::Utils::Fieldmapper; +use OpenILS::Utils::CStoreEditor q/:funcs/; +use OpenILS::Application::Trigger::ModRunner; + +my $log = 'OpenSRF::Utils::Logger'; + +sub new { + my $class = shift; + my $id = shift; + $class = ref($class) || $class; + + my $self = bless { id => $id, editor => new_editor() } => $class; + + return $self->init() +} + +sub init { + my $self = shift; + my $id = shift; + + return $self if ($self->event); + + $self->id( $id ); + $self->environment( {} ); + + return $self if (!$self->id); + + $self->event( + $self->editor->retrieve_action_trigger_event([ + $self->id, { + flesh => 2, + flesh_fields => { + atev => [ 'event_def' ], + atevdef => [ 'hook' ] + } + } + ]) + ); + + my $class = $self->_fm_class_by_hint( $self->event->event_def->hook->core_type ); + + my $meth = "retreive_" . $class; + $meth =~ s/Fieldmapper:://; + $meth =~ s/::/_/; + + $self->target( $self->editor->$meth( $self->event->target ) ); + + return $self; +} + +sub cleanup { + my $self = shift; + + if (defined $self->reacted) { + $self->update_state( 'cleaning') || die 'Unable to update event state'; + try { + my $cleanup = $self->reacted ? $self->event->event_def->cleanup_success : $self->event->event_def->cleanup_failure; + $self->cleanedup( + OpenILS::Application::Trigger::ModRunner::Cleanup + ->new( $cleanup, $self->environment ) + ->run + ->final_result + ); + } otherwise { + $log->error( shift() ); + $self->update_state( 'error' ) || die 'Unable to update event state'; + }; + + if ($self->cleanedup) { + $self->update_state( 'complete' ) || die 'Unable to update event state'; + } else { + $self->update_state( 'error' ) || die 'Unable to update event state'; + } + + } else { + $self->{cleanedup} = undef; + } + return $self; +} + +sub react { + my $self = shift; + + if ($self->valid) { + if ($self->event->event_def->group_field) { # can't react individually to a grouped definition + $self->{reacted} = undef; + } else { + $self->update_state( 'reacting') || die 'Unable to update event state'; + try { + $self->reacted( + OpenILS::Application::Trigger::ModRunner::Reactor + ->new( $self->event->event_def->reactor, $self->environment ) + ->run + ->final_result + ); + } otherwise { + $log->error( shift() ); + $self->update_state( 'error' ) || die 'Unable to update event state'; + }; + + if (defined $self->reacted) { + $self->update_state( 'reacted' ) || die 'Unable to update event state'; + } else { + $self->update_state( 'error' ) || die 'Unable to update event state'; + } + } + } else { + $self->{reacted} = undef; + } + return $self; +} + +sub validate { + my $self = shift; + + return $self if (defined $self->valid); + + if ($self->build_environment->environment->{complete}) { + $self->update_state( 'validating') || die 'Unable to update event state'; + try { + $self->valid( + OpenILS::Application::Trigger::ModRunner::Validator + ->new( $self->event->event_def->validator, $self->environment ) + ->run + ->final_result + ); + } otherwise { + $log->error( shift() ); + $self->update_state( 'error' ) || die 'Unable to update event state'; + }; + + if (defined $self->valid) { + if ($self->valid) { + $self->update_state( 'valid' ) || die 'Unable to update event state'; + } else { + $self->update_state( 'invalid' ) || die 'Unable to update event state'; + } + } else { + $self->update_state( 'error' ) || die 'Unable to update event state'; + } + } else { + $self->{valid} = undef + } + + return $self; +} + +sub cleanedup { + my $self = shift; + return undef unless (ref $self); + + my $c = shift; + $self->{cleanedup} = $c if (defined $c); + return $self->{cleanedup}; +} + +sub reacted { + my $self = shift; + return undef unless (ref $self); + + my $r = shift; + $self->{reacted} = $r if (defined $r); + return $self->{reacted}; +} + +sub valid { + my $self = shift; + return undef unless (ref $self); + + my $v = shift; + $self->{valid} = $v if (defined $v); + return $self->{valid}; +} + +sub event { + my $self = shift; + return undef unless (ref $self); + + my $e = shift; + $self->{event} = $e if (defined $e); + return $self->{event}; +} + +sub id { + my $self = shift; + return undef unless (ref $self); + + my $i = shift; + $self->{id} = $i if (defined $i); + return $self->{id}; +} + +sub environment { + my $self = shift; + return undef unless (ref $self); + + my $e = shift; + $self->{environment} = $e if (defined $e); + return $self->{environment}; +} + +sub editor { + my $self = shift; + return undef unless (ref $self); + + my $e = shift; + $self->{editor} = $e if (defined $e); + return $self->{editor}; +} + +sub target { + my $self = shift; + return undef unless (ref $self); + + my $t = shift; + $self->{target} = $t if (defined $t); + return $self->{target}; +} + +sub update_state { + my $self = shift; + return undef unless ($self && ref $self); + + my $state = shift; + return undef unless ($state); + + $self->editor->xact_begin || return undef; + + my $e = $self->editor->retrieve_action_trigger_event( $self->id ); + $e->update_time( 'now' ); + $e->update_process( $$ ); + $e->state( $state ); + $self->editor->update_action_trigger_event( $e ); + + return $self->editor->xact_commit || undef; +} + +sub build_environment { + my $self = shift; + return $self if ($self->environment->{complete}); + + $self->update_state( 'collecting') || die 'Unable to update event state'; + + try { + + $self->environment->{target} = $self->target; + $self->environment->{event} = $self->event; + $self->environment->{template} = $self->event->event_def->template; + + my @env_list = $self->editor->search_action_trigger_environment( { event_def => $self->event->event_def } ); + my @param_list = $self->editor->search_action_trigger_params( { event_def => $self->event->event_def } ); + + $self->environment->{params}{ $_->param } = eval $_->value for ( @param_list ); + + for my $e ( @env_list ) { + my (@label, @path); + @path = split('.', $e->path) if ($e->path); + @label = split('.', $e->label) if ($e->label); + + $self->_object_by_path( $self->event->target, $e->collector, \@label, \@path ); + } + + $self->environment->{complete} = 1; + } otherwise { + $log->error( shift() ); + $self->update_state( 'error' ) || die 'Unable to update event state'; + }; + + if ($self->environment->{complete}) { + $self->update_state( 'collected' ) || die 'Unable to update event state'; + } else { + $self->update_state( 'error' ) || die 'Unable to update event state'; + } + + return $self; +} + +sub _fm_class_by_hint { + my $self = shift; + my $hint = shift; + + my ($class) = grep { + Fieldmapper->publish_fieldmapper->{$_}->{hint} eq $hint + } keys %{ Fieldmapper->publish_fieldmapper }; + + return $class; +} + +sub _object_by_path { + my $self = shift; + my $context = shift; + my $collector = shift; + my $label = shift; + my $path = shift; + + my $step = shift(@$path); + + my $fhint = Fieldmapper->publish_fieldmapper->{$context->class_name}{links}{$step}{class}; + my $fclass = $self->_fm_class_by_hint( $fhint ); + + my $ffield = Fieldmapper->publish_fieldmapper->{$context->class_name}{links}{$step}{key}; + my $rtype = Fieldmapper->publish_fieldmapper->{$context->class_name}{links}{$step}{reltype}; + + my $meth = 'retrieve_'; + my $multi = 0; + my $lfield = $step; + if ($rtype eq 'has_many') { + $meth = 'search_'; + $multi = 1; + $lfield = $context->Identity; + } + + $meth .= $fclass; + $meth =~ s/Fieldmapper:://; + $meth =~ s/::/_/; + + my $obj = $self->editor->$meth( { $ffield => $context->$lfield() } ); + + if (@$path) { + + my $obj_list = []; + if (!$multi) { + $obj_list = [$obj] if ($obj); + } else { + $obj_list = $obj; + } + + $self->_object_by_path( $_, $collector, $label, $path ) for (@$obj_list); + + $obj = $$obj_list[0] if (!$multi); + $context->$step( $obj ) if ($obj && !$label); + + } else { + + if ($collector) { + my $obj_list = [$obj] if ($obj && !$multi); + $obj_list = $obj if ($multi); + + my @new_obj_list; + for my $o ( @$obj_list ) { + push @new_obj_list, + OpenILS::Application::Trigger::ModRunner::Collector + ->new( $collector, $o ) + ->run + ->final_result + } + + if (!$multi) { + $obj = $new_obj_list[0]; + } else { + $obj = \@new_obj_list; + } + } + + if ($label) { + my $node = $self->environment; + my $i = 0; my $max = scalar(@$label) - 1; + for (; $i < $max; $i++) { + my $part = $$label[$i]; + $$node{$part} ||= {}; + $node = $$node{$part}; + } + $$node{$$label[-1]} = $obj; + } else { + $context->$step( $obj ) if ($obj); + } + } + + return $obj; +} + +1; diff --git a/Open-ILS/src/perlmods/OpenILS/Application/Trigger/ModRunner.pm b/Open-ILS/src/perlmods/OpenILS/Application/Trigger/ModRunner.pm index 47621ae9ca..e8d416391f 100644 --- a/Open-ILS/src/perlmods/OpenILS/Application/Trigger/ModRunner.pm +++ b/Open-ILS/src/perlmods/OpenILS/Application/Trigger/ModRunner.pm @@ -1,16 +1,17 @@ package OpenILS::Application::Trigger::ModLoader; use UNIVERSAL::require; +sub prefix { return 'OpenILS::Application::Trigger' } + sub new { my $class = shift; $class = ref($class) || $class; - my $mod_thing = shift; - return undef unless ($mod_thing); + my $mod = shift; + return undef unless ($mod); my $self = bless { - mod_thing => $mod_thing, - module => $mod_thing->module(), + module => ref $mod ? $mod->module() : $mod, handler => 'handler' } => $class; @@ -55,7 +56,7 @@ sub load { my $loaded = $m->use; if (!$loaded) { - $builtin_m = "OpenILS::Application::Trigger::$m"; + $builtin_m = $self->prefix . "::$m"; $loaded = $builtin_m->use; if (!$loaded) { @@ -67,13 +68,22 @@ sub load { if (!$loaded) { $h = $self->handler; - my $builtin_m = "OpenILS::Application::Trigger::$m"; + $builtin_m = $self->prefix . "::$m"; $loaded = $m->use; $m = $builtin_m if ($loaded); } } else { $loaded = $m->use; + + # The following is an escape hatch for builtin dummy handlers + if (!$loaded) { + $loaded = $self->prefix->use; + if ($loaded && $self->prefix->can( $self->module ) ) { + $m = $self->prefix; + $h = $self->module; + } + } } } else { $m = $builtin_m; @@ -152,6 +162,22 @@ sub run { return $self; }; +package OpenILS::Application::Trigger::ModRunner::Collector; +use base 'OpenILS::Application::Trigger::ModRunner'; +sub prefix { return 'OpenILS::Application::Trigger::Collector' } + +package OpenILS::Application::Trigger::ModRunner::Validator; +use base 'OpenILS::Application::Trigger::ModRunner'; +sub prefix { return 'OpenILS::Application::Trigger::Validator' } + +package OpenILS::Application::Trigger::ModRunner::Reactor; +use base 'OpenILS::Application::Trigger::ModRunner'; +sub prefix { return 'OpenILS::Application::Trigger::Reactor' } + +package OpenILS::Application::Trigger::ModRunner::Cleanup; +use base 'OpenILS::Application::Trigger::ModRunner'; +sub prefix { return 'OpenILS::Application::Trigger::Cleanup' } + package OpenILS::Application::Trigger::ModStackRunner; use base 'OpenILS::Application::Trigger::ModRunner'; diff --git a/Open-ILS/src/perlmods/OpenILS/Application/Trigger/Reactor.pm b/Open-ILS/src/perlmods/OpenILS/Application/Trigger/Reactor.pm new file mode 100644 index 0000000000..d405161657 --- /dev/null +++ b/Open-ILS/src/perlmods/OpenILS/Application/Trigger/Reactor.pm @@ -0,0 +1,5 @@ +package OpenILS::Application::Trigger::Reactor; +sub fourty_two { return 42 } +sub NOOP_True { return 1 } +sub NOOP_False { return 0 } +1; diff --git a/Open-ILS/src/perlmods/OpenILS/Application/Trigger/Validator.pm b/Open-ILS/src/perlmods/OpenILS/Application/Trigger/Validator.pm new file mode 100644 index 0000000000..d97b911fb6 --- /dev/null +++ b/Open-ILS/src/perlmods/OpenILS/Application/Trigger/Validator.pm @@ -0,0 +1,29 @@ +package OpenILS::Application::Trigger::Validator; +sub fourty_two { return 42 } +sub NOOP_True { return 1 } +sub NOOP_False { return 0 } + +sub CircIsOpen { + my $self = shift; + my $env = shift; + + return defined($env->{target}->checkin_time) ? 0 : 1; +} + +sub HoldIsAvailable { + my $self = shift; + my $env = shift; + + my $t = $env->{target}->transit; + + die "Transit object exists, but is not fleshed. Add 'transit' to the environment in order to use this Validator." + if ($t && !ref($t)); + + if ($t) { + return (defined($env->{target}->capture_time) && defined($t->dest_recv_time)) ? 1 : 0; + } + + return defined($env->{target}->capture_time) ? 1 : 0; +} + +1; diff --git a/Open-ILS/src/sql/Pg/400.schema.action_trigger.sql b/Open-ILS/src/sql/Pg/400.schema.action_trigger.sql index 5c687324e5..8911ed9566 100644 --- a/Open-ILS/src/sql/Pg/400.schema.action_trigger.sql +++ b/Open-ILS/src/sql/Pg/400.schema.action_trigger.sql @@ -49,13 +49,17 @@ CREATE TABLE action_trigger.collector ( module TEXT PRIMARY KEY, -- All live under the OpenILS::Trigger::Collector:: namespace description TEXT ); -INSERT INTO action_trigger.collector (module,description) VALUES ('CircCountsByCircMod','Count of Circulations for a User, broken down by circulation modifier'); +INSERT INTO action_trigger.collector (module,description) VALUES ('fourty_two','Returns the answer to life, the universe and everything'); +--INSERT INTO action_trigger.collector (module,description) VALUES ('CircCountsByCircMod','Count of Circulations for a User, broken down by circulation modifier'); -- Simple tests on an FM object from hook.core_type to test for "should we still do this." CREATE TABLE action_trigger.validator ( module TEXT PRIMARY KEY, -- All live under the OpenILS::Trigger::Validator:: namespace description TEXT ); +INSERT INTO action_trigger.validator (module,description) VALUES ('fourty_two','Returns the answer to life, the universe and everything'); +INSERT INTO action_trigger.validator (module,description) VALUES ('NOOP_True','Always returns true -- validation always passes'); +INSERT INTO action_trigger.validator (module,description) VALUES ('NOOP_False','Always returns false -- validation always fails'); INSERT INTO action_trigger.validator (module,description) VALUES ('CircIsOpen','Check that the circulation is still open'); INSERT INTO action_trigger.validator (module,description) VALUES ('HoldIsAvailable','Check that an item is on the hold shelf'); @@ -64,6 +68,9 @@ CREATE TABLE action_trigger.reactor ( module TEXT PRIMARY KEY, -- All live under the OpenILS::Trigger::Reactor:: namespace description TEXT ); +INSERT INTO action_trigger.reactor (module,description) VALUES ('fourty_two','Returns the answer to life, the universe and everything'); +INSERT INTO action_trigger.reactor (module,description) VALUES ('NOOP_True','Always returns true -- reaction always passes'); +INSERT INTO action_trigger.reactor (module,description) VALUES ('NOOP_False','Always returns false -- reaction always fails'); INSERT INTO action_trigger.reactor (module,description) VALUES ('SendEmail','Send an email based on a user-defined template'); INSERT INTO action_trigger.reactor (module,description) VALUES ('GenerateBatchOverduePDF','Output a batch PDF of overdue notices for printing'); @@ -72,6 +79,9 @@ CREATE TABLE action_trigger.cleanup ( module TEXT PRIMARY KEY, -- All live under the OpenILS::Trigger::Cleanup:: namespace description TEXT ); +INSERT INTO action_trigger.cleanup (module,description) VALUES ('fourty_two','Returns the answer to life, the universe and everything'); +INSERT INTO action_trigger.cleanup (module,description) VALUES ('NOOP_True','Always returns true -- cleanup always passes'); +INSERT INTO action_trigger.cleanup (module,description) VALUES ('NOOP_False','Always returns false -- cleanup always fails'); INSERT INTO action_trigger.cleanup (module,description) VALUES ('ClearAllPending','Remove all future, pending notifications for this target'); CREATE TABLE action_trigger.event_definition ( @@ -112,7 +122,7 @@ CREATE TABLE action_trigger.event ( update_time TIMESTAMPTZ, complete_time TIMESTAMPTZ, update_process INT, - state TEXT NOT NULL DEFAULT 'pending' CHECK (state IN ('pending','found','collecting','validating','reacting','cleanup','complete','error')), + state TEXT NOT NULL DEFAULT 'pending' CHECK (state IN ('pending','invalid','found','collecting','collected','validating','valid','reacting','reacted','cleaning','complete','error')), template_output TEXT, error_output TEXT ); diff --git a/Open-ILS/tests/datasets/README b/Open-ILS/tests/datasets/README index c055389011..dbc6ff70fe 100644 --- a/Open-ILS/tests/datasets/README +++ b/Open-ILS/tests/datasets/README @@ -6,5 +6,6 @@ The following table lists the data sets we have collected for testing purposes. | lul_fre_100.marc | MARC21 | MARC8 | Unicorn GL3.1 | 100 records, French, pre-1923 | | lul_fre_500.marc | MARC21 | MARC8 | Unicorn GL3.1 | 500 records, French, pre-1923 | | jazz_1k.marc | MARC21 | MARC8 | Unicorn GL3.1 | 1000 records | +| map_data.marc | MARC21 | UTF8 | Voyager (LoC) | 3 records with some geospatial metadata | | music_5k.marc | MARC21 | MARC8 | Unicorn GL3.1 | 5000 records | | hebrew.marc | MARC21 | MARC8 | III | Hebrew scripts, 25 records | diff --git a/Open-ILS/tests/datasets/map_data.mrc b/Open-ILS/tests/datasets/map_data.mrc new file mode 100644 index 0000000000..c9c2147485 --- /dev/null +++ b/Open-ILS/tests/datasets/map_data.mrc @@ -0,0 +1 @@ +03311cem 2200529 a 45000010009000000050017000090070009000260080039000359060045000749550032001190100015001510340054001660400013002200500026002330520013002591100048002722450137003202550089004572600149005463000106006954400071008015000044008725000031009165000075009475000069010225000208010915000074012995040018013735000056013915050415014476500053018626500062019156500063019776500041020406500030020816500039021117000018021507000024021687000033021927100029022257400064022547400108023187400092024267400109025189010030026278520124026571368378320090125221700.0aj canzn040811s1989 cauae bh b s 0 eng a7bcbccorigcopduencipf20gn-geogmaps aga09 2004-08-16 sent to CMT a20046317631 aab250000dW1260000eW1240000fN0420000gN0400000 aDLCcDLC00aG4362.C6C5 s250b.C37 a4362bC61 aCalifornia.bDivision of Mines and Geology.10aGeology of the northern California continental margin /cH. Gary Greene and Michael P. Kennedy, editors ; [graphics by Ross Martin]. aScale 1:250,000 ;btransverse Mercator proj.c(W 126⁰--W 124⁰/N 42⁰--N 40⁰). a[Sacramento, Calif.] :bState of California, Resources Agency, Dept. of Conservation ;a[Reston, Va.] :bUnited States Geological Survey,c1989. a4 maps :bcol. ;ceach 91 x 69 cm., on sheets 116 x 99 cm. or smaller, folded in envelope 31 x 26 cm. 0aCalifornia continental margin geologic map series ;vmap no. 7A-7D aDepths shown by contours and soundings. aTitle from envelope cover. a"Northern California continental margin--Area 7 of 7"--Envelope cover. aMaps attributed to various authors, compilers, and contributors. aThe California continental margin geologic map series was developed cooperatively by the State of California Dept. of Conservation, Division of Mines and Geology, and the United States Geological Survey. aSome sheets include chart of geophysical tracklines and data sources. aBibliography. aIncludes geologic explanation and location diagram.0 aMap no. 7A. Geologic map of the northern California continental margin -- Map no. 7B. Earthquake epicenters and selected fault plane solutions of the northern California continental margin -- Map no. 7C. Bouguer gravity and magnetic anomaly map of the northern California continental margin -- Map no. 7D. Well location, geophysical trackline, and data source map of the northern California continental margin. 0aGeologyzCaliforniazPacific Coast RegionvMaps. 0aFaults (Geology)zCaliforniazPacific Coast RegionvMaps. 0aGravity anomalieszCaliforniazPacific Coast RegionvMaps. 0aContinental shelfzCaliforniavMaps. 0aCoastszCaliforniavMaps. 0aSubmerged landszCaliforniavMaps.1 aGreene, H. G.1 aKennedy, Michael P.1 aMartin, Ross,ccartographer.2 aGeological Survey (U.S.)02aGeologic map of the northern California continental margin.02aEarthquake epicenters and selected fault plane solutions of the northern California continental margin.02aBouguer gravity and magnetic anomaly map of the northern California continental margin.02aWell location, geophysical trackline, and data source map of the northern California continental margin. a13683783bSystem Localc14 agaaagplbBR1bBR1cStacksjG4362.C6C5 s250.C37p11223344y0.00xnonreferencexholdablexcirculatingxvisiblezAvailable01918cem 22003854a 45000010009000000050017000090070009000260080039000359060045000749550032001190100015001510200015001660340053001810400013002340500024002470520018002711100029002892450160003182500046004782550110005242600045006343000033006795000057007125000044007695000120008135000084009335000096010176510049011136510056011626500048012187000078012667000036013449010030013808520122014101493368920090127030616.0aj canzn070719s2007 vauabg cp a f 0 eng a7bcbccorigcopduencipf20gy-geogmaps aga09 2007-07-19 sent to CMT a2007631309 a14113180131 aab24000dW1194500eW1192910fN0374705gN0374200 aDLCcDLC00aG4362.Y62 2007b.G4 a4362bY62bY62 aGeological Survey (U.S.)10aMap of Yosemite Valley, Yosemite National Park and Wilderness, California, Mariposa County /cUnited States, Department of the Interior, Geological Survey. aShaded relief ed., limited revision 1970. aScale 1:24,000 ;bpolyconic proj.c(W 119⁰45ʹ00ʺ--W 119⁰29ʹ10ʺ/N 37⁰47ʹ05ʺ--N 37⁰42ʹ00ʺ). aReston, Va. :bGeological Survey,c2007. a1 map :bcol. ;c40 x 97 cm. aRelief shown by contours, shading, and spot heights. a"Interior--Geological Survey ... 1995." aOn verso: The geologic story of Yosemite Valley / by N. king Huber, in the footsteps of François E. Matthes. 2007. aIncludes descriptive list of "Elevations of principal points" and location map. aMap of California showing location of Yosemite National Park and ill. (some col.) on verso. 0aYosemite Valley (Calif.)vMaps, Topographic. 0aYosemite National Park (Calif.)vMaps, Topographic. 0aGeologyzCaliforniazYosemite ValleyvMaps.12aHuber, N. Kingq(Norman King),d1926-tGeologic story of Yosemite Valley.1 aMatthes, François,d1874-1948. a14933689bSystem Localc34 agaaagplbBR1bBR1cStacksjG4362.Y62 2007.G4p1090109y0.00xnonreferencexholdablexcirculatingxvisiblezIn process03375cem 2200529 a 45000010009000000050017000090070009000260080039000359060045000749550032001190100015001510340054001660400013002200500026002330520013002591100048002722450153003202550089004732600149005623000106007114400071008175000044008885000031009325000081009635000069010445000208011135000074013215040018013955000056014135050439014696500053019086500062019616500063020236500041020866500030021276500039021577000018021967000024022147000028022387100029022667400070022957400114023657400098024797400115025779010030026928520123027221368374020090126032558.0aj canzn040811s1987 cauae bh b s 0 eng a7bcbccorigcopduencipf20gn-geogmaps aga09 2004-08-16 sent to CMT a20046317621 aab250000dW1220000eW1180000fN0340000gN0320000 aDLCcDLC00aG4362.C6C5 s250b.C33 a4362bC61 aCalifornia.bDivision of Mines and Geology.10aGeology of the outer-southern California continental margin /cH. Gary Greene and Michael P. Kennedy, editors ; [graphics by James Dennis Williams]. aScale 1:250,000 ;btransverse Mercator proj.c(W 122⁰--W 118⁰/N 34⁰--N 32⁰). a[Sacramento, Calif.] :bState of California, Resources Agency, Dept. of Conservation ;a[Reston, Va.] :bUnited States Geological Survey,c1987. a4 maps :bcol. ;ceach 91 x 78 cm., on sheets 140 x 85 cm. or smaller, folded in envelope 31 x 26 cm. 0aCalifornia continental margin geologic map series ;vmap no. 3A-3D aDepths shown by contours and soundings. aTitle from envelope cover. a"Outer-southern California continental margin--Area 3 of 7"--Envelope cover. aMaps attributed to various authors, compilers, and contributors. aThe California continental margin geologic map series was developed cooperatively by the State of California Dept. of Conservation, Division of Mines and Geology, and the United States Geological Survey. aSome sheets include chart of geophysical tracklines and data sources. aBibliography. aIncludes geologic explanation and location diagram.0 aMap no. 3A. Geologic map of the outer-southern California continental margin -- Map no. 3B. Earthquake epicenters and selected fault plane solutions of the outer-southern California continental margin -- Map no. 3C. Bouguer gravity and magnetic anomaly map of the outer-southern California continental margin -- Map no. 3D. Well location, geophysical trackline, and data source map of the outer-southern California continental margin. 0aGeologyzCaliforniazPacific Coast RegionvMaps. 0aFaults (Geology)zCaliforniazPacific Coast RegionvMaps. 0aGravity anomalieszCaliforniazPacific Coast RegionvMaps. 0aContinental shelfzCaliforniavMaps. 0aCoastszCaliforniavMaps. 0aSubmerged landszCaliforniavMaps.1 aGreene, H. G.1 aKennedy, Michael P.1 aWilliams, James Dennis.2 aGeological Survey (U.S.)02aGeologic map of the outer-southern California continental margin.02aEarthquake epicenters and selected fault plane solutions of the outer-southern California continental margin.02aBouguer gravity and magnetic anomaly map of the outer-southern California continental margin.02aWell location, geophysical trackline, and data source map of the outer-southern California continental margin. a13683740bSystem Localc24 agaaagplbBR1bBR1cStacksjG4362.C6C5 s250.C33p2233444y0.00xnonreferencexholdablexcirculatingxvisiblezAvailable \ No newline at end of file diff --git a/Open-ILS/web/js/dojo/openils/PermaCrud.js b/Open-ILS/web/js/dojo/openils/PermaCrud.js index 909a667f27..a6d7a873ba 100644 --- a/Open-ILS/web/js/dojo/openils/PermaCrud.js +++ b/Open-ILS/web/js/dojo/openils/PermaCrud.js @@ -58,11 +58,13 @@ if(!dojo._hasResource["openils.PermaCrud"]) { }, disconnect : function ( onerror ) { + this.connected = false; + return true; + // disconnect returns nothing, which is null, which is not true, cause the following to always run ... arg. if (!this.session.disconnect()) { if (onerror) onerror(this.session); return false; } - return true; }, diff --git a/Open-ILS/web/reports/oils_rpt_common.xhtml b/Open-ILS/web/reports/oils_rpt_common.xhtml index c1b43028a0..3f3c825876 100644 --- a/Open-ILS/web/reports/oils_rpt_common.xhtml +++ b/Open-ILS/web/reports/oils_rpt_common.xhtml @@ -13,6 +13,7 @@