static void clear_query_stack( void );
static const jsonObject* verifyUserPCRUD( osrfMethodContext* );
-static int verifyObjectPCRUD( osrfMethodContext*, const jsonObject*, const int );
+static int verifyObjectPCRUD( osrfMethodContext*, osrfHash*, const jsonObject*, int );
static const char* org_tree_root( osrfMethodContext* ctx );
static jsonObject* single_hash( const char* key, const char* value );
that it will free whatever else needs freeing.
*/
static void sessionDataFree( char* key, void* item ) {
- if( !strcmp( key, "xact_id" ) || !strcmp( key, "authkey" ) )
+ if( !strcmp( key, "xact_id" ) || !strcmp( key, "authkey" ) || !strncmp( key, "rs_size_", 8) )
free( item );
else if( !strcmp( key, "user_login" ) )
jsonObjectFree( (jsonObject*) item );
}
/**
+ @brief Initialize session cache.
+ @param ctx Pointer to the method context.
+
+ Create a cache for the session by making the session's userData member point
+ to an osrfHash instance.
+*/
+static osrfHash* initSessionCache( osrfMethodContext* ctx ) {
+ ctx->session->userData = osrfNewHash();
+ osrfHashSetCallback( (osrfHash*) ctx->session->userData, &sessionDataFree );
+ ctx->session->userDataFree = &userDataFree;
+ return ctx->session->userData;
+}
+
+/**
@brief Save a transaction id.
@param ctx Pointer to the method context.
// If the session doesn't already have a hash, create one. Make sure
// that the application session frees the hash when it terminates.
- if( NULL == cache ) {
- session->userData = cache = osrfNewHash();
- osrfHashSetCallback( cache, &sessionDataFree );
- ctx->session->userDataFree = &userDataFree;
- }
+ if( NULL == cache )
+ cache = initSessionCache( ctx );
// Save the transaction id in the hash, with the key "xact_id"
osrfHashSet( cache, strdup( session->session_id ), "xact_id" );
// If the session doesn't already have a hash, create one. Make sure
// that the application session frees the hash when it terminates.
- if( NULL == cache ) {
- session->userData = cache = osrfNewHash();
- osrfHashSetCallback( cache, &sessionDataFree );
- ctx->session->userDataFree = &userDataFree;
- }
+ if( NULL == cache )
+ cache = initSessionCache( ctx );
osrfHash* pcache = osrfHashGet(cache, "pcache");
// If the session doesn't already have a hash, create one. Make sure
// that the application session frees the hash when it terminates.
- if( NULL == cache ) {
- session->userData = cache = osrfNewHash();
- osrfHashSetCallback( cache, &sessionDataFree );
- ctx->session->userDataFree = &userDataFree;
- }
+ if( NULL == cache )
+ cache = initSessionCache( ctx );
if( user_login )
osrfHashSet( cache, user_login, "user_login" );
// If the session doesn't already have a hash, create one. Make sure
// that the application session frees the hash when it terminates.
- if( NULL == cache ) {
- session->userData = cache = osrfNewHash();
- osrfHashSetCallback( cache, &sessionDataFree );
- ctx->session->userDataFree = &userDataFree;
- }
+ if( NULL == cache )
+ cache = initSessionCache( ctx );
// Save the transaction id in the hash, with the key "xact_id"
if( authkey && *authkey )
static const char* getAuthkey( osrfMethodContext* ctx ) {
if( ctx && ctx->session && ctx->session->userData ) {
const char* authkey = osrfHashGet( (osrfHash*) ctx->session->userData, "authkey" );
+ // LFW recent changes mean the userData hash gets set up earlier, but
+ // doesn't necessarily have an authkey yet
+ if (!authkey)
+ return NULL;
// Possibly reset the authentication timeout to keep the login alive. We do so
// no more than once per method call, and not at all if it has been only a short
return -1;
}
- // Return each row to the client (except that some may be suppressed by PCRUD)
- jsonObject* cur = 0;
- unsigned long res_idx = 0;
- while((cur = jsonObjectGetIndex( obj, res_idx++ ) )) {
- if( enforce_pcrud && !verifyObjectPCRUD( ctx, cur, obj->size ))
- continue;
- osrfAppRespond( ctx, cur );
- }
+ // doFieldmapperSearch() now takes care of our responding for us
+// // Return each row to the client
+// jsonObject* cur = 0;
+// unsigned long res_idx = 0;
+//
+// while((cur = jsonObjectGetIndex( obj, res_idx++ ) )) {
+// // We used to discard based on perms here, but now that's
+// // inside doFieldmapperSearch()
+// osrfAppRespond( ctx, cur );
+// }
+
jsonObjectFree( obj );
osrfAppRespondComplete( ctx, NULL );
jsonObject* cur;
unsigned long res_idx = 0;
while((cur = jsonObjectGetIndex( obj, res_idx++ ) )) {
- if( enforce_pcrud && !verifyObjectPCRUD( ctx, cur, obj->size ))
- continue; // Suppress due to lack of permission
- else
- osrfAppRespond( ctx,
- oilsFMGetObject( cur, osrfHashGet( class_meta, "primarykey" ) ) );
+ // We used to discard based on perms here, but now that's
+ // inside doFieldmapperSearch()
+ osrfAppRespond( ctx,
+ oilsFMGetObject( cur, osrfHashGet( class_meta, "primarykey" ) ) );
}
jsonObjectFree( obj );
}
if( enforce_pcrud )
- return verifyObjectPCRUD( ctx, param, 1 );
+ return verifyObjectPCRUD( ctx, class, param, 1 );
else
return 1;
}
/**
@brief For PCRUD: Determine whether the current user may access the current row.
@param ctx Pointer to the method context.
+ @param class Same as ctx->method->userData's item for key "class" except when called in recursive doFieldmapperSearch
@param obj Pointer to the row being potentially accessed.
@return 1 if access is permitted, or 0 if it isn't.
The @a obj parameter points to a JSON_HASH of column values, keyed on column name.
*/
-static int verifyObjectPCRUD ( osrfMethodContext* ctx, const jsonObject* obj, const int rs_size ) {
+static int verifyObjectPCRUD ( osrfMethodContext* ctx, osrfHash *class, const jsonObject* obj, int rs_size ) {
dbhandle = writehandle;
// Figure out what class and method are involved
osrfHash* method_metadata = (osrfHash*) ctx->method->userData;
- osrfHash* class = osrfHashGet( method_metadata, "class" );
const char* method_type = osrfHashGet( method_metadata, "methodtype" );
+ if (!rs_size) {
+ int *rs_size_from_hash = osrfHashGetFmt( (osrfHash *) ctx->session->userData, "rs_size_req_%d", ctx->request );
+ if (rs_size_from_hash) {
+ rs_size = *rs_size_from_hash;
+ osrfLogDebug(OSRF_LOG_MARK, "used rs_size from request-scoped hash: %d", rs_size);
+ }
+ }
+
// Set fetch to 1 in all cases except for inserts, meaning that for local or foreign
// contexts we will do another lookup of the current row, even if we already have a
// previously fetched row image, because the row image in hand may not include the
// Get a list of permissions from the permacrud entry.
osrfStringArray* permission = osrfHashGet( pcrud, "permission" );
if( permission->size == 0 ) {
- osrfLogDebug( OSRF_LOG_MARK, "No permissions required for this action, passing through" );
+ osrfLogDebug(
+ OSRF_LOG_MARK,
+ "No permissions required for this action (class %s), passing through",
+ osrfHashGet(class, "classname")
+ );
return 1;
}
osrfLogDebug( OSRF_LOG_MARK,
"global-level permissions required, fetching top of the org tree" );
+ // no need to check perms for org tree root retrieval
+ osrfHashSet((osrfHash*) ctx->session->userData, "1", "inside_verify");
// check for perm at top of org tree
const char* org_tree_root_id = org_tree_root( ctx );
+ osrfHashSet((osrfHash*) ctx->session->userData, "0", "inside_verify");
+
if( org_tree_root_id ) {
osrfStringArrayAdd( context_org_array, org_tree_root_id );
osrfLogDebug( OSRF_LOG_MARK, "top of the org tree is %s", org_tree_root_id );
if( fetch ) {
// Fetch the row so that we can look at the foreign key(s)
+ osrfHashSet((osrfHash*) ctx->session->userData, "1", "inside_verify");
jsonObject* _tmp_params = single_hash( pkey, pkey_value );
jsonObject* _list = doFieldmapperSearch( ctx, class, _tmp_params, NULL, &err );
jsonObjectFree( _tmp_params );
+ osrfHashSet((osrfHash*) ctx->session->userData, "0", "inside_verify");
param = jsonObjectExtractIndex( _list, 0 );
jsonObjectFree( _list );
// Look up the row to which the foreign key points
jsonObject* _tmp_params = single_hash( foreign_pkey, foreign_pkey_value );
+
+ osrfHashSet((osrfHash*) ctx->session->userData, "1", "inside_verify");
jsonObject* _list = doFieldmapperSearch(
ctx, osrfHashGet( oilsIDL(), class_name ), _tmp_params, NULL, &err );
+ osrfHashSet((osrfHash*) ctx->session->userData, "0", "inside_verify");
jsonObject* _fparam = NULL;
if( _list && JSON_ARRAY == _list->type && _list->size > 0 )
if( enforce_pcrud ) {
// no result, skip this entirely
- if(NULL != obj && !verifyObjectPCRUD( ctx, obj, 1 )) {
+ if(NULL != obj && !verifyObjectPCRUD( ctx, class_def, obj, 1 )) {
jsonObjectFree( obj );
growing_buffer* msg = buffer_init( 128 );
}
}
- osrfAppRespondComplete( ctx, obj );
+ // doFieldmapperSearch() now does the responding for us
+ //osrfAppRespondComplete( ctx, obj );
+ osrfAppRespondComplete( ctx, NULL );
+
jsonObjectFree( obj );
return 0;
}
dbhandle = writehandle;
char* core_class = osrfHashGet( class_meta, "classname" );
+ osrfLogDebug( OSRF_LOG_MARK, "entering doFieldmapperSearch() with core_class %s", core_class );
+
char* pkey = osrfHashGet( class_meta, "primarykey" );
- const jsonObject* _tmp;
+ if (!ctx->session->userData)
+ (void) initSessionCache( ctx );
+
+ char *methodtype = osrfHashGet( (osrfHash *) ctx->method->userData, "methodtype" );
+ char *inside_verify = osrfHashGet( (osrfHash*) ctx->session->userData, "inside_verify" );
+ int need_to_verify = (inside_verify ? !atoi(inside_verify) : 1);
+ int has_controller = osrfStringArrayContains(osrfHashGet(class_meta, "controller"), modulename);
+
+ int i_respond_directly = 0;
+ int flesh_depth = 0;
+
+ // XXX This can be redundant with another instance of the same test that happens
+ // within the functions that call doFieldmapperSearch(), but we have it here to
+ // prevent any non-pcrud-controlled classes from being fleshed on.
+ //
+ // TODO To avoid redundancy, move this block to right before we recurse,
+ // and change the class we're checking to the one we're /about/ to search for,
+ // not the one we're currently searching for.
+ if (
+ (!has_controller && !enforce_pcrud) // cstore client-level case: we require the controller, period
+ || (!has_controller && enforce_pcrud && need_to_verify) // pcrud case: we require the controller in need_to_verify mode
+ ) {
+ osrfLogInfo(OSRF_LOG_MARK, "%s is not listed as a controller for %s, moving on",
+ modulename, core_class);
+ return jsonNewObjectType( JSON_ARRAY ); /* empty */
+ }
char* sql = buildSELECT( where_hash, query_hash, class_meta, ctx );
if( !sql ) {
jsonObject* res_list = jsonNewObjectType( JSON_ARRAY );
jsonObject* row_obj = NULL;
+ // The following two steps are for verifyObjectPCRUD()'s benefit.
+ // 1. get the flesh depth
+ const jsonObject* _tmp = jsonObjectGetKeyConst( query_hash, "flesh" );
+ if( _tmp ) {
+ flesh_depth = (int) jsonObjectGetNumber( _tmp );
+ if( flesh_depth == -1 || flesh_depth > max_flesh_depth )
+ flesh_depth = max_flesh_depth;
+ }
+
+ // 2. figure out one consistent rs_size for verifyObjectPCRUD to use
+ // over the whole life of this request. This means if we've already set
+ // up a rs_size_req_%d, do nothing.
+ // a. Incidentally, we can also use this opportunity to set i_respond_directly
+ int *rs_size = osrfHashGetFmt( (osrfHash *) ctx->session->userData, "rs_size_req_%d", ctx->request );
+ if( !rs_size ) { // pointer null, so value not set in hash
+ // i_respond_directly can only be true at the /top/ of a recursive search, if even that.
+ i_respond_directly = ( *methodtype == 'r' || *methodtype == 'i' || *methodtype == 's' );
+
+ rs_size = (int *) safe_malloc( sizeof(int) ); // will be freed by sessionDataFree()
+ unsigned long long result_count = dbi_result_get_numrows( result );
+ *rs_size = (int) result_count * (flesh_depth + 1); // yes, we could lose some bits, but come on
+ osrfHashSet( (osrfHash *) ctx->session->userData, rs_size, "rs_size_req_%d", ctx->request );
+ }
+
if( dbi_result_first_row( result )) {
// Convert each row to a JSON_ARRAY of column values, and enclose those objects
jsonObjectFree( row_obj );
free( pkey_val );
} else {
- osrfHashSet( dedup, pkey_val, pkey_val );
- jsonObjectPush( res_list, row_obj );
+ if( !enforce_pcrud || !need_to_verify ||
+ verifyObjectPCRUD( ctx, class_meta, row_obj, 0 /* means check user data for rs_size */ )) {
+ osrfHashSet( dedup, pkey_val, pkey_val );
+ jsonObjectPush( res_list, row_obj );
+ }
}
} while( dbi_result_next_row( result ));
osrfHashFree( dedup );
free( sql );
// If we're asked to flesh, and there's anything to flesh, then flesh it
- // (but not for PCRUD, lest the user to bypass permissions by fleshing
- // something that he has no permission to look at).
- if( res_list->size && query_hash && ! enforce_pcrud ) {
- _tmp = jsonObjectGetKeyConst( query_hash, "flesh" );
- if( _tmp ) {
- // Get the flesh depth
- int flesh_depth = (int) jsonObjectGetNumber( _tmp );
- if( flesh_depth == -1 || flesh_depth > max_flesh_depth )
- flesh_depth = max_flesh_depth;
-
- // We need a non-zero flesh depth, and a list of fields to flesh
- const jsonObject* temp_blob = jsonObjectGetKeyConst( query_hash, "flesh_fields" );
+ // (formerly we would skip fleshing if in pcrud mode, but now we support
+ // fleshing even in PCRUD).
+ if( res_list->size ) {
+ jsonObject* temp_blob; // We need a non-zero flesh depth, and a list of fields to flesh
+ jsonObject* flesh_fields;
+ jsonObject* flesh_blob = NULL;
+ osrfStringArray* link_fields = NULL;
+ osrfHash* links = NULL;
+ int want_flesh = 0;
+
+ if( query_hash ) {
+ temp_blob = jsonObjectGetKey( query_hash, "flesh_fields" );
if( temp_blob && flesh_depth > 0 ) {
- jsonObject* flesh_blob = jsonObjectClone( temp_blob );
- const jsonObject* flesh_fields = jsonObjectGetKeyConst( flesh_blob, core_class );
+ flesh_blob = jsonObjectClone( temp_blob );
+ flesh_fields = jsonObjectGetKey( flesh_blob, core_class );
- osrfStringArray* link_fields = NULL;
- osrfHash* links = osrfHashGet( class_meta, "links" );
+ links = osrfHashGet( class_meta, "links" );
// Make an osrfStringArray of the names of fields to be fleshed
if( flesh_fields ) {
jsonIteratorFree( _i );
}
}
+ want_flesh = link_fields ? 1 : 0;
+ }
+ }
- osrfHash* fields = osrfHashGet( class_meta, "fields" );
+ osrfHash* fields = osrfHashGet( class_meta, "fields" );
- // Iterate over the JSON_ARRAY of rows
- jsonObject* cur;
- unsigned long res_idx = 0;
- while((cur = jsonObjectGetIndex( res_list, res_idx++ ) )) {
+ // Iterate over the JSON_ARRAY of rows
+ jsonObject* cur;
+ unsigned long res_idx = 0;
+ while((cur = jsonObjectGetIndex( res_list, res_idx++ ) )) {
- int i = 0;
- const char* link_field;
+ int i = 0;
+ const char* link_field;
- // Iterate over the list of fleshable fields
- while( (link_field = osrfStringArrayGetString(link_fields, i++)) ) {
+ // Iterate over the list of fleshable fields
+ if ( want_flesh ) {
+ while( (link_field = osrfStringArrayGetString(link_fields, i++)) ) {
- osrfLogDebug( OSRF_LOG_MARK, "Starting to flesh %s", link_field );
+ osrfLogDebug( OSRF_LOG_MARK, "Starting to flesh %s", link_field );
- osrfHash* kid_link = osrfHashGet( links, link_field );
- if( !kid_link )
- continue; // Not a link field; skip it
+ osrfHash* kid_link = osrfHashGet( links, link_field );
+ if( !kid_link )
+ continue; // Not a link field; skip it
- osrfHash* field = osrfHashGet( fields, link_field );
- if( !field )
- continue; // Not a field at all; skip it (IDL is ill-formed)
+ osrfHash* field = osrfHashGet( fields, link_field );
+ if( !field )
+ continue; // Not a field at all; skip it (IDL is ill-formed)
- osrfHash* kid_idl = osrfHashGet( oilsIDL(),
- osrfHashGet( kid_link, "class" ));
- if( !kid_idl )
- continue; // The class it links to doesn't exist; skip it
+ osrfHash* kid_idl = osrfHashGet( oilsIDL(),
+ osrfHashGet( kid_link, "class" ));
+ if( !kid_idl )
+ continue; // The class it links to doesn't exist; skip it
- const char* reltype = osrfHashGet( kid_link, "reltype" );
- if( !reltype )
- continue; // No reltype; skip it (IDL is ill-formed)
+ const char* reltype = osrfHashGet( kid_link, "reltype" );
+ if( !reltype )
+ continue; // No reltype; skip it (IDL is ill-formed)
- osrfHash* value_field = field;
+ osrfHash* value_field = field;
- if( !strcmp( reltype, "has_many" )
- || !strcmp( reltype, "might_have" ) ) { // has_many or might_have
- value_field = osrfHashGet(
- fields, osrfHashGet( class_meta, "primarykey" ) );
- }
-
- osrfStringArray* link_map = osrfHashGet( kid_link, "map" );
+ if( !strcmp( reltype, "has_many" )
+ || !strcmp( reltype, "might_have" ) ) { // has_many or might_have
+ value_field = osrfHashGet(
+ fields, osrfHashGet( class_meta, "primarykey" ) );
+ }
- if( link_map->size > 0 ) {
- jsonObject* _kid_key = jsonNewObjectType( JSON_ARRAY );
- jsonObjectPush(
- _kid_key,
- jsonNewObject( osrfStringArrayGetString( link_map, 0 ) )
- );
+ osrfStringArray* link_map = osrfHashGet( kid_link, "map" );
- jsonObjectSetKey(
- flesh_blob,
- osrfHashGet( kid_link, "class" ),
- _kid_key
- );
- };
+ if( link_map->size > 0 ) {
+ jsonObject* _kid_key = jsonNewObjectType( JSON_ARRAY );
+ jsonObjectPush(
+ _kid_key,
+ jsonNewObject( osrfStringArrayGetString( link_map, 0 ) )
+ );
- osrfLogDebug(
- OSRF_LOG_MARK,
- "Link field: %s, remote class: %s, fkey: %s, reltype: %s",
- osrfHashGet( kid_link, "field" ),
+ jsonObjectSetKey(
+ flesh_blob,
osrfHashGet( kid_link, "class" ),
- osrfHashGet( kid_link, "key" ),
- osrfHashGet( kid_link, "reltype" )
+ _kid_key
);
+ };
- const char* search_key = jsonObjectGetString(
- jsonObjectGetIndex( cur,
- atoi( osrfHashGet( value_field, "array_position" ) )
- )
- );
+ osrfLogDebug(
+ OSRF_LOG_MARK,
+ "Link field: %s, remote class: %s, fkey: %s, reltype: %s",
+ osrfHashGet( kid_link, "field" ),
+ osrfHashGet( kid_link, "class" ),
+ osrfHashGet( kid_link, "key" ),
+ osrfHashGet( kid_link, "reltype" )
+ );
- if( !search_key ) {
- osrfLogDebug( OSRF_LOG_MARK, "Nothing to search for!" );
- continue;
- }
+ const char* search_key = jsonObjectGetString(
+ jsonObjectGetIndex( cur,
+ atoi( osrfHashGet( value_field, "array_position" ) )
+ )
+ );
- osrfLogDebug( OSRF_LOG_MARK, "Creating param objects..." );
+ if( !search_key ) {
+ osrfLogDebug( OSRF_LOG_MARK, "Nothing to search for!" );
+ continue;
+ }
- // construct WHERE clause
- jsonObject* where_clause = jsonNewObjectType( JSON_HASH );
- jsonObjectSetKey(
- where_clause,
- osrfHashGet( kid_link, "key" ),
- jsonNewObject( search_key )
- );
+ osrfLogDebug( OSRF_LOG_MARK, "Creating param objects..." );
- // construct the rest of the query, mostly
- // by copying pieces of the previous level of query
- jsonObject* rest_of_query = jsonNewObjectType( JSON_HASH );
- jsonObjectSetKey( rest_of_query, "flesh",
- jsonNewNumberObject( flesh_depth - 1 + link_map->size )
+ // construct WHERE clause
+ jsonObject* where_clause = jsonNewObjectType( JSON_HASH );
+ jsonObjectSetKey(
+ where_clause,
+ osrfHashGet( kid_link, "key" ),
+ jsonNewObject( search_key )
+ );
+
+ // construct the rest of the query, mostly
+ // by copying pieces of the previous level of query
+ jsonObject* rest_of_query = jsonNewObjectType( JSON_HASH );
+ jsonObjectSetKey( rest_of_query, "flesh",
+ jsonNewNumberObject( flesh_depth - 1 + link_map->size )
+ );
+
+ if( flesh_blob )
+ jsonObjectSetKey( rest_of_query, "flesh_fields",
+ jsonObjectClone( flesh_blob ));
+
+ if( jsonObjectGetKeyConst( query_hash, "order_by" )) {
+ jsonObjectSetKey( rest_of_query, "order_by",
+ jsonObjectClone( jsonObjectGetKeyConst( query_hash, "order_by" ))
);
+ }
- if( flesh_blob )
- jsonObjectSetKey( rest_of_query, "flesh_fields",
- jsonObjectClone( flesh_blob ));
+ if( jsonObjectGetKeyConst( query_hash, "select" )) {
+ jsonObjectSetKey( rest_of_query, "select",
+ jsonObjectClone( jsonObjectGetKeyConst( query_hash, "select" ))
+ );
+ }
- if( jsonObjectGetKeyConst( query_hash, "order_by" )) {
- jsonObjectSetKey( rest_of_query, "order_by",
- jsonObjectClone( jsonObjectGetKeyConst( query_hash, "order_by" ))
- );
- }
+ // do the query, recursively, to expand the fleshable field
+ jsonObject* kids = doFieldmapperSearch( ctx, kid_idl,
+ where_clause, rest_of_query, err );
- if( jsonObjectGetKeyConst( query_hash, "select" )) {
- jsonObjectSetKey( rest_of_query, "select",
- jsonObjectClone( jsonObjectGetKeyConst( query_hash, "select" ))
- );
- }
+ jsonObjectFree( where_clause );
+ jsonObjectFree( rest_of_query );
- // do the query, recursively, to expand the fleshable field
- jsonObject* kids = doFieldmapperSearch( ctx, kid_idl,
- where_clause, rest_of_query, err );
+ if( *err ) {
+ osrfStringArrayFree( link_fields );
+ jsonObjectFree( res_list );
+ jsonObjectFree( flesh_blob );
+ return NULL;
+ }
- jsonObjectFree( where_clause );
- jsonObjectFree( rest_of_query );
+ osrfLogDebug( OSRF_LOG_MARK, "Search for %s return %d linked objects",
+ osrfHashGet( kid_link, "class" ), kids->size );
- if( *err ) {
- osrfStringArrayFree( link_fields );
- jsonObjectFree( res_list );
- jsonObjectFree( flesh_blob );
- return NULL;
- }
+ // Traverse the result set
+ jsonObject* X = NULL;
+ if( link_map->size > 0 && kids->size > 0 ) {
+ X = kids;
+ kids = jsonNewObjectType( JSON_ARRAY );
- osrfLogDebug( OSRF_LOG_MARK, "Search for %s return %d linked objects",
- osrfHashGet( kid_link, "class" ), kids->size );
-
- // Traverse the result set
- jsonObject* X = NULL;
- if( link_map->size > 0 && kids->size > 0 ) {
- X = kids;
- kids = jsonNewObjectType( JSON_ARRAY );
-
- jsonObject* _k_node;
- unsigned long res_idx = 0;
- while((_k_node = jsonObjectGetIndex( X, res_idx++ ) )) {
- jsonObjectPush(
- kids,
- jsonObjectClone(
- jsonObjectGetIndex(
- _k_node,
- (unsigned long) atoi(
+ jsonObject* _k_node;
+ unsigned long res_idx = 0;
+ while((_k_node = jsonObjectGetIndex( X, res_idx++ ) )) {
+ jsonObjectPush(
+ kids,
+ jsonObjectClone(
+ jsonObjectGetIndex(
+ _k_node,
+ (unsigned long) atoi(
+ osrfHashGet(
osrfHashGet(
osrfHashGet(
osrfHashGet(
- osrfHashGet(
- oilsIDL(),
- osrfHashGet( kid_link, "class" )
- ),
- "fields"
+ oilsIDL(),
+ osrfHashGet( kid_link, "class" )
),
- osrfStringArrayGetString( link_map, 0 )
+ "fields"
),
- "array_position"
- )
+ osrfStringArrayGetString( link_map, 0 )
+ ),
+ "array_position"
)
)
)
- );
- } // end while loop traversing X
- }
+ )
+ );
+ } // end while loop traversing X
+ }
+
+ if (kids->size > 0) {
- if( !strcmp( osrfHashGet( kid_link, "reltype" ), "has_a" )
- || !strcmp( osrfHashGet( kid_link, "reltype" ), "might_have" )) {
+ if(( !strcmp( osrfHashGet( kid_link, "reltype" ), "has_a" )
+ || !strcmp( osrfHashGet( kid_link, "reltype" ), "might_have" ))
+ ) {
osrfLogDebug(OSRF_LOG_MARK, "Storing fleshed objects in %s",
osrfHashGet( kid_link, "field" ));
jsonObjectSetIndex(
jsonObjectClone( jsonObjectGetIndex( kids, 0 ))
);
}
+ }
- if( !strcmp( osrfHashGet( kid_link, "reltype" ), "has_many" )) {
- // has_many
- osrfLogDebug( OSRF_LOG_MARK, "Storing fleshed objects in %s",
- osrfHashGet( kid_link, "field" ) );
- jsonObjectSetIndex(
- cur,
- (unsigned long) atoi( osrfHashGet( field, "array_position" ) ),
- jsonObjectClone( kids )
- );
- }
-
- if( X ) {
- jsonObjectFree( kids );
- kids = X;
- }
+ if( !strcmp( osrfHashGet( kid_link, "reltype" ), "has_many" )) {
+ // has_many
+ osrfLogDebug( OSRF_LOG_MARK, "Storing fleshed objects in %s",
+ osrfHashGet( kid_link, "field" ) );
+ jsonObjectSetIndex(
+ cur,
+ (unsigned long) atoi( osrfHashGet( field, "array_position" ) ),
+ jsonObjectClone( kids )
+ );
+ }
+ if( X ) {
jsonObjectFree( kids );
+ kids = X;
+ }
- osrfLogDebug( OSRF_LOG_MARK, "Fleshing of %s complete",
- osrfHashGet( kid_link, "field" ) );
- osrfLogDebug( OSRF_LOG_MARK, "%s", jsonObjectToJSON( cur ));
+ jsonObjectFree( kids );
+
+ osrfLogDebug( OSRF_LOG_MARK, "Fleshing of %s complete",
+ osrfHashGet( kid_link, "field" ) );
+ osrfLogDebug( OSRF_LOG_MARK, "%s", jsonObjectToJSON( cur ));
- } // end while loop traversing list of fleshable fields
- } // end while loop traversing res_list
- jsonObjectFree( flesh_blob );
- osrfStringArrayFree( link_fields );
+ } // end while loop traversing list of fleshable fields
}
- }
+
+ if( i_respond_directly ) {
+ if ( *methodtype == 'i' ) {
+ osrfAppRespond( ctx,
+ oilsFMGetObject( cur, osrfHashGet( class_meta, "primarykey" ) ) );
+ } else {
+ osrfAppRespond( ctx, cur );
+ }
+ }
+ } // end while loop traversing res_list
+ jsonObjectFree( flesh_blob );
+ osrfStringArrayFree( link_fields );
}
- return res_list;
+ if( i_respond_directly ) {
+ jsonObjectFree( res_list );
+ return jsonNewObjectType( JSON_ARRAY );
+ } else {
+ return res_list;
+ }
}
id = oilsFMGetString( jsonObjectGetIndex(ctx->params, _obj_pos), pkey );
} else {
- if( enforce_pcrud && !verifyObjectPCRUD( ctx, NULL, 1 )) {
+ if( enforce_pcrud && !verifyObjectPCRUD( ctx, meta, NULL, 1 )) {
osrfAppRespondComplete( ctx, NULL );
return -1;
}
$po = create_purchase_order($mgr,
ordering_agency => $ordering_agency,
provider => $provider->id,
- state => 'on-order'
+ state => 'pending' # will be updated later if activated
) or return $mgr->editor->die_event;
}
use OpenSRF::Utils qw/:datetime/;
use OpenSRF::Utils::Logger qw/:logger/;
use OpenILS::Const qw/:const/;
+use OpenILS::Application::AppUtils;
sub fourty_two { return 42 }
sub NOOP_True { return 1 }
sub NOOP_False { return 0 }
+my $U = 'OpenILS::Application::AppUtils';
+
sub CircIsOpen {
my $self = shift;
my $env = shift;
my $hold = $env->{target};
+ if ($env->{params}->{check_email_notify}) {
+ return 0 unless $U->is_true($hold->email_notify);
+ }
+ if ($env->{params}->{check_sms_notify}) {
+ return 0 unless $hold->sms_notify;
+ }
+ if ($env->{params}->{check_phone_notify}) {
+ return 0 unless $hold->phone_notify;
+ }
+
return 1 if
!$hold->cancel_time and
!$hold->fulfillment_time and
my $hold = $env->{target};
+ if ($env->{params}->{check_email_notify}) {
+ return 0 unless $U->is_true($hold->email_notify);
+ }
+ if ($env->{params}->{check_sms_notify}) {
+ return 0 unless $hold->sms_notify;
+ }
+ if ($env->{params}->{check_phone_notify}) {
+ return 0 unless $hold->phone_notify;
+ }
+
return ($hold->cancel_time) ? 1 : 0;
}
+sub HoldNotifyCheck {
+ my $self = shift;
+ my $env = shift;
+
+ my $hold = $env->{target};
+
+ if ($env->{params}->{check_email_notify}) {
+ return 0 unless $U->is_true($hold->email_notify);
+ }
+ if ($env->{params}->{check_sms_notify}) {
+ return 0 unless $hold->sms_notify;
+ }
+ if ($env->{params}->{check_phone_notify}) {
+ return 0 unless $hold->phone_notify;
+ }
+
+ return 1;
+}
+
1;
BEFORE INSERT OR UPDATE ON config.db_patch_dependencies
FOR EACH ROW EXECUTE PROCEDURE evergreen.array_overlap_check ('deprecates');
-INSERT INTO config.upgrade_log (version, applied_to) VALUES ('0682', :eg_version); -- berick/dbs/tsbere
+INSERT INTO config.upgrade_log (version, applied_to) VALUES ('0683', :eg_version); -- tsbere/berick
CREATE TABLE config.bib_source (
id SERIAL PRIMARY KEY,
$$);
+INSERT INTO action_trigger.event_params (event_def, param, value)
+ VALUES (5, 'check_email_notify', 1);
INSERT INTO action_trigger.hook (
key,
$$
);
+INSERT INTO action_trigger.event_params (event_def, param, value)
+ VALUES (7, 'check_email_notify', 1);
INSERT INTO action_trigger.environment (
event_def,
TRUE
);
+INSERT INTO action_trigger.validator (module,description) VALUES
+ ('HoldNotifyCheck',
+ oils_i18n_gettext(
+ 'HoldNotifyCheck',
+ 'Check Hold notification flag(s)',
+ 'atval',
+ 'description'
+ ));
+
INSERT INTO action_trigger.event_definition (
id,
active,
1,
'Hold waiting for pickup for long time',
'hold_request.long_wait',
- 'NOOP_True',
+ 'HoldNotifyCheck',
'SendEmail',
'6 MONTHS',
'request_time',
(9, 'usr'),
(9, 'current_copy.call_number');
+INSERT INTO action_trigger.event_params (event_def, param, value)
+ VALUES (9, 'check_email_notify', 1);
+
-- trigger data related to acq user requests
INSERT INTO action_trigger.hook (key,core_type,description,passive) VALUES (
(38, 'pickup_lib'),
(38, 'bib_rec.bib_record.simple_record');
+INSERT INTO action_trigger.event_params (event_def, param, value)
+ VALUES (currval('action_trigger.event_definition_id_seq'), 'check_email_notify', 1);
+
----------------------------------------------------------------
-- Seed data for queued record/item exports
----------------------------------------------------------------
'pickup_lib.billing_address'
);
+INSERT INTO action_trigger.event_params (event_def, param, value)
+ VALUES (currval('action_trigger.event_definition_id_seq'), 'check_sms_notify', 1);
+
INSERT INTO action_trigger.hook(
key,
core_type,
--- /dev/null
+BEGIN;
+
+-- check whether patch can be applied
+SELECT evergreen.upgrade_deps_block_check('0683', :eg_version);
+
+INSERT INTO action_trigger.event_params (event_def, param, value)
+ VALUES (5, 'check_email_notify', 1);
+INSERT INTO action_trigger.event_params (event_def, param, value)
+ VALUES (7, 'check_email_notify', 1);
+INSERT INTO action_trigger.event_params (event_def, param, value)
+ VALUES (9, 'check_email_notify', 1);
+INSERT INTO action_trigger.validator (module,description) VALUES
+ ('HoldNotifyCheck',
+ oils_i18n_gettext(
+ 'HoldNotifyCheck',
+ 'Check Hold notification flag(s)',
+ 'atval',
+ 'description'
+ ));
+UPDATE action_trigger.event_definition SET validator = 'HoldNotifyCheck' WHERE id = 9;
+
+-- NOT COVERED: Adding check_sms_notify to the proper trigger. It doesn't have a static id.
+
+COMMIT;
+
+--UNDO
+--UPDATE action_trigger.event_definition SET validator = 'NOOP_True' WHERE id = 9;
+--DELETE FROM action_trigger.event_params WHERE param = 'check_email_notify';
+--DELETE FROM action_trigger.validator WHERE module = 'HoldNotifyCheck';
[% l('Pickup library') %]
</th>
<td>
- [% PROCESS build_org_selector
+ [% INCLUDE build_org_selector
name='pickup_lib' value=ahr.pickup_lib %]
</td>
</tr>
prefs_page = 'notify' %]
<form method='POST'>
-
- <div style="float:right;width:65px;">
- <input type='submit'
- value="[% l('Save') %]"
- alt="[% l('Save') %]"
- class="opac-button" />
- </div>
-
[% setting = 'opac.hold_notify' %]
<input name='[% setting %]' type="hidden"
[% IF ctx.user_setting_map.$setting; %] value='[% ctx.user_setting_map.$setting | html %]' [% END %]/>
[% END %]
</tbody>
</table>
+ <input type='submit' value="[% l('Save') %]" alt="[% l('Save') %]" class="opac-button" />
</form>
[% END %]
IF ctx.user_setting_map.$setting;
thang = ctx.user_setting_map.$setting;
END;
- PROCESS build_org_selector name=setting value=thang;
+ INCLUDE build_org_selector name=setting value=thang;
%]
</td>
</tr>
<td valign='top'>
<strong>[% l("Search Library") %]</strong><br />
[% PROCESS "opac/parts/org_selector.tt2";
- PROCESS build_org_selector show_loc_groups=1 %]
+ INCLUDE build_org_selector show_loc_groups=1 %]
<div style="position:relative;top:7px;">
<input type='checkbox' name="modifier"
value="available"[% CGI.param('modifier').grep('available').size ? ' checked="checked"' : '' %]
IF val == ''; cgi.delete(p); END;
# Delete POST vars unless we asked for them
- UNLESS CGI.url_param(p) OR params.defined(p);
+ UNLESS CGI.url_param(p).defined OR params.defined(p);
cgi.delete(p);
END;
END;
args.issn = xml.findnodes('//*[@tag="022"]/*[@code="a"]').textContent;
args.author = xml.findnodes('//*[@tag="100"]/*[@code="a"]').textContent;
+ # Include subfields 'abnp' to generate a more comprehensive title display in search results
+ titresults = xml.findnodes('//*[@tag="245"]/*[@code="a" or @code="b" or @code="n" or @code="p"]');
+ titresults_content = [];
+ FOR sub IN titresults; titresults_content.push(sub.textContent); END;
+ args.title = titresults_content.join(" ");
# Avoid ugly trailing syntax on brief titles
- args.title = xml.findnodes('//*[@tag="245"]/*[@code="a"]').textContent;
args.title = args.title | replace('[:;/]$', '');
# Provide correct spacing between the subfields
[%
# Org Unit Selector Widget :
-# PROCESS build_org_selector id='selector-id' name='selector-name'
+# INCLUDE build_org_selector id='selector-id' name='selector-name'
# value=org_id show_loc_groups=1/0 can_have_vols_only=1/0
+#
+# NOTE: DO NOT USE PROCESS
+# Use of PROCESS results in internal variables, such as value or org_unit, to "leak" out
BLOCK build_org_selector;
node_stack = [{org => org_unit || ctx.aou_tree}];
<p>
[% l('Pickup location:') %]
[% PROCESS "opac/parts/org_selector.tt2";
- PROCESS build_org_selector name='pickup_lib' value=ctx.default_pickup_lib id='pickup_lib' can_have_vols_only=1 %]
+ INCLUDE build_org_selector name='pickup_lib' value=ctx.default_pickup_lib id='pickup_lib' can_have_vols_only=1 %]
</p>
<p>
[% l('Notify when hold is ready for pickup?') %]
[% END %]
</blockquote>
</p>
- <p>
- [% |l %]If you use the Traveling Library Center (TLC) and ABC Express
- services, please select "Outreach" to have the item delivered
- during your scheduled visit.[% END %]
- </p>
<input type="submit" name="submit" value="[% l('Submit') %]" title="[% l('Submit') %]"
alt="[% l('Submit') %]" class="opac-button" />
[%- END # autosuggest enabled %] />
</span>
[%- INCLUDE "opac/parts/qtype_selector.tt2" id="qtype";
- l(' in '); PROCESS build_org_selector show_loc_groups=1
+ l(' in '); INCLUDE build_org_selector show_loc_groups=1
%]
<span>
<input id='search-submit-go' type="submit" value="[% l('Search') %]" alt="[% l('Search') %]" class="opac-button"
INSERT INTO biblio.record_entry (marc, last_xact_id) SELECT marc, 'IMPORT' FROM marcxml_import;
--- Create call numbers for BR1
-INSERT INTO asset.call_number (record, creator, editor, owning_lib, label, label_class)
- SELECT id, 1, 1, 4, 'CONCERTO ' || id::text, 1
- FROM biblio.record_entry
- WHERE id > 0;
-
--- Create call numbers for BR2
-INSERT INTO asset.call_number (record, creator, editor, owning_lib, label, label_class)
- SELECT id, 1, 1, 5, 'CONCERTO ' || id::text, 1
- FROM biblio.record_entry
- WHERE id > 0;
-
--- Create call numbers for BR4
-INSERT INTO asset.call_number (record, creator, editor, owning_lib, label, label_class)
- SELECT id, 1, 1, 7, 'CONCERTO ' || id::text, 1
- FROM biblio.record_entry
- WHERE id > 0;
-
--- CREATE copies for BR1
-INSERT INTO asset.copy (call_number, circ_lib, creator, editor, loan_duration, fine_level, barcode)
- SELECT id, owning_lib, 1, 1, 1, 1, 'CONC40000' || id::text
- FROM asset.call_number
- WHERE record > 0 AND label LIKE 'CONCERTO %' AND owning_lib = 4;
+CREATE FUNCTION evergreen.populate_call_number (ownlib INTEGER, label TEXT)
+RETURNS void AS $$
+ INSERT INTO asset.call_number (record, creator, editor, owning_lib, label, label_class)
+ SELECT id, 1, 1, $1, $2 || id::text, 1
+ FROM biblio.record_entry
+ WHERE id > 0;
+$$ LANGUAGE SQL;
--- CREATE copies for BR2
-INSERT INTO asset.copy (call_number, circ_lib, creator, editor, loan_duration, fine_level, barcode)
- SELECT id, owning_lib, 1, 1, 1, 1, 'CONC50000' || id::text
- FROM asset.call_number
- WHERE record > 0 AND label LIKE 'CONCERTO %' AND owning_lib = 5;
+CREATE FUNCTION evergreen.populate_copy (circlib INTEGER, ownlib INTEGER, barcode TEXT, label TEXT)
+RETURNS void AS $$
+ INSERT INTO asset.copy (call_number, circ_lib, creator, editor, loan_duration, fine_level, barcode)
+ SELECT id, $1, 1, 1, 1, 1, $3 || id::text
+ FROM asset.call_number
+ WHERE record > 0 AND label LIKE $4 || '%' AND owning_lib = $2;
+$$ LANGUAGE SQL;
--- CREATE copies for BR4
-INSERT INTO asset.copy (call_number, circ_lib, creator, editor, loan_duration, fine_level, barcode)
- SELECT id, owning_lib, 1, 1, 1, 1, 'CONC70000' || id::text
- FROM asset.call_number
- WHERE record > 0 AND label LIKE 'CONCERTO %' AND owning_lib = 7;
+-- Create call numbers
+SELECT evergreen.populate_call_number(4, 'CONCERTO '); -- BR1
+SELECT evergreen.populate_call_number(5, 'CONCERTO '); -- BR2
+SELECT evergreen.populate_call_number(6, 'CONCERTO '); -- BR3
+SELECT evergreen.populate_call_number(7, 'CONCERTO '); -- BR4
+SELECT evergreen.populate_call_number(9, 'CONCERTO '); -- BM1
+SELECT evergreen.populate_call_number(4, 'PERFORM '); -- BR1
+SELECT evergreen.populate_call_number(5, 'PERFORM '); -- BR2
+SELECT evergreen.populate_call_number(6, 'PERFORM '); -- BR3
+SELECT evergreen.populate_call_number(7, 'PERFORM '); -- BR4
+SELECT evergreen.populate_call_number(9, 'PERFORM '); -- BM1
+
+-- Create copies
+SELECT evergreen.populate_copy(4, 4, 'CONC40000', 'CONCERTO'); -- BR1
+SELECT evergreen.populate_copy(5, 5, 'CONC50000', 'CONCERTO'); -- BR2
+SELECT evergreen.populate_copy(6, 6, 'CONC60000', 'CONCERTO'); -- BR3
+SELECT evergreen.populate_copy(7, 7, 'CONC70000', 'CONCERTO'); -- BR4
+SELECT evergreen.populate_copy(9, 9, 'CONC90000', 'CONCERTO'); -- BM1
+
+SELECT evergreen.populate_copy(4, 4, 'CONC41000', 'CONCERTO'); -- BR1
+SELECT evergreen.populate_copy(5, 5, 'CONC51000', 'CONCERTO'); -- BR2
+SELECT evergreen.populate_copy(6, 6, 'CONC61000', 'CONCERTO'); -- BR3
+SELECT evergreen.populate_copy(7, 7, 'CONC71000', 'CONCERTO'); -- BR4
+SELECT evergreen.populate_copy(9, 9, 'CONC91000', 'CONCERTO'); -- BM1
+
+SELECT evergreen.populate_copy(4, 4, 'CONC42000', 'CONCERTO'); -- BR1
+SELECT evergreen.populate_copy(5, 5, 'CONC52000', 'CONCERTO'); -- BR2
+SELECT evergreen.populate_copy(6, 6, 'CONC62000', 'CONCERTO'); -- BR3
+SELECT evergreen.populate_copy(7, 7, 'CONC72000', 'CONCERTO'); -- BR4
+SELECT evergreen.populate_copy(9, 9, 'CONC92000', 'CONCERTO'); -- BM1
+
+SELECT evergreen.populate_copy(4, 4, 'CONC43000', 'CONCERTO'); -- BR1
+SELECT evergreen.populate_copy(5, 5, 'CONC53000', 'CONCERTO'); -- BR2
+SELECT evergreen.populate_copy(6, 6, 'CONC63000', 'CONCERTO'); -- BR3
+SELECT evergreen.populate_copy(7, 7, 'CONC73000', 'CONCERTO'); -- BR4
+SELECT evergreen.populate_copy(9, 9, 'CONC93000', 'CONCERTO'); -- BM1
+
+SELECT evergreen.populate_copy(4, 4, 'CONC44000', 'CONCERTO'); -- BR1
+SELECT evergreen.populate_copy(5, 5, 'CONC54000', 'CONCERTO'); -- BR2
+SELECT evergreen.populate_copy(6, 6, 'CONC64000', 'CONCERTO'); -- BR3
+SELECT evergreen.populate_copy(7, 7, 'CONC74000', 'CONCERTO'); -- BR4
+SELECT evergreen.populate_copy(9, 9, 'CONC94000', 'CONCERTO'); -- BM1
+
+SELECT evergreen.populate_copy(4, 4, 'CONC40000', 'PERFORM'); -- BR1
+SELECT evergreen.populate_copy(5, 5, 'CONC50000', 'PERFORM'); -- BR2
+SELECT evergreen.populate_copy(6, 6, 'CONC60000', 'PERFORM'); -- BR3
+SELECT evergreen.populate_copy(7, 7, 'CONC70000', 'PERFORM'); -- BR4
+SELECT evergreen.populate_copy(9, 9, 'CONC90000', 'PERFORM'); -- BM1
+
+SELECT evergreen.populate_copy(4, 4, 'CONC41000', 'PERFORM'); -- BR1
+SELECT evergreen.populate_copy(5, 5, 'CONC51000', 'PERFORM'); -- BR2
+SELECT evergreen.populate_copy(6, 6, 'CONC61000', 'PERFORM'); -- BR3
+SELECT evergreen.populate_copy(7, 7, 'CONC71000', 'PERFORM'); -- BR4
+SELECT evergreen.populate_copy(9, 9, 'CONC91000', 'PERFORM'); -- BM1
-- Delete some copies, call numbers, and bib records
DELETE FROM biblio.record_entry
GROUP BY bpt.id, acn.record, ac.id;
DROP TABLE marcxml_import;
+DROP FUNCTION evergreen.populate_call_number(INTEGER, TEXT);
+DROP FUNCTION evergreen.populate_copy(INTEGER, INTEGER, TEXT, TEXT);
COMMIT;
.dijitTooltipTable td {padding: 3px;} /* custom class for handling dialog tables */
/* ----------------------------------------------------------------- */
+.autoGridLineNumber {
+ background-color: -moz-dialog;
+ font-weight: bold;
+}
.oils-fm-edit-pane { margin: 5px; }
.oils-fm-edit-pane td { padding: 5px; }
suppressEditFields : null,
suppressFilterFields : null,
hideSelector : false,
+ hideLineNumber : false,
selectorWidth : '1.5',
+ lineNumberWidth : '1.5',
showColumnPicker : false,
columnPickerPrefix : null,
displayLimit : 15,
/* by default, don't show auto-generated (sequence) fields */
showSequenceFields : false,
+ // style the cells in the line number column
+ onStyleRow : function(row) {
+ if (!this.hideLineNumber) {
+ var cellIdx = this.hideSelector ? 0 : 1;
+ dojo.addClass(this.views.views[0].getCellNode(row.index, cellIdx), 'autoGridLineNumber');
+ }
+ },
+
startup : function() {
this.selectionMode = 'single';
this.sequence = openils.widget.AutoGrid.sequence++;
canSort : function(rowIdx) {
if(rowIdx == 1 && !this.hideSelector)
return false;
+ if(this.hideSelector && rowIdx == 1 && !this.hideLineNumber)
+ return false;
+ if(!this.hideSelector && rowIdx == 2 && !this.hideLineNumber)
+ return false;
return true;
},
});
}
+ if(!this.hideLineNumber) {
+ // insert the line number column
+ pushEntry({
+ field : '+lineno',
+ get : function(rowIdx, item) { if(item) return 1 + rowIdx; },
+ width : this.lineNumberWidth,
+ name : '#',
+ nonSelectable : false
+ });
+ }
if(!this.fieldOrder) {
/* no order defined, start with any explicit grid fields */
if (typeof params.prebuilt != 'undefined') obj.prebuilt = params.prebuilt;
if (typeof params.columns == 'undefined') throw('util.list.init: No columns');
- obj.columns = [];
+ obj.columns = [
+ {
+ 'id' : 'lineno',
+ 'label' : document.getElementById('offlineStrings').getString('list.line_number'),
+ 'flex' : '0',
+ 'no_sort' : 'true',
+ 'properties' : 'ordinal', // column properties for css styling
+ 'hidden' : 'false',
+ 'editable' : false,
+ 'render' : function(my,scratch) {
+ // special code will handle this based on the attribute we set
+ // here. All cells for this column need to be updated whenever
+ // a list adds, removes, or sorts rows
+ return '_';
+ }
+ }
+ ];
for (var i = 0; i < params.columns.length; i++) {
if (typeof params.columns[i] == 'object') {
obj.columns.push( params.columns[i] );
}
if (rparams && params.attributes) {
for (var i in params.attributes) {
- rparams.my_node.setAttribute(i,params.attributes[i]);
+ rparams.treeitem_node.setAttribute(i,params.attributes[i]);
}
}
this.row_count.total++;
if (this.row_count.fleshed == this.row_count.total) {
setTimeout( function() { obj.exec_on_all_fleshed(); }, 0 );
}
- rparams.my_node.setAttribute('unique_row_counter',obj.unique_row_counter);
+ rparams.treeitem_node.setAttribute('unique_row_counter',obj.unique_row_counter);
rparams.unique_row_counter = obj.unique_row_counter++;
if (typeof params.on_append == 'function') {
params.on_append(rparams);
}
if (rparams && params.attributes) {
for (var i in params.attributes) {
- rparams.my_node.setAttribute(i,params.attributes[i]);
+ rparams.treeitem_node.setAttribute(i,params.attributes[i]);
}
}
this.row_count.fleshed--;
}
}
- params.row_node = treeitem;
+ params.treeitem_node = treeitem;
params.on_retrieve = function(p) {
try {
p.row = params.row;
obj._map_row_to_treecell(p,treerow);
inc_fleshed();
- var idx = obj.node.contentView.getIndexOfItem( params.row_node );
+ var idx = obj.node.contentView.getIndexOfItem( params.treeitem_node );
dump('idx = ' + idx + '\n');
// if current row is selected, send another select event to re-sync data that the client code fetches on selects
if ( obj.node.view.selection.isSelected( idx ) ) {
} catch(E) {
}
- setTimeout( function() { obj.auto_retrieve(); }, 0 );
+ setTimeout( function() { obj.auto_retrieve(); obj.refresh_ordinals(); }, 0 );
- params.my_node = treeitem;
+ params.treeitem_node = treeitem;
return params;
},
var obj = this;
if (typeof params.row == 'undefined') throw('util.list.refresh_row: Object must contain a row');
- if (typeof params.my_node == 'undefined') throw('util.list.refresh_row: Object must contain a my_node');
- if (params.my_node.nodeName != 'treeitem') throw('util.list.refresh_rwo: my_node must be a treeitem');
+ if (typeof params.treeitem_node == 'undefined') throw('util.list.refresh_row: Object must contain a treeitem_node');
+ if (params.treeitem_node.nodeName != 'treeitem') throw('util.list.refresh_rwo: treeitem_node must be a treeitem');
var s = ('util.list.refresh_row: params = ' + (params) + '\n');
- var treeitem = params.my_node;
+ var treeitem = params.treeitem_node;
treeitem.setAttribute('retrieve_id',params.retrieve_id);
if (typeof params.to_bottom != 'undefined') {
if (typeof params.no_auto_select == 'undefined') {
}
}
- params.row_node = treeitem;
+ params.treeitem_node = treeitem;
params.on_retrieve = function(p) {
try {
p.row = params.row;
obj._map_row_to_treecell(p,treerow);
inc_fleshed();
- var idx = obj.node.contentView.getIndexOfItem( params.row_node );
+ var idx = obj.node.contentView.getIndexOfItem( params.treeitem_node );
dump('idx = ' + idx + '\n');
// if current row is selected, send another select event to re-sync data that the client code fetches on selects
if ( obj.node.view.selection.isSelected( idx ) ) {
} catch(E) {
}
- setTimeout( function() { obj.auto_retrieve(); }, 0 );
+ setTimeout( function() { obj.auto_retrieve(); obj.refresh_ordinals(); }, 0 );
JSAN.use('util.widgets'); util.widgets.dispatch('select',obj.node);
return params;
},
+ 'refresh_ordinals' : function() {
+ var obj = this;
+ try {
+ setTimeout( // Otherwise we can miss a row just added
+ function() {
+ var nl = document.getElementsByAttribute('label','_');
+ for (var i = 0; i < nl.length; i++) {
+ nl[i].setAttribute(
+ 'ord_col',
+ 'true'
+ );
+ nl[i].setAttribute( // treecell properties for css styling
+ 'properties',
+ 'ordinal'
+ );
+ }
+ nl = document.getElementsByAttribute('ord_col','true');
+ for (var i = 0; i < nl.length; i++) {
+ nl[i].setAttribute(
+ 'label',
+ // we could just use 'i' here if we trust the order of elements
+ 1 + obj.node.contentView.getIndexOfItem(nl[i].parentNode.parentNode) // treeitem
+ );
+ }
+ }, 1000
+ );
+ } catch(E) {
+ alert('Error in list.js, refresh_ordinals(): ' + E);
+ }
+ },
+
'put_retrieving_label' : function(treerow) {
var obj = this;
try {
//FIXME//Make async and fire when row is visible in list
var row;
- params.row_node = listitem;
+ params.treeitem_node = listitem;
params.on_retrieve = function(row) {
params.row = row;
obj._map_row_to_listcell(params,listitem);
}
this.error.sdump('D_LIST',s);
- params.my_node = listitem;
+ params.treeitem_node = listitem;
return params;
},
'_sort_tree' : function(col,sortDir) {
var obj = this;
try {
- if (obj.node.getAttribute('no_sort')) {
+ if (obj.node.getAttribute('no_sort') || col.getAttribute('no_sort')) {
return;
}
var col_pos;
} catch(E) {
obj.error.standard_unexpected_error_alert('sorting',E);
}
+ obj.refresh_ordinals();
}
);
} catch(E) {
list.actions.save_column_configuration.label=Save Column Configuration
list.actions.save_column_configuration.accesskey=S
list.dump_extended_format.record_separator==-=-=
+list.line_number=#
menu.cmd_survey_wizard.inadequate_perm=You are lacking the CREATE_SURVEY permission and/or working locations.
menu.cmd_local_admin_fonts_and_sounds.tab=Global Font and Sound Settings
menu.cmd_local_admin_printer.tab=Printer Settings Editor
}
function retrieve_row(params) { // callback function for fleshing rows in a list
- params.row_node.setAttribute('retrieve_id',params.row.my.au.id());
+ params.treeitem_node.setAttribute('retrieve_id',params.row.my.au.id());
params.on_retrieve(params.row);
return params.row;
}
if (typeof r_mvr.ilsevent != 'undefined') throw(r_mvr);
row.my.mvr = r_mvr;
- params.row_node.setAttribute(
+ params.treeitem_node.setAttribute(
'retrieve_id', js2JSON( {
'copy_id' : row.my.acp ? row.my.acp.id() : null,
'doc_id' : row.my.mvr ? row.my.mvr.doc_id() : null,
}
);
} else {
- params.row_node.setAttribute(
+ params.treeitem_node.setAttribute(
'retrieve_id', js2JSON( {
'copy_id' : row.my.acp ? row.my.acp.id() : null,
'doc_id' : row.my.mvr ? row.my.mvr.doc_id() : null,
data.node = obj.map_tree[ 'aou_' + parent_org.id() ];
}
var nparams = obj.list.append(data);
- var node = nparams.my_node;
+ obj.list.refresh_ordinals();
+ var node = nparams.treeitem_node;
if (params) {
for (var i in params) {
node.setAttribute(i,params[i]);
'no_auto_select' : true,
};
var nparams = obj.list.append(data);
- var node = nparams.my_node;
+ obj.list.refresh_ordinals();
+ var node = nparams.treeitem_node;
obj.map_tree[ 'acn_' + acn_tree.id() ] = node;
if (params) {
for (var i in params) {
'no_auto_select' : true,
};
var nparams = obj.list.append(data);
- var node = nparams.my_node;
+ obj.list.refresh_ordinals();
+ var node = nparams.treeitem_node;
obj.map_tree[ 'acp_' + acp_item.id() ] = node;
if (params) {
for (var i in params) {
[ row.my.circ.target_copy() ]
);
- params.row_node.setAttribute( 'retrieve_id',row.my.acp.barcode() );
+ params.treeitem_node.setAttribute( 'retrieve_id',row.my.acp.barcode() );
}
);
} else {
- params.row_node.setAttribute( 'retrieve_id',row.my.acp.barcode() );
+ params.treeitem_node.setAttribute( 'retrieve_id',row.my.acp.barcode() );
}
*/
obj.funcs.push(
if (typeof params.on_retrieve == 'function') {
params.on_retrieve(row);
}
+ obj.list.refresh_ordinals();
}
);
if (typeof window.xulG == 'object' && typeof window.xulG.on_select == 'function') {
window.xulG.on_select(list);
}
+ obj.list.refresh_ordinals();
},
'on_dblclick' : function(ev) {
JSAN.use('util.functional');
);
obj.toggle_actions();
util.widgets.dispatch('command','cmd_edit_items');
+ obj.list.refresh_ordinals();
},
'on_select' : function(ev) {
JSAN.use('util.functional');
if (typeof window.xulG == 'object' && typeof window.xulG.on_select == 'function') {
window.xulG.on_select(obj.sel_list);
}
+ obj.list.refresh_ordinals();
},
}
);
row.my.acn = blob.volume;
row.my.ahr = blob.hold;
row.my.circ = blob.circ;
- params.row_node.setAttribute('retrieve_id', js2JSON( [ blob.copy.id(), blob.copy.barcode(), row.my.bucket_item_id ] ));
+ params.treeitem_node.setAttribute('retrieve_id', js2JSON( [ blob.copy.id(), blob.copy.barcode(), row.my.bucket_item_id ] ));
if (typeof params.on_retrieve == 'function') { params.on_retrieve(row); }
} catch(E) {
{
'retrieve_row' : function(params) {
if (params.row.my.bpbcm) {
- params.row_node.setAttribute('retrieve_id',params.row.my.bpbcm.id());
+ params.treeitem_node.setAttribute('retrieve_id',params.row.my.bpbcm.id());
}
params.on_retrieve(params.row);
return params.row;
};
if (barcode && rows[barcode]) {
- var node = rows[barcode].my_node;
+ var node = rows[barcode].treeitem_node;
var parentNode = node.parentNode;
parentNode.removeChild( node );
delete(rows[barcode]);
for (var i = 0; i < ids.length; i++) {
var bpbcm_id = ids[i];
try {
- var node = rows[ bpbcm_barcode_map[ bpbcm_id ] ].my_node;
+ var node = rows[ bpbcm_barcode_map[ bpbcm_id ] ].treeitem_node;
var parentNode = node.parentNode;
parentNode.removeChild( node );
delete(rows[ bpbcm_barcode_map[ bpbcm_id ] ]);
}
}
);
- n.my_node.setAttribute('isbn', function(a){return a;}(obj.result_set[ obj.number_of_result_sets ].records[j].mvr).isbn());
- n.my_node.setAttribute(
+ n.treeitem_node.setAttribute('isbn', function(a){return a;}(obj.result_set[ obj.number_of_result_sets ].records[j].mvr).isbn());
+ n.treeitem_node.setAttribute(
'service',
function(a){return a;}(
results[i].service
)
);
- n.my_node.setAttribute(
+ n.treeitem_node.setAttribute(
'doc_id',
function(a){return a;}(
(obj.result_set[ obj.number_of_result_sets ].records[j].mvr)
).doc_id()
);
- if (!f) { n.my_node.parentNode.focus(); f = n; }
+ if (!f) { n.treeitem_node.parentNode.focus(); f = n; }
}
} else {
x = document.createElement('description'); obj.controller.view.result_message.appendChild(x);
try {
var row = params.row;
if (typeof params.on_retrieve == 'function') params.on_retrieve(row);
- obj.update_no_change_label(params.my_node,row);
+ obj.update_no_change_label(params.treeitem_node,row);
var bill = row.my.mbts;
if (bill && document.getElementById('fine_tally') && ! row.already_tallied) {
params.row.already_tallied = true;
if (typeof obj.list_copyid_map[details.copy.id()][i] == 'undefined') {
obj.list.append(params);
} else {
- params.my_node = obj.list_copyid_map[details.copy.id()][i].my_node;
+ params.treeitem_node = obj.list_copyid_map[details.copy.id()][i].treeitem_node;
obj.list.refresh_row(params);
}
}
function handle_props(row) {
try {
if ( row && row.my && row.my.mbts && Number( row.my.mbts.balance_owed() ) < 0 ) {
- util.widgets.addProperty(params.row_node.firstChild,'refundable');
- util.widgets.addProperty(params.row_node.firstChild.childNodes[ g.payment_pending_column_idx ],'refundable');
+ util.widgets.addProperty(params.treeitem_node.firstChild,'refundable');
+ util.widgets.addProperty(params.treeitem_node.firstChild.childNodes[ g.payment_pending_column_idx ],'refundable');
}
if ( row && row.my && row.my.circ && ! row.my.circ.checkin_time() ) {
$('circulating_hint').hidden = false;
- util.widgets.addProperty(params.row_node.firstChild,'circulating');
- util.widgets.addProperty(params.row_node.firstChild.childNodes[ g.title_column_idx ],'circulating');
+ util.widgets.addProperty(params.treeitem_node.firstChild,'circulating');
+ util.widgets.addProperty(params.treeitem_node.firstChild.childNodes[ g.title_column_idx ],'circulating');
}
} catch(E) {
g.error.sdump('D_WARN','Error setting list properties in bill2.js: ' + E);
}
obj.holds_map[ row.my.ahr.id() ] = blob;
- params.row_node.setAttribute('retrieve_id',
+ params.treeitem_node.setAttribute('retrieve_id',
js2JSON({
'copy_id':copy_id,
'barcode':row.my.acp ? row.my.acp.barcode() : null,
if (typeof robj.copy == 'object' && robj.copy != null) copy_id = robj.copy.id();
}
- params.row_node.setAttribute( 'retrieve_id', js2JSON({'copy_id':copy_id,'circ_id':row.my.circ.id(),'barcode':row.my.acp.barcode(),'doc_id': ( row.my.record ? row.my.record.id() : null ) }) );
+ params.treeitem_node.setAttribute( 'retrieve_id', js2JSON({'copy_id':copy_id,'circ_id':row.my.circ.id(),'barcode':row.my.acp.barcode(),'doc_id': ( row.my.record ? row.my.record.id() : null ) }) );
if (typeof params.on_retrieve == 'function') {
params.on_retrieve(row);
if (typeof row.my.acp == 'object' && row.my.acp != null) copy_id = row.my.acp.id();
}
- params.row_node.setAttribute( 'retrieve_id', js2JSON({'copy_id':row.my.acp.id(),'circ_id':row.my.circ.id(),'barcode':row.my.acp.barcode(),'doc_id': (row.my.record ? row.my.record.id() : null) }) );
+ params.treeitem_node.setAttribute( 'retrieve_id', js2JSON({'copy_id':row.my.acp.id(),'circ_id':row.my.circ.id(),'barcode':row.my.acp.barcode(),'doc_id': (row.my.record ? row.my.record.id() : null) }) );
if (typeof params.on_retrieve == 'function') {
params.on_retrieve(row);
}
try {
var nparams = obj.list_circ_map[circ_id];
if (move_to_bottom_list) {
- obj.list_circ_map[circ_id].my_node.setAttribute('hidden','true');
+ obj.list_circ_map[circ_id].treeitem_node.setAttribute('hidden','true');
var nparams2 = obj.list2.append( { 'row' : { 'my' : { 'circ_id' : circ_id } }, 'to_bottom' : true, 'which_list' : 1 } );
obj.list_circ_map[circ_id] = nparams2;
} else {
if (idx == ids.length) { pm.value = 0; pm.hidden = true; }
var robj = req.getResultObject();
if (robj == '1') {
- var node = rows[ row_id_usrname_map[ id ] ].my_node;
+ var node = rows[ row_id_usrname_map[ id ] ].treeitem_node;
var parentNode = node.parentNode;
parentNode.removeChild( node );
delete(rows[ row_id_usrname_map[ id ] ]);
function gen_on_save_handler(usrname) {
return function() {
try {
- var node = rows[ usrname ].my_node;
+ var node = rows[ usrname ].treeitem_node;
var parentNode = node.parentNode;
parentNode.removeChild( node );
delete(row_id_usrname_map[ rows[ usrname ].row.my.stgu.row_id() ]);
function retrieve_row(params) { // callback function for fleshing rows in a list
try {
- params.row_node.setAttribute('retrieve_id',js2JSON( { 'row_id' : params.row.my.stgu.row_id(), 'usrname' : params.row.my.stgu.usrname() } ));
+ params.treeitem_node.setAttribute('retrieve_id',js2JSON( { 'row_id' : params.row.my.stgu.row_id(), 'usrname' : params.row.my.stgu.usrname() } ));
params.on_retrieve(params.row);
} catch(E) {
alert('Error in staged.js, retrieve_row(): ' + E);
function retrieve_row (params) { // callback function for fleshing rows in a list
- params.row_node.setAttribute('retrieve_id',params.row.my.ausp.id());
+ params.treeitem_node.setAttribute('retrieve_id',params.row.my.ausp.id());
params.on_retrieve(params.row);
return params.row;
}
if (typeof req.ilsevent != 'undefined' || String(req) != '1') {
error.standard_unexpected_error_alert(patronStrings.getFormattedString('staff.patron.standing_penalty.remove_error',[id]),req);
} else {
- var node = rows[ id ].my_node;
+ var node = rows[ id ].treeitem_node;
var parentNode = node.parentNode;
parentNode.removeChild( node );
delete(rows[ id ]);
try {
var res = openils.Util.readResponse(r,true);
/* FIXME - test for success */
- var node = rows[row_id].my_node;
+ var node = rows[row_id].treeitem_node;
var parentNode = node.parentNode;
parentNode.removeChild( node );
delete(rows[row_id]);
}
function retrieve_row(params) { // callback function for fleshing rows in a list
- params.row_node.setAttribute('retrieve_id',params.row.my.atev.id());
+ params.treeitem_node.setAttribute('retrieve_id',params.row.my.atev.id());
params.on_retrieve(params.row);
return params.row;
}
data.node = obj.map_tree[ 'aou_' + parent_org.id() ];
}
var nparams = obj.list.append(data);
- var node = nparams.my_node;
+ var node = nparams.treeitem_node;
if (params) {
for (var i in params) {
node.setAttribute(i,params[i]);
'no_auto_select' : true,
};
var nparams = obj.list.append(data);
- var node = nparams.my_node;
+ var node = nparams.treeitem_node;
obj.map_tree[ 'sdist_' + sdist_tree.id() ] = node;
if (params) {
for (var i in params) {
'no_auto_select' : true,
};
nparams = obj.list.append(sstr_group_node_data);
- obj.map_tree[ 'sdist_sstr_group_' + sdist_tree.id() ] = nparams.my_node;
+ obj.map_tree[ 'sdist_sstr_group_' + sdist_tree.id() ] = nparams.treeitem_node;
} catch(E) {
dump(E+'\n');
alert(E);
};
data['row']['my'][type] = item; // TODO: future optimization: get only the IDs of these leaves, then fetch the full row in 'retrieve_row'
var nparams = obj.list.append(data);
- var node = nparams.my_node;
+ var node = nparams.treeitem_node;
obj.map_tree[ type + '_' + sdist_tree.id() + '_' + item.id() ] = node;
if (label) {
data['row']['my']['label'] = label;
var sitem = robj[0];
obj.list_sitem_map[sitem.id()] = sitem;
row.my.sitem = sitem;
- //params.row_node.setAttribute( 'retrieve_id', js2JSON({'copy_id':copy_id,'circ_id':row.my.circ.id(),'barcode':row.my.acp.barcode(),'doc_id': ( row.my.record ? row.my.record.id() : null ) }) );
- params.row_node.setAttribute( 'retrieve_id', js2JSON({'sitem_id':sitem.id()}) );
+ //params.treeitem_node.setAttribute( 'retrieve_id', js2JSON({'copy_id':copy_id,'circ_id':row.my.circ.id(),'barcode':row.my.acp.barcode(),'doc_id': ( row.my.record ? row.my.record.id() : null ) }) );
+ params.treeitem_node.setAttribute( 'retrieve_id', js2JSON({'sitem_id':sitem.id()}) );
dump('dumping... ' + js2JSON(obj.list_sitem_map[sitem.id()]));
if (typeof params.on_retrieve == 'function') {
params.on_retrieve(row);
data.node = obj.map_tree[ 'aou_' + parent_org.id() ];
}
var nparams = obj.list.append(data);
- var node = nparams.my_node;
+ var node = nparams.treeitem_node;
if (params) {
for (var i in params) {
node.setAttribute(i,params[i]);
'no_auto_select' : true,
};
var nparams = obj.list.append(data);
- var node = nparams.my_node;
+ var node = nparams.treeitem_node;
obj.map_tree[ 'ssub_' + ssub_tree.id() ] = node;
if (params) {
for (var i in params) {
'no_auto_select' : true,
};
nparams = obj.list.append(sdist_group_node_data);
- obj.map_tree[ 'ssub_sdist_group_' + ssub_tree.id() ] = nparams.my_node;
+ obj.map_tree[ 'ssub_sdist_group_' + ssub_tree.id() ] = nparams.treeitem_node;
var siss_group_node_data = {
'row' : {
'no_auto_select' : true,
};
nparams = obj.list.append(siss_group_node_data);
- obj.map_tree[ 'ssub_siss_group_' + ssub_tree.id() ] = nparams.my_node;
+ obj.map_tree[ 'ssub_siss_group_' + ssub_tree.id() ] = nparams.treeitem_node;
var scap_group_node_data = {
'row' : {
'no_auto_select' : true,
};
nparams = obj.list.append(scap_group_node_data);
- obj.map_tree[ 'ssub_scap_group_' + ssub_tree.id() ] = nparams.my_node;
+ obj.map_tree[ 'ssub_scap_group_' + ssub_tree.id() ] = nparams.treeitem_node;
} catch(E) {
dump(E+'\n');
alert(E);
};
data['row']['my'][type] = item; // TODO: future optimization: get only the IDs of these leaves, then fetch the full row in 'retrieve_row'
var nparams = obj.list.append(data);
- var node = nparams.my_node;
+ var node = nparams.treeitem_node;
obj.map_tree[ type + '_' + item.id() ] = node;
if (attributes) {
for (var i in attributes) {
border: thin dashed lightblue ! important;
}
+treechildren::-moz-tree-column(ordinal) {
+ background: -moz-dialog ! important;
+}
+
+treechildren::-moz-tree-cell-text(ordinal) {
+ font-weight: bold ! important;
+}
/*
treechildren::-moz-tree-cell-text(selected,focus) {
color: black;