3 #include "openils/oils_utils.h"
4 #include "openils/oils_idl.h"
6 osrfHash* oilsInitIDL(const char* idl_filename) {
8 char* freeable_filename = NULL;
12 filename = idl_filename;
14 freeable_filename = osrf_settings_host_value("/IDL");
15 filename = freeable_filename;
19 osrfLogError(OSRF_LOG_MARK, "No settings config for '/IDL'");
23 osrfLogInfo(OSRF_LOG_MARK, "Parsing IDL %s", filename);
25 if (!oilsIDLInit( filename )) {
26 osrfLogError(OSRF_LOG_MARK, "Problem loading IDL file [%s]!", filename);
28 free(freeable_filename);
33 free(freeable_filename);
38 @brief Return a const string with the value of a specified column in a row object.
39 @param object Pointer to the row object.
40 @param field Name of the column.
41 @return Pointer to a const string representing the value of the specified column,
42 or NULL in case of error.
44 The row object must be a JSON_ARRAY with a classname. The column value must be a
45 JSON_STRING or a JSON_NUMBER. Any other object type results in a return of NULL.
47 The return value points into the internal contents of the row object, which
50 const char* oilsFMGetStringConst( const jsonObject* object, const char* field ) {
51 return jsonObjectGetString(oilsFMGetObject( object, field ));
55 @brief Return a string with the value of a specified column in a row object.
56 @param object Pointer to the row object.
57 @param field Name of the column.
58 @return Pointer to a newly allocated string representing the value of the specified column,
59 or NULL in case of error.
61 The row object must be a JSON_ARRAY with a classname. The column value must be a
62 JSON_STRING or a JSON_NUMBER. Any other object type results in a return of NULL.
64 The calling code is responsible for freeing the returned string by calling free().
66 char* oilsFMGetString( const jsonObject* object, const char* field ) {
67 return jsonObjectToSimpleString(oilsFMGetObject( object, field ));
71 @brief Return a pointer to the value of a specified column in a row object.
72 @param object Pointer to the row object.
73 @param field Name of the column.
74 @return Pointer to the jsonObject representing the value of the specified column, or NULL
77 The row object must be a JSON_ARRAY with a classname.
79 The return value may point to a JSON_NULL, JSON_STRING, JSON_NUMBER, or JSON_ARRAY. It
80 points into the internal contents of the row object, which retains ownership.
82 const jsonObject* oilsFMGetObject( const jsonObject* object, const char* field ) {
83 if(!(object && field)) return NULL;
84 if( object->type != JSON_ARRAY || !object->classname ) return NULL;
85 int pos = fm_ntop(object->classname, field);
87 return jsonObjectGetIndex( object, pos );
92 int oilsFMSetString( jsonObject* object, const char* field, const char* string ) {
93 if(!(object && field && string)) return -1;
94 osrfLogInternal(OSRF_LOG_MARK, "oilsFMSetString(): Collecing position for field %s", field);
95 int pos = fm_ntop(object->classname, field);
97 osrfLogInternal(OSRF_LOG_MARK, "oilsFMSetString(): Setting string "
98 "%s at field %s [position %d]", string, field, pos );
99 jsonObjectSetIndex( object, pos, jsonNewObject(string) );
106 int oilsUtilsIsDBTrue( const char* val ) {
107 if( val && strcasecmp(val, "f") && strcmp(val, "0") ) return 1;
112 long oilsFMGetObjectId( const jsonObject* obj ) {
115 char* ids = oilsFMGetString( obj, "id" );
123 int oilsUtilsTrackUserActivity(long usr, const char* ewho, const char* ewhat, const char* ehow) {
124 if (!usr && !(ewho || ewhat || ehow)) return 0;
127 jsonObject* params = jsonParseFmt(
128 "{\"from\":[\"actor.insert_usr_activity\", %ld, \"%s\", \"%s\", \"%s\"]}",
130 (NULL == ewho) ? "" : ewho,
131 (NULL == ewhat) ? "" : ewhat,
132 (NULL == ehow) ? "" : ehow
135 osrfAppSession* session = osrfAppSessionClientInit("open-ils.cstore");
136 osrfAppSessionConnect(session);
137 int reqid = osrfAppSessionSendRequest(session, NULL, "open-ils.cstore.transaction.begin", 1);
138 osrfMessage* omsg = osrfAppSessionRequestRecv(session, reqid, 60);
141 osrfMessageFree(omsg);
142 reqid = osrfAppSessionSendRequest(session, params, "open-ils.cstore.json_query", 1);
143 omsg = osrfAppSessionRequestRecv(session, reqid, 60);
146 const jsonObject* rows = osrfMessageGetResult(omsg);
147 if (rows) rowcount = rows->size;
148 osrfMessageFree(omsg); // frees rows
150 reqid = osrfAppSessionSendRequest(session, NULL, "open-ils.cstore.transaction.commit", 1);
151 omsg = osrfAppSessionRequestRecv(session, reqid, 60);
152 osrfMessageFree(omsg);
154 reqid = osrfAppSessionSendRequest(session, NULL, "open-ils.cstore.transaction.rollback", 1);
155 omsg = osrfAppSessionRequestRecv(session, reqid, 60);
156 osrfMessageFree(omsg);
161 osrfAppSessionFree(session); // calls disconnect internally
162 jsonObjectFree(params);
167 static int rootOrgId = 0; // cache the ID of the root org unit.
168 int oilsUtilsGetRootOrgId() {
170 // return the cached value if we have it.
171 if (rootOrgId > 0) return rootOrgId;
173 jsonObject* where_clause = jsonParse("{\"parent_ou\":null}");
174 jsonObject* org = oilsUtilsQuickReq(
176 "open-ils.cstore.direct.actor.org_unit.search",
181 jsonObjectGetNumber(oilsFMGetObject(org, "id"));
183 jsonObjectFree(where_clause);
189 oilsEvent* oilsUtilsCheckPerms( int userid, int orgid, char* permissions[], int size ) {
190 if (!permissions) return NULL;
193 // Check perms against the root org unit if no org unit is provided.
195 orgid = oilsUtilsGetRootOrgId();
197 for( i = 0; i < size && permissions[i]; i++ ) {
198 oilsEvent* evt = NULL;
199 char* perm = permissions[i];
201 jsonObject* params = jsonParseFmt(
202 "{\"from\":[\"permission.usr_has_perm\",\"%d\",\"%s\",\"%d\"]}",
207 jsonObject* result = oilsUtilsCStoreReq(
208 "open-ils.cstore.json_query", params);
210 const jsonObject* hasPermStr =
211 jsonObjectGetKeyConst(result, "permission.usr_has_perm");
213 if (!oilsUtilsIsDBTrue(jsonObjectGetString(hasPermStr))) {
215 OSRF_LOG_MARK, OILS_EVENT_PERM_FAILURE, perm, orgid);
218 jsonObjectFree(params);
219 jsonObjectFree(result);
221 // return first failed permission check.
225 return NULL; // all perm checks succeeded
229 @brief Perform a remote procedure call.
230 @param service The name of the service to invoke.
231 @param method The name of the method to call.
232 @param params The parameters to be passed to the method, if any.
233 @return A copy of whatever the method returns as a result, or a JSON_NULL if the method
234 doesn't return anything.
236 If the @a params parameter points to a JSON_ARRAY, pass each element of the array
237 as a separate parameter. If it points to any other kind of jsonObject, pass it as a
238 single parameter. If it is NULL, pass no parameters.
240 The calling code is responsible for freeing the returned object by calling jsonObjectFree().
242 jsonObject* oilsUtilsQuickReq( const char* service, const char* method,
243 const jsonObject* params ) {
244 if(!(service && method)) return NULL;
246 osrfLogDebug(OSRF_LOG_MARK, "oilsUtilsQuickReq(): %s - %s", service, method );
248 // Open an application session with the service, and send the request
249 osrfAppSession* session = osrfAppSessionClientInit( service );
250 int reqid = osrfAppSessionSendRequest( session, params, method, 1 );
253 osrfMessage* omsg = osrfAppSessionRequestRecv( session, reqid, 60 );
254 jsonObject* result = jsonObjectClone( osrfMessageGetResult(omsg) );
257 osrfMessageFree(omsg);
258 osrfAppSessionFree(session);
263 @brief Call a method of the open-ils.storage service.
264 @param method Name of the method.
265 @param params Parameters to be passed to the method, if any.
266 @return A copy of whatever the method returns as a result, or a JSON_NULL if the method
267 doesn't return anything.
269 If the @a params parameter points to a JSON_ARRAY, pass each element of the array
270 as a separate parameter. If it points to any other kind of jsonObject, pass it as a
271 single parameter. If it is NULL, pass no parameters.
273 The calling code is responsible for freeing the returned object by calling jsonObjectFree().
275 jsonObject* oilsUtilsStorageReq( const char* method, const jsonObject* params ) {
276 return oilsUtilsQuickReq( "open-ils.storage", method, params );
280 @brief Call a method of the open-ils.cstore service.
281 @param method Name of the method.
282 @param params Parameters to be passed to the method, if any.
283 @return A copy of whatever the method returns as a result, or a JSON_NULL if the method
284 doesn't return anything.
286 If the @a params parameter points to a JSON_ARRAY, pass each element of the array
287 as a separate parameter. If it points to any other kind of jsonObject, pass it as a
288 single parameter. If it is NULL, pass no parameters.
290 The calling code is responsible for freeing the returned object by calling jsonObjectFree().
292 jsonObject* oilsUtilsCStoreReq( const char* method, const jsonObject* params ) {
293 return oilsUtilsQuickReq("open-ils.cstore", method, params);
299 @brief Given a username, fetch the corresponding row from the actor.usr table, if any.
300 @param name The username for which to search.
301 @return A Fieldmapper object for the relevant row in the actor.usr table, if it exists;
302 or a JSON_NULL if it doesn't.
304 The calling code is responsible for freeing the returned object by calling jsonObjectFree().
306 jsonObject* oilsUtilsFetchUserByUsername( const char* name ) {
307 if(!name) return NULL;
308 jsonObject* params = jsonParseFmt("{\"usrname\":\"%s\"}", name);
309 jsonObject* user = oilsUtilsQuickReq(
310 "open-ils.cstore", "open-ils.cstore.direct.actor.user.search", params );
312 jsonObjectFree(params);
313 long id = oilsFMGetObjectId(user);
314 osrfLogDebug(OSRF_LOG_MARK, "Fetched user %s:%ld", name, id);
319 @brief Given a barcode, fetch the corresponding row from the actor.usr table, if any.
320 @param name The barcode for which to search.
321 @return A Fieldmapper object for the relevant row in the actor.usr table, if it exists;
322 or a JSON_NULL if it doesn't.
324 Look up the barcode in actor.card. Follow a foreign key from there to get a row in
327 The calling code is responsible for freeing the returned object by calling jsonObjectFree().
329 jsonObject* oilsUtilsFetchUserByBarcode(const char* barcode) {
330 if(!barcode) return NULL;
332 osrfLogInfo(OSRF_LOG_MARK, "Fetching user by barcode %s", barcode);
334 jsonObject* params = jsonParseFmt("{\"barcode\":\"%s\"}", barcode);
335 jsonObject* card = oilsUtilsQuickReq(
336 "open-ils.cstore", "open-ils.cstore.direct.actor.card.search", params );
337 jsonObjectFree(params);
340 return NULL; // No such card
342 // Get the user's id as a double
343 char* usr = oilsFMGetString(card, "usr");
344 jsonObjectFree(card);
346 return NULL; // No user id (shouldn't happen)
347 double iusr = strtod(usr, NULL);
350 // Look up the user in actor.usr
351 params = jsonParseFmt("[%f]", iusr);
352 jsonObject* user = oilsUtilsQuickReq(
353 "open-ils.cstore", "open-ils.cstore.direct.actor.user.retrieve", params);
355 jsonObjectFree(params);
359 char* oilsUtilsFetchOrgSetting( int orgid, const char* setting ) {
360 if(!setting) return NULL;
362 jsonObject* params = jsonParseFmt("[%d, \"%s\"]", orgid, setting );
364 jsonObject* set = oilsUtilsQuickReq(
366 "open-ils.actor.ou_setting.ancestor_default", params);
368 char* value = jsonObjectToSimpleString( jsonObjectGetKeyConst( set, "value" ));
369 jsonObjectFree(params);
371 osrfLogDebug(OSRF_LOG_MARK, "Fetched org [%d] setting: %s => %s", orgid, setting, value);
377 char* oilsUtilsLogin( const char* uname, const char* passwd, const char* type, int orgId ) {
378 if(!(uname && passwd)) return NULL;
380 osrfLogDebug(OSRF_LOG_MARK, "Logging in with username %s", uname );
383 jsonObject* params = jsonParseFmt("[\"%s\"]", uname);
385 jsonObject* o = oilsUtilsQuickReq(
386 "open-ils.auth", "open-ils.auth.authenticate.init", params );
388 const char* seed = jsonObjectGetString(o);
389 char* passhash = md5sum(passwd);
391 snprintf(buf, sizeof(buf), "%s%s", seed, passhash);
392 char* fullhash = md5sum(buf);
395 jsonObjectFree(params);
398 params = jsonParseFmt( "[\"%s\", \"%s\", \"%s\", \"%d\"]", uname, fullhash, type, orgId );
399 o = oilsUtilsQuickReq( "open-ils.auth",
400 "open-ils.auth.authenticate.complete", params );
403 const char* tok = jsonObjectGetString(
404 jsonObjectGetKeyConst( jsonObjectGetKey( o,"payload" ), "authtoken" ));
406 token = strdup( tok );
410 jsonObjectFree(params);
417 jsonObject* oilsUtilsFetchWorkstation( long id ) {
418 jsonObject* p = jsonParseFmt("[%ld]", id);
419 jsonObject* r = oilsUtilsQuickReq(
421 "open-ils.storage.direct.actor.workstation.retrieve", p );
426 jsonObject* oilsUtilsFetchWorkstationByName( const char* name ) {
427 jsonObject* p = jsonParseFmt("{\"name\":\"%s\"}", name);
428 jsonObject* r = oilsUtilsCStoreReq(
429 "open-ils.cstore.direct.actor.workstation.search", p);
435 @brief Convert a string to a number representing a time interval in seconds.
436 @param interval Pointer to string, e.g. "420" or "2 weeks".
437 @return If successful, the number of seconds that the string represents; otherwise -1.
439 If the string is all digits (apart from any leading or trailing white space), convert
440 it directly. Otherwise pass it to PostgreSQL for translation.
442 The result is the same as if we were to pass every string to PostgreSQL, except that,
443 depending on the value of LONG_MAX, we return values for some strings that represent
444 intervals too long for PostgreSQL to represent (i.e. more than 2147483647 seconds).
446 WARNING: a valid interval of -1 second will be indistinguishable from an error. If
447 such an interval is a plausible possibility, don't use this function.
449 long oilsUtilsIntervalToSeconds( const char* s ) {
452 osrfLogWarning( OSRF_LOG_MARK, "String to be converted is NULL" );
456 // Skip leading white space
457 while( isspace( (unsigned char) *s ))
461 osrfLogWarning( OSRF_LOG_MARK, "String to be converted is empty or all white space" );
465 // See if the string is a raw number, i.e. all digits
466 // (apart from any leading or trailing white space)
468 const char* p = s; // For traversing and examining the remaining string
469 if( isdigit( (unsigned char) *p )) {
470 // Looks like a number so far...skip over the digits
473 } while( isdigit( (unsigned char) *p ));
474 // Skip over any following white space
475 while( isspace( (unsigned char) *p ))
478 // This string is a raw number. Convert it directly.
479 long n = strtol( s, NULL, 10 );
480 if( LONG_MAX == n ) {
482 osrfLogWarning( OSRF_LOG_MARK,
483 "String \"%s\"represents a number too big for a long", s );
490 // If we get to this point, the string is not all digits. Pass it to PostgreSQL.
493 jsonObject* query_obj = jsonParseFmt(
494 "{\"from\":[\"config.interval_to_seconds\",\"%s\"]}", s );
497 jsonObject* result = oilsUtilsCStoreReq(
498 "open-ils.cstore.json_query", query_obj );
499 jsonObjectFree( query_obj );
502 const jsonObject* seconds_obj = jsonObjectGetKeyConst( result, "config.interval_to_seconds" );
504 if( seconds_obj && JSON_NUMBER == seconds_obj->type )
505 seconds = (long) jsonObjectGetNumber( seconds_obj );
507 osrfLogError( OSRF_LOG_MARK,
508 "Error calling json_query to convert \"%s\" to seconds", s );
510 jsonObjectFree( result );