From 667c1538ed7e412aa1bce4e4f497f86f478b636f Mon Sep 17 00:00:00 2001 From: erickson Date: Mon, 4 Aug 2008 01:25:53 +0000 Subject: [PATCH] Merged revisions 10219-10220,10223,10225,10228-10229,10231-10233,10236-10237,10240-10241 via svnmerge from svn://svn.open-ils.org/ILS/trunk ........ r10219 | erickson | 2008-07-31 11:53:44 -0400 (Thu, 31 Jul 2008) | 12 lines Upped the default patron timeout to 10 minutes When an item barcode is scanned but the Enter key is not sent, the system waits a configured amount of time (default 800 milliseconds) then selects the text so the next scan will replace the existing text. Automatically print at logout time Replace Logout and Print links with "Done" links since printing is assumed ........ r10220 | miker | 2008-07-31 12:16:11 -0400 (Thu, 31 Jul 2008) | 1 line make grace period a command line parameter ........ r10223 | erickson | 2008-07-31 12:28:30 -0400 (Thu, 31 Jul 2008) | 1 line added explicit DESTROY methods to each package so AUTOLOAD won't attempt to use it ........ r10225 | erickson | 2008-07-31 12:44:46 -0400 (Thu, 31 Jul 2008) | 1 line if a patron barcode regex is configured and a patron barcode is scanned into the item barcode input, the current user is logged out and the new user is logged in ........ r10228 | erickson | 2008-07-31 14:55:38 -0400 (Thu, 31 Jul 2008) | 1 line if you set signed.applets.codebase_principal_support to true in about:config in Firefox, you now have the option to bypass the printer dialog if you accept the security dialogs ........ r10229 | dbs | 2008-07-31 22:47:39 -0400 (Thu, 31 Jul 2008) | 2 lines No leading period for selector, please. ........ r10231 | dbs | 2008-08-01 12:21:15 -0400 (Fri, 01 Aug 2008) | 2 lines D'oh! That 404 error really does mean that osrf-http-translator could not be found. ........ r10232 | erickson | 2008-08-01 12:45:45 -0400 (Fri, 01 Aug 2008) | 1 line removed ":" from log line so output can be pasted directly into srfsh ........ r10233 | erickson | 2008-08-01 13:04:08 -0400 (Fri, 01 Aug 2008) | 7 lines fixed faulty rule set query made some var names more explicit fix getopt setting ........ r10236 | miker | 2008-08-01 14:00:30 -0400 (Fri, 01 Aug 2008) | 1 line add support for selecting from a function, given the function name and all params in an array (and the function takes only TEXT params) ........ r10237 | miker | 2008-08-01 14:57:44 -0400 (Fri, 01 Aug 2008) | 1 line ingest of dates thinko ........ r10240 | erickson | 2008-08-03 19:57:06 -0400 (Sun, 03 Aug 2008) | 1 line "parent" is a special variable. some browsers (opera) will complain ........ r10241 | erickson | 2008-08-03 19:58:09 -0400 (Sun, 03 Aug 2008) | 1 line "parent" is a special variable. some browsers (opera) will complain ........ git-svn-id: svn://svn.open-ils.org/ILS/branches/acq-experiment@10243 dcc99617-32d9-48b4-a31d-7c20da2025e4 --- Open-ILS/examples/apache/eg_vhost.conf | 2 +- Open-ILS/src/c-apps/oils_cstore.c | 665 +++++++++++---------- .../src/perlmods/OpenILS/Application/Ingest.pm | 12 +- .../src/perlmods/OpenILS/Utils/CStoreEditor.pm | 2 +- Open-ILS/src/perlmods/OpenILS/Utils/ZClient.pm | 4 + Open-ILS/src/support-scripts/fine_generator.pl | 3 +- .../src/support-scripts/test-scripts/indb_circ.pl | 37 +- Open-ILS/web/js/dojo/fieldmapper/OrgUtils.js | 6 +- Open-ILS/web/opac/common/js/org_utils.js | 6 +- Open-ILS/web/opac/extras/selfcheck/selfcheck.css | 9 + Open-ILS/web/opac/extras/selfcheck/selfcheck.js | 100 +++- Open-ILS/web/opac/extras/selfcheck/selfcheck.xml | 73 ++- Open-ILS/web/opac/locale/en-US/opac.dtd | 5 +- Open-ILS/web/opac/skin/default/js/myopac.js | 2 +- 14 files changed, 522 insertions(+), 404 deletions(-) diff --git a/Open-ILS/examples/apache/eg_vhost.conf b/Open-ILS/examples/apache/eg_vhost.conf index 38d0ce5a99..badf40b91d 100644 --- a/Open-ILS/examples/apache/eg_vhost.conf +++ b/Open-ILS/examples/apache/eg_vhost.conf @@ -207,7 +207,7 @@ RewriteRule ^/opac/extras/ac/jacket/(small|medium|large)/$ \ # OpenSRF-over-HTTP translator # (http://open-ils.org/dokuwiki/doku.php?id=opensrf_over_http) # ---------------------------------------------------------------------------------- - + SetHandler osrf_http_translator_module allow from all diff --git a/Open-ILS/src/c-apps/oils_cstore.c b/Open-ILS/src/c-apps/oils_cstore.c index 63bdc7748f..c580fa3025 100644 --- a/Open-ILS/src/c-apps/oils_cstore.c +++ b/Open-ILS/src/c-apps/oils_cstore.c @@ -1725,6 +1725,7 @@ static char* SELECT ( jsonObject* found = NULL; char* string = NULL; + int from_function = 0; int first = 1; int gfirst = 1; //int hfirst = 1; @@ -1752,13 +1753,17 @@ static char* SELECT ( jsonIteratorFree( tmp_itr ); snode = NULL; + } else if (join_hash->type == JSON_ARRAY) { + from_function = 1; + selhash = NULL; + } else if (join_hash->type == JSON_STRING) { core_class = jsonObjectToSimpleString( join_hash ); join_hash = NULL; } - // punt if we don't know about the core class - if (!(core_meta = osrfHashGet( oilsIDL(), core_class ))) { + // punt if we don't know about the core class (and it's not a function) + if (!from_function && !(core_meta = osrfHashGet( oilsIDL(), core_class ))) { free(core_class); return NULL; } @@ -1786,7 +1791,8 @@ static char* SELECT ( growing_buffer* group_buf = buffer_init(128); growing_buffer* having_buf = buffer_init(128); - core_fields = osrfHashGet(core_meta, "fields"); + if (!from_function) + core_fields = osrfHashGet(core_meta, "fields"); // ... and if we /are/ building the default list, do that if ( (_tmp = jsonObjectGetKey(selhash,core_class)) && !_tmp->size ) { @@ -1794,355 +1800,366 @@ static char* SELECT ( int i = 0; char* field; - osrfStringArray* keys = osrfHashKeys( core_fields ); - while ( (field = osrfStringArrayGetString(keys, i++)) ) { - if ( strncasecmp( "true", osrfHashGet( osrfHashGet( core_fields, field ), "virtual" ), 4 ) ) - jsonObjectPush( _tmp, jsonNewObject( field ) ); - } - osrfStringArrayFree(keys); + if (!from_function) { + osrfStringArray* keys = osrfHashKeys( core_fields ); + while ( (field = osrfStringArrayGetString(keys, i++)) ) { + if ( strncasecmp( "true", osrfHashGet( osrfHashGet( core_fields, field ), "virtual" ), 4 ) ) + jsonObjectPush( _tmp, jsonNewObject( field ) ); + } + osrfStringArrayFree(keys); + } } // Now we build the actual select list - int sel_pos = 1; - jsonObject* is_agg = jsonObjectFindPath(selhash, "//aggregate"); - first = 1; - gfirst = 1; - jsonIterator* selclass_itr = jsonNewIterator( selhash ); - while ( (selclass = jsonIteratorNext( selclass_itr )) ) { - - // round trip through the idl, just to be safe - idlClass = osrfHashGet( oilsIDL(), selclass_itr->key ); - if (!idlClass) continue; - char* cname = osrfHashGet(idlClass, "classname"); - - // make sure the target relation is in the join tree - if (strcmp(core_class,cname)) { - if (!join_hash) continue; - - if (join_hash->type == JSON_STRING) { - string = jsonObjectToSimpleString(join_hash); - found = strcmp(string,cname) ? NULL : jsonParseString("{\"1\":\"1\"}"); - free(string); - } else { - found = jsonObjectFindPath(join_hash, "//%s", cname); - } - - if (!found->size) { - jsonObjectFree(found); - continue; - } - - jsonObjectFree(found); - } - - // stitch together the column list ... - jsonIterator* select_itr = jsonNewIterator( selclass ); - while ( (selfield = jsonIteratorNext( select_itr )) ) { - - char* __column = NULL; - char* __alias = NULL; - - // ... if it's a sstring, just toss it on the pile - if (selfield->type == JSON_STRING) { - - // again, just to be safe - char* _requested_col = jsonObjectToSimpleString(selfield); - osrfHash* field = osrfHashGet( osrfHashGet( idlClass, "fields" ), _requested_col ); - free(_requested_col); - - if (!field) continue; - __column = strdup(osrfHashGet(field, "name")); - - if (first) { - first = 0; - } else { - buffer_add(select_buf, ","); - } - - if (locale) { - char* i18n = osrfHashGet(field, "i18n"); - if (flags & DISABLE_I18N) - i18n = NULL; - - if ( i18n && !strncasecmp("true", i18n, 4)) { - char* pkey = osrfHashGet(idlClass, "primarykey"); - char* tname = osrfHashGet(idlClass, "tablename"); - - buffer_fadd(select_buf, " oils_i18n_xlate('%s', '%s', '%s', '%s', \"%s\".%s::TEXT, '%s') AS \"%s\"", tname, cname, __column, pkey, cname, pkey, locale, __column); - } else { - buffer_fadd(select_buf, " \"%s\".%s AS \"%s\"", cname, __column, __column); - } - } else { - buffer_fadd(select_buf, " \"%s\".%s AS \"%s\"", cname, __column, __column); - } - - // ... but it could be an object, in which case we check for a Field Transform - } else { - - __column = jsonObjectToSimpleString( jsonObjectGetKeyConst( selfield, "column" ) ); - - // again, just to be safe - osrfHash* field = osrfHashGet( osrfHashGet( idlClass, "fields" ), __column ); - if (!field) continue; - const char* fname = osrfHashGet(field, "name"); - - if (first) { - first = 0; - } else { - buffer_add(select_buf, ","); - } + if (!from_function) { + int sel_pos = 1; + jsonObject* is_agg = jsonObjectFindPath(selhash, "//aggregate"); + first = 1; + gfirst = 1; + jsonIterator* selclass_itr = jsonNewIterator( selhash ); + while ( (selclass = jsonIteratorNext( selclass_itr )) ) { + + // round trip through the idl, just to be safe + idlClass = osrfHashGet( oilsIDL(), selclass_itr->key ); + if (!idlClass) continue; + char* cname = osrfHashGet(idlClass, "classname"); + + // make sure the target relation is in the join tree + if (strcmp(core_class,cname)) { + if (!join_hash) continue; + + if (join_hash->type == JSON_STRING) { + string = jsonObjectToSimpleString(join_hash); + found = strcmp(string,cname) ? NULL : jsonParseString("{\"1\":\"1\"}"); + free(string); + } else { + found = jsonObjectFindPath(join_hash, "//%s", cname); + } + + if (!found->size) { + jsonObjectFree(found); + continue; + } + + jsonObjectFree(found); + } + + // stitch together the column list ... + jsonIterator* select_itr = jsonNewIterator( selclass ); + while ( (selfield = jsonIteratorNext( select_itr )) ) { + + char* __column = NULL; + char* __alias = NULL; + + // ... if it's a sstring, just toss it on the pile + if (selfield->type == JSON_STRING) { + + // again, just to be safe + char* _requested_col = jsonObjectToSimpleString(selfield); + osrfHash* field = osrfHashGet( osrfHashGet( idlClass, "fields" ), _requested_col ); + free(_requested_col); + + if (!field) continue; + __column = strdup(osrfHashGet(field, "name")); + + if (first) { + first = 0; + } else { + buffer_add(select_buf, ","); + } - if ((tmp_const = jsonObjectGetKeyConst( selfield, "alias" ))) { - __alias = jsonObjectToSimpleString( tmp_const ); - } else { - __alias = strdup(__column); - } - - if (jsonObjectGetKeyConst( selfield, "transform" )) { - free(__column); - __column = searchFieldTransform(cname, field, selfield); - buffer_fadd(select_buf, " %s AS \"%s\"", __column, __alias); - } else { if (locale) { - char* i18n = osrfHashGet(field, "i18n"); + char* i18n = osrfHashGet(field, "i18n"); if (flags & DISABLE_I18N) i18n = NULL; - if ( i18n && !strncasecmp("true", i18n, 4)) { + if ( i18n && !strncasecmp("true", i18n, 4)) { char* pkey = osrfHashGet(idlClass, "primarykey"); char* tname = osrfHashGet(idlClass, "tablename"); - buffer_fadd(select_buf, " oils_i18n_xlate('%s', '%s', '%s', '%s', \"%s\".%s::TEXT, '%s') AS \"%s\"", tname, cname, fname, pkey, cname, pkey, locale, __alias); + buffer_fadd(select_buf, " oils_i18n_xlate('%s', '%s', '%s', '%s', \"%s\".%s::TEXT, '%s') AS \"%s\"", tname, cname, __column, pkey, cname, pkey, locale, __column); } else { - buffer_fadd(select_buf, " \"%s\".%s AS \"%s\"", cname, fname, __alias); + buffer_fadd(select_buf, " \"%s\".%s AS \"%s\"", cname, __column, __column); } } else { - buffer_fadd(select_buf, " \"%s\".%s AS \"%s\"", cname, fname, __alias); + buffer_fadd(select_buf, " \"%s\".%s AS \"%s\"", cname, __column, __column); } - } - } - - if (is_agg->size || (flags & SELECT_DISTINCT)) { - if (!jsonBoolIsTrue( jsonObjectGetKey( selfield, "aggregate" ) )) { - if (gfirst) { - gfirst = 0; - } else { - buffer_add(group_buf, ","); - } - - buffer_fadd(group_buf, " %d", sel_pos); - /* - } else if (is_agg = jsonObjectGetKey( selfield, "having" )) { - if (gfirst) { - gfirst = 0; - } else { - buffer_add(group_buf, ","); - } - - __column = searchFieldTransform(cname, field, selfield); - buffer_fadd(group_buf, " %s", __column); - __column = searchFieldTransform(cname, field, selfield); - */ - } - } - - if (__column) free(__column); - if (__alias) free(__alias); - - sel_pos++; - } - - // jsonIteratorFree(select_itr); - } - - // jsonIteratorFree(selclass_itr); + // ... but it could be an object, in which case we check for a Field Transform + } else { + + __column = jsonObjectToSimpleString( jsonObjectGetKeyConst( selfield, "column" ) ); + + // again, just to be safe + osrfHash* field = osrfHashGet( osrfHashGet( idlClass, "fields" ), __column ); + if (!field) continue; + const char* fname = osrfHashGet(field, "name"); + + if (first) { + first = 0; + } else { + buffer_add(select_buf, ","); + } + + if ((tmp_const = jsonObjectGetKeyConst( selfield, "alias" ))) { + __alias = jsonObjectToSimpleString( tmp_const ); + } else { + __alias = strdup(__column); + } + + if (jsonObjectGetKeyConst( selfield, "transform" )) { + free(__column); + __column = searchFieldTransform(cname, field, selfield); + buffer_fadd(select_buf, " %s AS \"%s\"", __column, __alias); + } else { + if (locale) { + char* i18n = osrfHashGet(field, "i18n"); + if (flags & DISABLE_I18N) + i18n = NULL; + + if ( i18n && !strncasecmp("true", i18n, 4)) { + char* pkey = osrfHashGet(idlClass, "primarykey"); + char* tname = osrfHashGet(idlClass, "tablename"); + + buffer_fadd(select_buf, " oils_i18n_xlate('%s', '%s', '%s', '%s', \"%s\".%s::TEXT, '%s') AS \"%s\"", tname, cname, fname, pkey, cname, pkey, locale, __alias); + } else { + buffer_fadd(select_buf, " \"%s\".%s AS \"%s\"", cname, fname, __alias); + } + } else { + buffer_fadd(select_buf, " \"%s\".%s AS \"%s\"", cname, fname, __alias); + } + } + } + + if (is_agg->size || (flags & SELECT_DISTINCT)) { + + if (!jsonBoolIsTrue( jsonObjectGetKey( selfield, "aggregate" ) )) { + if (gfirst) { + gfirst = 0; + } else { + buffer_add(group_buf, ","); + } + + buffer_fadd(group_buf, " %d", sel_pos); + /* + } else if (is_agg = jsonObjectGetKey( selfield, "having" )) { + if (gfirst) { + gfirst = 0; + } else { + buffer_add(group_buf, ","); + } + + __column = searchFieldTransform(cname, field, selfield); + buffer_fadd(group_buf, " %s", __column); + __column = searchFieldTransform(cname, field, selfield); + */ + } + } + + if (__column) free(__column); + if (__alias) free(__alias); + + sel_pos++; + } + + // jsonIteratorFree(select_itr); + } + + // jsonIteratorFree(selclass_itr); + + if (is_agg) jsonObjectFree(is_agg); + } else { + buffer_add(select_buf, "*"); + } - if (is_agg) jsonObjectFree(is_agg); char* col_list = buffer_release(select_buf); - char* table = getSourceDefinition(core_meta); + char* table = NULL; + if (!from_function) table = getSourceDefinition(core_meta); + else table = searchValueTransform(join_hash); // Put it all together buffer_fadd(sql_buf, "SELECT %s FROM %s AS \"%s\" ", col_list, table, core_class ); free(col_list); free(table); - // Now, walk the join tree and add that clause - if ( join_hash ) { - char* join_clause = searchJOIN( join_hash, core_meta ); - buffer_add(sql_buf, join_clause); - free(join_clause); - } - - if ( search_hash ) { - buffer_add(sql_buf, " WHERE "); - - // and it's on the the WHERE clause - char* pred = searchWHERE( search_hash, core_meta, AND_OP_JOIN ); + if (!from_function) { + // Now, walk the join tree and add that clause + if ( join_hash ) { + char* join_clause = searchJOIN( join_hash, core_meta ); + buffer_add(sql_buf, join_clause); + free(join_clause); + } + + if ( search_hash ) { + buffer_add(sql_buf, " WHERE "); + + // and it's on the the WHERE clause + char* pred = searchWHERE( search_hash, core_meta, AND_OP_JOIN ); + + if (!pred) { + osrfAppSessionStatus( + ctx->session, + OSRF_STATUS_INTERNALSERVERERROR, + "osrfMethodException", + ctx->request, + "Severe query error in WHERE predicate -- see error log for more details" + ); + free(core_class); + buffer_free(having_buf); + buffer_free(group_buf); + buffer_free(order_buf); + buffer_free(sql_buf); + if (defaultselhash) jsonObjectFree(defaultselhash); + return NULL; + } else { + buffer_add(sql_buf, pred); + free(pred); + } + } - if (!pred) { - osrfAppSessionStatus( - ctx->session, - OSRF_STATUS_INTERNALSERVERERROR, - "osrfMethodException", - ctx->request, - "Severe query error in WHERE predicate -- see error log for more details" - ); - free(core_class); - buffer_free(having_buf); - buffer_free(group_buf); - buffer_free(order_buf); - buffer_free(sql_buf); - if (defaultselhash) jsonObjectFree(defaultselhash); - return NULL; - } else { - buffer_add(sql_buf, pred); - free(pred); - } + if ( having_hash ) { + buffer_add(sql_buf, " HAVING "); + + // and it's on the the WHERE clause + char* pred = searchWHERE( having_hash, core_meta, AND_OP_JOIN ); + + if (!pred) { + osrfAppSessionStatus( + ctx->session, + OSRF_STATUS_INTERNALSERVERERROR, + "osrfMethodException", + ctx->request, + "Severe query error in HAVING predicate -- see error log for more details" + ); + free(core_class); + buffer_free(having_buf); + buffer_free(group_buf); + buffer_free(order_buf); + buffer_free(sql_buf); + if (defaultselhash) jsonObjectFree(defaultselhash); + return NULL; + } else { + buffer_add(sql_buf, pred); + free(pred); + } + } + + first = 1; + jsonIterator* class_itr = jsonNewIterator( order_hash ); + while ( (snode = jsonIteratorNext( class_itr )) ) { + + if (!jsonObjectGetKeyConst(selhash,class_itr->key)) + continue; + + if ( snode->type == JSON_HASH ) { + + jsonIterator* order_itr = jsonNewIterator( snode ); + while ( (onode = jsonIteratorNext( order_itr )) ) { + + if (!oilsIDLFindPath( "/%s/fields/%s", class_itr->key, order_itr->key )) + continue; + + char* direction = NULL; + if ( onode->type == JSON_HASH ) { + if ( jsonObjectGetKeyConst( onode, "transform" ) ) { + string = searchFieldTransform( + class_itr->key, + oilsIDLFindPath( "/%s/fields/%s", class_itr->key, order_itr->key ), + onode + ); + } else { + growing_buffer* field_buf = buffer_init(16); + buffer_fadd(field_buf, "\"%s\".%s", class_itr->key, order_itr->key); + string = buffer_release(field_buf); + } + + if ( (tmp_const = jsonObjectGetKeyConst( onode, "direction" )) ) { + direction = jsonObjectToSimpleString(tmp_const); + if (!strncasecmp(direction, "d", 1)) { + free(direction); + direction = " DESC"; + } else { + free(direction); + direction = " ASC"; + } + } + + } else { + string = strdup(order_itr->key); + direction = jsonObjectToSimpleString(onode); + if (!strncasecmp(direction, "d", 1)) { + free(direction); + direction = " DESC"; + } else { + free(direction); + direction = " ASC"; + } + } + + if (first) { + first = 0; + } else { + buffer_add(order_buf, ", "); + } + + buffer_add(order_buf, string); + free(string); + + if (direction) { + buffer_add(order_buf, direction); + } + + } + // jsonIteratorFree(order_itr); + + } else if ( snode->type == JSON_ARRAY ) { + + jsonIterator* order_itr = jsonNewIterator( snode ); + while ( (onode = jsonIteratorNext( order_itr )) ) { + + char* _f = jsonObjectToSimpleString( onode ); + + if (!oilsIDLFindPath( "/%s/fields/%s", class_itr->key, _f)) + continue; + + if (first) { + first = 0; + } else { + buffer_add(order_buf, ", "); + } + + buffer_add(order_buf, _f); + free(_f); + + } + // jsonIteratorFree(order_itr); + + + // IT'S THE OOOOOOOOOOOLD STYLE! + } else { + osrfLogError(OSRF_LOG_MARK, "%s: Possible SQL injection attempt; direct order by is not allowed", MODULENAME); + osrfAppSessionStatus( + ctx->session, + OSRF_STATUS_INTERNALSERVERERROR, + "osrfMethodException", + ctx->request, + "Severe query error -- see error log for more details" + ); + + free(core_class); + buffer_free(having_buf); + buffer_free(group_buf); + buffer_free(order_buf); + buffer_free(sql_buf); + if (defaultselhash) jsonObjectFree(defaultselhash); + jsonIteratorFree(class_itr); + return NULL; + } + + } } - if ( having_hash ) { - buffer_add(sql_buf, " HAVING "); - - // and it's on the the WHERE clause - char* pred = searchWHERE( having_hash, core_meta, AND_OP_JOIN ); - - if (!pred) { - osrfAppSessionStatus( - ctx->session, - OSRF_STATUS_INTERNALSERVERERROR, - "osrfMethodException", - ctx->request, - "Severe query error in HAVING predicate -- see error log for more details" - ); - free(core_class); - buffer_free(having_buf); - buffer_free(group_buf); - buffer_free(order_buf); - buffer_free(sql_buf); - if (defaultselhash) jsonObjectFree(defaultselhash); - return NULL; - } else { - buffer_add(sql_buf, pred); - free(pred); - } - } - - first = 1; - jsonIterator* class_itr = jsonNewIterator( order_hash ); - while ( (snode = jsonIteratorNext( class_itr )) ) { - - if (!jsonObjectGetKeyConst(selhash,class_itr->key)) - continue; - - if ( snode->type == JSON_HASH ) { - - jsonIterator* order_itr = jsonNewIterator( snode ); - while ( (onode = jsonIteratorNext( order_itr )) ) { - - if (!oilsIDLFindPath( "/%s/fields/%s", class_itr->key, order_itr->key )) - continue; - - char* direction = NULL; - if ( onode->type == JSON_HASH ) { - if ( jsonObjectGetKeyConst( onode, "transform" ) ) { - string = searchFieldTransform( - class_itr->key, - oilsIDLFindPath( "/%s/fields/%s", class_itr->key, order_itr->key ), - onode - ); - } else { - growing_buffer* field_buf = buffer_init(16); - buffer_fadd(field_buf, "\"%s\".%s", class_itr->key, order_itr->key); - string = buffer_release(field_buf); - } - - if ( (tmp_const = jsonObjectGetKeyConst( onode, "direction" )) ) { - direction = jsonObjectToSimpleString(tmp_const); - if (!strncasecmp(direction, "d", 1)) { - free(direction); - direction = " DESC"; - } else { - free(direction); - direction = " ASC"; - } - } - - } else { - string = strdup(order_itr->key); - direction = jsonObjectToSimpleString(onode); - if (!strncasecmp(direction, "d", 1)) { - free(direction); - direction = " DESC"; - } else { - free(direction); - direction = " ASC"; - } - } - - if (first) { - first = 0; - } else { - buffer_add(order_buf, ", "); - } - - buffer_add(order_buf, string); - free(string); - - if (direction) { - buffer_add(order_buf, direction); - } - - } - // jsonIteratorFree(order_itr); - - } else if ( snode->type == JSON_ARRAY ) { - - jsonIterator* order_itr = jsonNewIterator( snode ); - while ( (onode = jsonIteratorNext( order_itr )) ) { - - char* _f = jsonObjectToSimpleString( onode ); - - if (!oilsIDLFindPath( "/%s/fields/%s", class_itr->key, _f)) - continue; - - if (first) { - first = 0; - } else { - buffer_add(order_buf, ", "); - } - - buffer_add(order_buf, _f); - free(_f); - - } - // jsonIteratorFree(order_itr); - - - // IT'S THE OOOOOOOOOOOLD STYLE! - } else { - osrfLogError(OSRF_LOG_MARK, "%s: Possible SQL injection attempt; direct order by is not allowed", MODULENAME); - osrfAppSessionStatus( - ctx->session, - OSRF_STATUS_INTERNALSERVERERROR, - "osrfMethodException", - ctx->request, - "Severe query error -- see error log for more details" - ); - - free(core_class); - buffer_free(having_buf); - buffer_free(group_buf); - buffer_free(order_buf); - buffer_free(sql_buf); - if (defaultselhash) jsonObjectFree(defaultselhash); - jsonIteratorFree(class_itr); - return NULL; - } - - } - // jsonIteratorFree(class_itr); string = buffer_release(group_buf); diff --git a/Open-ILS/src/perlmods/OpenILS/Application/Ingest.pm b/Open-ILS/src/perlmods/OpenILS/Application/Ingest.pm index 9cf011ecea..daee2c92c2 100644 --- a/Open-ILS/src/perlmods/OpenILS/Application/Ingest.pm +++ b/Open-ILS/src/perlmods/OpenILS/Application/Ingest.pm @@ -1088,12 +1088,16 @@ sub biblio_descriptor { my $res = $rd_script->run || ($log->error( "Descriptor script died! $@" ) && return undef); $log->debug("Script for biblio descriptor extraction completed successfully"); - if ($res->{date1} ne ' ') { - $res->{date1} =~ tr/ux/00/; + my $d1 = $res->date1; + if ($d1 && $d1 ne ' ') { + $d1 =~ tr/ux/00/; + $res->date1( $d1 ); } - if ($res->{date2} ne ' ') { - $res->{date2} =~ tr/ux/99/; + my $d2 = $res->date2; + if ($d2 && $d2 ne ' ') { + $d2 =~ tr/ux/99/; + $res->date2( $d2 ); } return $res; diff --git a/Open-ILS/src/perlmods/OpenILS/Utils/CStoreEditor.pm b/Open-ILS/src/perlmods/OpenILS/Utils/CStoreEditor.pm index e33e31e014..674fea1127 100644 --- a/Open-ILS/src/perlmods/OpenILS/Utils/CStoreEditor.pm +++ b/Open-ILS/src/perlmods/OpenILS/Utils/CStoreEditor.pm @@ -289,7 +289,7 @@ sub request { my $err; my $argstr = __arg_to_string( (scalar(@params)) == 1 ? $params[0] : \@params); - $self->log(I, "request $method : $argstr"); + $self->log(I, "request $method $argstr"); if( ($self->{xact} or $always_xact) and $self->session->state != OpenSRF::AppSession::CONNECTED() ) { diff --git a/Open-ILS/src/perlmods/OpenILS/Utils/ZClient.pm b/Open-ILS/src/perlmods/OpenILS/Utils/ZClient.pm index 6fa48a5cd5..10080de1a3 100644 --- a/Open-ILS/src/perlmods/OpenILS/Utils/ZClient.pm +++ b/Open-ILS/src/perlmods/OpenILS/Utils/ZClient.pm @@ -1,6 +1,8 @@ package OpenILS::Utils::ZClient; use UNIVERSAL::require; +sub DESTROY {}; + use overload 'bool' => sub { return $_[0]->{connection} ? 1 : 0 }; sub EVENT_NONE { 0 } @@ -85,6 +87,7 @@ sub AUTOLOAD { #------------------------------------------------------------------------------- package OpenILS::Utils::ZClient::ResultSet; +sub DESTROY {}; our $AUTOLOAD; sub new { @@ -128,6 +131,7 @@ sub AUTOLOAD { #------------------------------------------------------------------------------- package OpenILS::Utils::ZClient::Record; +sub DESTROY {}; our $AUTOLOAD; sub new { diff --git a/Open-ILS/src/support-scripts/fine_generator.pl b/Open-ILS/src/support-scripts/fine_generator.pl index 9e04a7820c..d6dc8f138a 100755 --- a/Open-ILS/src/support-scripts/fine_generator.pl +++ b/Open-ILS/src/support-scripts/fine_generator.pl @@ -12,6 +12,7 @@ use OpenSRF::System; my $config = shift || die "bootstrap config required\n"; my $lockfile = shift || "/tmp/generate_fines-LOCK"; +my $grace = int(shift()) || 1; if (-e $lockfile) { open(F,$lockfile); @@ -36,7 +37,7 @@ OpenSRF::System->bootstrap_client( config_file => $config ); my $r = OpenSRF::AppSession ->create( 'open-ils.storage' ) - ->request( 'open-ils.storage.action.circulation.overdue.generate_fines' => 1 ); + ->request( 'open-ils.storage.action.circulation.overdue.generate_fines' => $grace ); while (!$r->complete) { $r->recv }; diff --git a/Open-ILS/src/support-scripts/test-scripts/indb_circ.pl b/Open-ILS/src/support-scripts/test-scripts/indb_circ.pl index b8ed0cae52..ae1b8d676c 100755 --- a/Open-ILS/src/support-scripts/test-scripts/indb_circ.pl +++ b/Open-ILS/src/support-scripts/test-scripts/indb_circ.pl @@ -17,7 +17,7 @@ my ($config, $org_id, $user_id, $copy_id, $copy_barcode) = ('/openils/conf/opensrf_core.xml', 326, 3, 301313, undef); GetOptions( - 'org=o' => \$org_id, + 'org=i' => \$org_id, 'user=i' => \$user_id, 'copy=i' => \$copy_id, 'barcode=s' => \$copy_barcode, @@ -32,6 +32,7 @@ my $CIRC_TEST = { column => 'id', params => [$copy_id, $user_id], result_field => 'matchpoint', + alias => 'matchpoint' }] }, from => 'aou', @@ -40,41 +41,45 @@ my $CIRC_TEST = { my $e = new_editor(); -my $mp_id = $e->json_query($CIRC_TEST)->[0]->{id}; -my $mp = $e->retrieve_config_circ_matrix_ruleset([ - $mp_id, +my $start = time; +my $mp_id = $e->json_query($CIRC_TEST)->[0]->{matchpoint}; + +my $rule_set = $e->search_config_circ_matrix_ruleset([ + {matchpoint => $mp_id}, { flesh => 1, flesh_fields => { 'ccmrs' => ['duration_rule', 'recurring_fine_rule', 'max_fine_rule'] } } -]); +])->[0]; + +my $rundur = time - $start; my $cp = $e->retrieve_asset_copy($copy_id); my ($dur, $recf); # get the actual duration if($cp->loan_duration == 1) { - $dur = $mp->duration_rule->shrt; + $dur = $rule_set->duration_rule->shrt; } elsif($cp->loan_duration == 2) { - $dur = $mp->duration_rule->normal; + $dur = $rule_set->duration_rule->normal; } else { - $dur = $mp->duration_rule->extended; + $dur = $rule_set->duration_rule->extended; } # get the recurring fine level if($cp->fine_level == 1) { - $recf = $mp->recurring_fine_rule->low; + $recf = $rule_set->recurring_fine_rule->low; } elsif($cp->fine_level == 2) { - $recf = $mp->recurring_fine_rule->normal; + $recf = $rule_set->recurring_fine_rule->normal; } else { - $recf = $mp->recurring_fine_rule->high; + $recf = $rule_set->recurring_fine_rule->high; } - -print "Duration [".$mp->duration_rule->name."] = $dur\n"; -print "Recurring fines [".$mp->recurring_fine_rule->name."; interval='". - $mp->recurring_fine_rule->recurance_interval."'] = \$$recf\n"; -print "Max fine [".$mp->max_fine_rule->name."] = \$".$mp->max_fine_rule->amount."\n"; +print "Duration [".$rule_set->duration_rule->name."] = $dur\n"; +print "Recurring fines [".$rule_set->recurring_fine_rule->name."; interval='". + $rule_set->recurring_fine_rule->recurance_interval."'] = \$$recf\n"; +print "Max fine [".$rule_set->max_fine_rule->name."] = \$".$rule_set->max_fine_rule->amount."\n"; +print "took: $rundur\n"; diff --git a/Open-ILS/web/js/dojo/fieldmapper/OrgUtils.js b/Open-ILS/web/js/dojo/fieldmapper/OrgUtils.js index e65dcb35f9..d927fa68c5 100644 --- a/Open-ILS/web/js/dojo/fieldmapper/OrgUtils.js +++ b/Open-ILS/web/js/dojo/fieldmapper/OrgUtils.js @@ -82,9 +82,9 @@ if(!dojo._hasResource["fieldmapper.OrgUtils"]){ continue; } - var parent = fieldmapper.aou.findOrgUnit(x.parent_ou(),true); - if (!parent.children()) parent.children([]); - parent.children().push(x); + var par = fieldmapper.aou.findOrgUnit(x.parent_ou(),true); + if (!par.children()) par.children([]); + par.children().push(x); fieldmapper.aou.OrgCache[x.id()].treePtr = x; } diff --git a/Open-ILS/web/opac/common/js/org_utils.js b/Open-ILS/web/opac/common/js/org_utils.js index 2acf826cb7..b23fb62219 100644 --- a/Open-ILS/web/opac/common/js/org_utils.js +++ b/Open-ILS/web/opac/common/js/org_utils.js @@ -112,9 +112,9 @@ for (var i in orgArraySearcher) { continue; } - var parent = findOrgUnit(x.parent_ou()); - if (!parent.children()) parent.children(new Array()); - parent.children().push(x); + var par = findOrgUnit(x.parent_ou()); + if (!par.children()) par.children(new Array()); + par.children().push(x); } function _tree_killer () { diff --git a/Open-ILS/web/opac/extras/selfcheck/selfcheck.css b/Open-ILS/web/opac/extras/selfcheck/selfcheck.css index b7aa88267c..30645742a2 100644 --- a/Open-ILS/web/opac/extras/selfcheck/selfcheck.css +++ b/Open-ILS/web/opac/extras/selfcheck/selfcheck.css @@ -81,6 +81,15 @@ body { font-size: 12pt; } display: block; visibility: visible; } +#selfck-items-out-done-div { + width: 100%; + text-align: center; + margin-top: 20px; +} +.selfck-done-link { + font-size: 12pt; + font-weight: bold; +} diff --git a/Open-ILS/web/opac/extras/selfcheck/selfcheck.js b/Open-ILS/web/opac/extras/selfcheck/selfcheck.js index 3ac63e0fb8..e723aad3da 100644 --- a/Open-ILS/web/opac/extras/selfcheck/selfcheck.js +++ b/Open-ILS/web/opac/extras/selfcheck/selfcheck.js @@ -19,28 +19,37 @@ ----------------------------------------------------------------- */ var STAFF_SES_PARAM = 'ses'; +var PATRON_BARCODE_COOKIE = 'pbcc'; var patron = null var itemBarcode = null; var itemsOutTemplate = null; var isRenewal = false; var pendingXact = false; -var patronTimeout = 120000; +var patronTimeout = 600000; /* 10 minutes */ var timerId = null; var printWrapper; var printTemplate; var successfulItems = {}; +var scanTimeout = 800; +var scanTimeoutId; +var patronBarcodeRegex; function selfckInit() { var cgi = new CGI(); var staff = grabUser(cookieManager.read(STAFF_SES_PARAM) || cgi.param(STAFF_SES_PARAM)); + selfckSetupPrinter(); + /* XXX we need org information (from the proxy?) var t = fetchOrgSettingDefault(1, 'circ.selfcheck.patron_login_timeout'); patronTimeout = (t) ? parseInt(t) * 1000 : patronTimeout; */ + var reg = fetchOrgSettingDefault(globalOrgTree.id(), 'opac.barcode_regex'); + if(reg) patronBarcodeRegex = new RegExp(reg); + if(!staff) { // should not happen when behind the proxy return alert('Staff must login'); @@ -54,10 +63,7 @@ function selfckInit() { selfckPatronLogin(); }; - $('selfck-item-barcode-input').onkeypress = function(evt) { - if(userPressedEnter(evt)) - selfckCheckout(); - }; + $('selfck-item-barcode-input').onkeypress = selfckItemBarcodeKeypress; // for debugging, allow passing the user barcode via param var urlbc = new CGI().param('patron'); @@ -70,7 +76,55 @@ function selfckInit() { printTemplate = printWrapper.removeChild($n(printWrapper, 'selfck-print-items-template')); itemsOutTemplate = $('selfck-items-out-tbody').removeChild($('selfck-items-out-row')); + selfckTryPatronCookie(); + // selfckMkDummyCirc(); // testing only + +} + +function selfckSetupPrinter() { + try { // Mozilla only + netscape.security.PrivilegeManager.enablePrivilege("UniversalBrowserRead"); + netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect'); + netscape.security.PrivilegeManager.enablePrivilege('UniversalPreferencesRead'); + netscape.security.PrivilegeManager.enablePrivilege('UniversalPreferencesWrite'); + var pref = Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefBranch); + if (pref) + pref.setBoolPref('print.always_print_silent', true); + } catch(E) { + + } +} + +function selfckTryPatronCookie() { + var pb = cookieManager.read(PATRON_BARCODE_COOKIE); + if(pb) { + cookieManager.write(PATRON_BARCODE_COOKIE, ''); + $('selfck-patron-login-input').value = pb; + selfckPatronLogin(); + } +} + + +function selfckItemBarcodeKeypress(evt) { + if(userPressedEnter(evt)) { + clearTimeout(scanTimeoutId); + selfckCheckout(); + } else { + /* If scanTimeout milliseconds have passed and there is + still data in the input box, it's a likely indication + of a partial scan. Select the text so the next scan + will replace the value */ + clearTimeout(scanTimeoutId); + scanTimeoutId = setTimeout( + function() { + if($('selfck-item-barcode-input').value) { + $('selfck-item-barcode-input').select(); + } + }, + scanTimeout + ); + } } /* @@ -100,8 +154,13 @@ function selfckResetTimer() { function selfckLogoutPatron() { $('selfck-item-barcode-input').value = ''; // prevent browser caching $('selfck-patron-login-input').value = ''; - if(patron) // page reload resets everything - location.href = location.href; + if(patron) { + selfckPrint(); + setTimeout( + function() { location.href = location.href; }, + 800 + ); + } } /* @@ -139,6 +198,21 @@ function selfckPatronLogin(barcode) { } /** + * If a user barcode was scanned into the item barcode + * input, log out the current user and log in the new user + */ +function selfckCheckPatronBarcode(itemBc) { + if(patronBarcodeRegex) { + if(itemBc.match(patronBarcodeRegex)) { + cookieManager.write(PATRON_BARCODE_COOKIE, itemBc, -1); + selfckLogoutPatron(); + return true; + } + } + return false; +} + +/** * Sends the checkout request */ function selfckCheckout() { @@ -153,6 +227,9 @@ function selfckCheckout() { itemBarcode = $('selfck-item-barcode-input').value; if(!itemBarcode) return; + if(selfckCheckPatronBarcode(itemBarcode)) + return; + if (itemBarcode in successfulItems) { selfckShowMsgNode({textcode:'dupe-barcode'}); $('selfck-item-barcode-input').select(); @@ -210,7 +287,7 @@ function selfckShowMsgNode(evt) { * Renders a row in the checkouts table for the current circulation */ function selfckDislplayCheckout(evt) { - unHideMe($('selfck-items-out-table')); + unHideMe($('selfck-items-out-table-wrapper')); var template = itemsOutTemplate.cloneNode(true); var copy = evt.payload.copy; @@ -279,8 +356,11 @@ function selfckRenew() { * Sets the print date and prints the page */ function selfckPrint() { - appendClear($('selfck-print-date'), text(new Date().toLocaleString())); - window.print(); + for(var x in successfulItems) { // make sure we've checked out at least one item + appendClear($('selfck-print-date'), text(new Date().toLocaleString())); + window.print(); + return; + } } diff --git a/Open-ILS/web/opac/extras/selfcheck/selfcheck.xml b/Open-ILS/web/opac/extras/selfcheck/selfcheck.xml index b2a98dc282..4337899087 100644 --- a/Open-ILS/web/opac/extras/selfcheck/selfcheck.xml +++ b/Open-ILS/web/opac/extras/selfcheck/selfcheck.xml @@ -73,16 +73,8 @@ @@ -113,6 +105,7 @@
+
@@ -120,33 +113,39 @@ - - - - - - - - - - - - - - - - - - - - - - - -
&selfck.barcode;&selfck.title;&selfck.author;&selfck.due_date;&selfck.remaining;&selfck.cotype;
- &selfck.cotype_co; - &selfck.cotype_rn; -
+
+ + + + + + + + + + + + + + + + + + + + + + + +
&selfck.barcode;&selfck.title;&selfck.author;&selfck.due_date;&selfck.remaining;&selfck.cotype;
+ &selfck.cotype_co; + &selfck.cotype_rn; +
+ +
diff --git a/Open-ILS/web/opac/locale/en-US/opac.dtd b/Open-ILS/web/opac/locale/en-US/opac.dtd index c493fbbb05..0ef11d91b6 100644 --- a/Open-ILS/web/opac/locale/en-US/opac.dtd +++ b/Open-ILS/web/opac/locale/en-US/opac.dtd @@ -645,6 +645,7 @@ Ensure Caps-Lock is off and try again or contact your local library."> + @@ -655,8 +656,7 @@ Ensure Caps-Lock is off and try again or contact your local library."> - - + @@ -666,5 +666,4 @@ Ensure Caps-Lock is off and try again or contact your local library."> - diff --git a/Open-ILS/web/opac/skin/default/js/myopac.js b/Open-ILS/web/opac/skin/default/js/myopac.js index 14c83e246e..a3a4fdc1dc 100644 --- a/Open-ILS/web/opac/skin/default/js/myopac.js +++ b/Open-ILS/web/opac/skin/default/js/myopac.js @@ -349,7 +349,7 @@ function myOPACDrawHolds(r) { unHideMe($n(row, 'myopac_hold_unfrozen_false')) if(h.thaw_date()) { var d = dojo.date.stamp.fromISOString(h.thaw_date()); - $n(row, 'myopac_holds_frozen_until').appendChild(text(dojo.date.locale.format(d, {.selector: 'date', fullYear: true}))); + $n(row, 'myopac_holds_frozen_until').appendChild(text(dojo.date.locale.format(d, {selector: 'date', fullYear: true}))); } } else { unHideMe($n(row, 'myopac_hold_unfrozen_true')) -- 2.11.0