From 20dcba1201bb4cdab6b66598c34fba3e38e74402 Mon Sep 17 00:00:00 2001 From: miker Date: Sun, 14 Dec 2008 21:19:44 +0000 Subject: [PATCH] C port of the permacrud service. This touches a lot of code, so expect some early breakage. * The IDL permacrud permission and context org lists are now space-separated instead of pipe-separated. * oils_utils.c now looks for an org unit with a null parent_ou instead of assuming that 1 is correct. * oils_idl-core.c parses the parts of the IDL now, noting the state of the global_required attribute, any class-local context fields and any foreign class context fields. * oils_cstore.c now has a new IDL context and personality, open-ils.pcrud, which (like cstore and reporter-store) ignore classes that do not have the appropriate setting in their controller attribute. * Said new personality will only create methods for classes where both the controller attr contains open-ils.pcrud and there is a permacrud block, and only for those actions listed in the block. * Much (ugly, currently) #ifdef'ing was used to segregate the permacrud code. This was done to avoid breaking cstore and reporter-store, if possible, while pcrud is worked out. ... fun times ... git-svn-id: svn://svn.open-ils.org/ILS/trunk@11543 dcc99617-32d9-48b4-a31d-7c20da2025e4 --- Open-ILS/examples/extract-IDL-permissions.xsl | 4 +- Open-ILS/examples/fm_IDL.xml | 208 ++++++------ Open-ILS/src/c-apps/Makefile.am | 7 +- Open-ILS/src/c-apps/oils_cstore.c | 438 ++++++++++++++++++++------ Open-ILS/src/c-apps/oils_idl-core.c | 154 +++++++++ Open-ILS/src/c-apps/oils_utils.c | 17 +- 6 files changed, 630 insertions(+), 198 deletions(-) diff --git a/Open-ILS/examples/extract-IDL-permissions.xsl b/Open-ILS/examples/extract-IDL-permissions.xsl index 65fbb97b44..4f8375a1e6 100644 --- a/Open-ILS/examples/extract-IDL-permissions.xsl +++ b/Open-ILS/examples/extract-IDL-permissions.xsl @@ -18,8 +18,8 @@ - - + + diff --git a/Open-ILS/examples/fm_IDL.xml b/Open-ILS/examples/fm_IDL.xml index 27d2ddf3f8..65089ada95 100644 --- a/Open-ILS/examples/fm_IDL.xml +++ b/Open-ILS/examples/fm_IDL.xml @@ -135,7 +135,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - + @@ -150,14 +150,14 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - + - + @@ -194,7 +194,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - + @@ -207,7 +207,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - + @@ -243,14 +243,14 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - + - + @@ -267,14 +267,14 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - + - + @@ -300,14 +300,14 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - + - + @@ -325,7 +325,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA @@ -333,7 +333,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - + @@ -350,14 +350,14 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - + - + @@ -376,14 +376,14 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - + - + @@ -400,14 +400,14 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - + - + @@ -431,14 +431,14 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - + - + @@ -456,7 +456,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA @@ -464,7 +464,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - + @@ -481,14 +481,14 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - + - + @@ -506,7 +506,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - + @@ -534,7 +534,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - + @@ -594,7 +594,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - + @@ -616,7 +616,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - + @@ -628,14 +628,14 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - + - + @@ -647,14 +647,14 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - + - + @@ -666,14 +666,14 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - + - + @@ -685,14 +685,14 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - + - + @@ -704,7 +704,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - + @@ -939,7 +939,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - + @@ -968,8 +968,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - - + + @@ -1050,7 +1050,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - + @@ -1062,7 +1062,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - + @@ -1096,7 +1096,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - + @@ -1117,7 +1117,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - + @@ -1141,7 +1141,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - + @@ -1154,13 +1154,13 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - + - + @@ -1172,13 +1172,13 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - + - + @@ -1234,7 +1234,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - + @@ -1258,7 +1258,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - + @@ -1308,13 +1308,13 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - + - + @@ -1348,7 +1348,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - + @@ -1371,7 +1371,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - + @@ -1530,7 +1530,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - + @@ -1597,7 +1597,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - + @@ -1615,7 +1615,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - + @@ -1628,7 +1628,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - + @@ -1741,7 +1741,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - + @@ -1755,13 +1755,13 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - + - + @@ -1781,14 +1781,14 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - + @@ -1802,7 +1802,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - + @@ -1850,7 +1850,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - + @@ -1883,7 +1883,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - + @@ -2161,7 +2161,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - + @@ -2202,7 +2202,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - + @@ -2214,13 +2214,13 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - + - + @@ -2232,13 +2232,13 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - + - + @@ -2255,13 +2255,13 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - + - + @@ -2273,13 +2273,13 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - + - + @@ -2295,7 +2295,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - + @@ -2332,7 +2332,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - + @@ -2364,7 +2364,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - + @@ -2444,7 +2444,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - + @@ -2489,7 +2489,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - + @@ -2648,7 +2648,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - + @@ -2671,7 +2671,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - + @@ -2738,7 +2738,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - + @@ -2829,7 +2829,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - + @@ -2842,7 +2842,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - + @@ -2981,7 +2981,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - + @@ -3074,7 +3074,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - + @@ -3095,7 +3095,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - + @@ -3196,7 +3196,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - + @@ -3214,7 +3214,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - + @@ -3429,7 +3429,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - + @@ -3460,8 +3460,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - - + + @@ -3501,7 +3501,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - + @@ -3518,13 +3518,13 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - + - + @@ -3538,13 +3538,13 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - + - + @@ -3560,13 +3560,13 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - + - + @@ -3618,7 +3618,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - + diff --git a/Open-ILS/src/c-apps/Makefile.am b/Open-ILS/src/c-apps/Makefile.am index 2db42f55cd..1145d48373 100644 --- a/Open-ILS/src/c-apps/Makefile.am +++ b/Open-ILS/src/c-apps/Makefile.am @@ -12,7 +12,7 @@ oils_dataloader_SOURCES = oils_dataloader.c oils_dataloader_LDFLAGS = $(AM_LDFLAGS) -loils_idl oils_dataloader_DEPENDENCIES = liboils_idl.la liboils_utils.la -lib_LTLIBRARIES = liboils_idl.la liboils_utils.la oils_cstore.la oils_rstore.la oils_auth.la +lib_LTLIBRARIES = liboils_idl.la liboils_utils.la oils_cstore.la oils_rstore.la oils_pcrud.la oils_auth.la liboils_idl_la_SOURCES = oils_idl-core.c @@ -27,6 +27,11 @@ oils_rstore_la_CFLAGS = $(AM_CFLAGS) -DRSTORE -c oils_rstore_la_LDFLAGS = $(AM_LDFLAGS) -loils_idl -ldbi -ldbdpgsql -module oils_rstore_la_DEPENDENCIES = liboils_utils.la liboils_idl.la +oils_pcrud_la_SOURCES = oils_cstore.c +oils_pcrud_la_CFLAGS = $(AM_CFLAGS) -DPCRUD -c +oils_pcrud_la_LDFLAGS = $(AM_LDFLAGS) -loils_idl -ldbi -ldbdpgsql -module +oils_pcrud_la_DEPENDENCIES = liboils_utils.la liboils_idl.la + oils_auth_la_SOURCES = oils_auth.c oils_auth_la_LDFLAGS = -module -loils_idl -loils_utils oils_auth_la_DEPENDENCIES = liboils_utils.la diff --git a/Open-ILS/src/c-apps/oils_cstore.c b/Open-ILS/src/c-apps/oils_cstore.c index ae10adb9d3..c4c6f8af03 100644 --- a/Open-ILS/src/c-apps/oils_cstore.c +++ b/Open-ILS/src/c-apps/oils_cstore.c @@ -4,7 +4,7 @@ #include "opensrf/utils.h" #include "opensrf/osrf_json.h" #include "opensrf/log.h" -#include "openils/oils_idl.h" +#include "openils/oils_utils.h" #include #include @@ -15,7 +15,11 @@ #ifdef RSTORE # define MODULENAME "open-ils.reporter-store" #else -# define MODULENAME "open-ils.cstore" +# ifdef PCRUD +# define MODULENAME "open-ils.pcrud" +# else +# define MODULENAME "open-ils.cstore" +# endif #endif #define SUBSELECT 4 @@ -69,6 +73,10 @@ void userDataFree( void* ); static void sessionDataFree( char*, void* ); static char* getSourceDefinition( osrfHash* ); +#ifdef PCRUD +static int verifyObjectPCRUD( osrfMethodContext*, const jsonObject* ); +#endif + static dbi_conn writehandle; /* our MASTER db connection */ static dbi_conn dbhandle; /* our CURRENT db connection */ //static osrfHash * readHandles; @@ -95,19 +103,21 @@ void osrfAppChildExit() { } int osrfAppInitialize() { - growing_buffer* method_name; osrfLogInfo(OSRF_LOG_MARK, "Initializing the CStore Server..."); osrfLogInfo(OSRF_LOG_MARK, "Finding XML file..."); if (!oilsIDLInit( osrf_settings_host_value("/IDL") )) return 1; /* return non-zero to indicate error */ + char* method_str = NULL; + growing_buffer* method_name = buffer_init(64); +#ifndef PCRUD // Generic search thingy - method_name = buffer_init(64); buffer_fadd(method_name, "%s.json_query", MODULENAME); - char* method_str = buffer_data(method_name); + method_str = buffer_data(method_name); osrfAppRegisterMethod( MODULENAME, method_str, "doJSONSearch", "", 1, OSRF_METHOD_STREAMING ); free(method_str); +#endif; // first we register all the transaction and savepoint methods buffer_reset(method_name); @@ -190,6 +200,11 @@ int osrfAppInitialize() { if (!osrfHashGet(idlClass, "fieldmapper")) continue; +#ifdef PCRUD + if (!osrfHashGet(idlClass, "permacrud")) continue; + if (!osrfHashGet( osrfHashGet(idlClass, "permacrud"), method_type )) continue; +#endif + char* readonly = osrfHashGet(idlClass, "readonly"); if ( readonly && !strncasecmp( "true", readonly, 4) && @@ -202,7 +217,7 @@ int osrfAppInitialize() { _fm = strdup( (char*)osrfHashGet(idlClass, "fieldmapper") ); part = strtok_r(_fm, ":", &st_tmp); - growing_buffer* method_name = buffer_init(64); + method_name = buffer_init(64); buffer_fadd(method_name, "%s.direct.%s", MODULENAME, part); while ((part = strtok_r(NULL, ":", &st_tmp))) { @@ -646,12 +661,20 @@ int dispatchCRUDMethod ( osrfMethodContext* ctx ) { } else if (!strcmp(methodtype, "search")) { - obj = doFieldmapperSearch(ctx, class_obj, ctx->params, &err); + jsonObject* _p = jsonObjectClone( ctx->params ); +#ifdef PCRUD + jsonObjectRemoveIndex(_p, 0); +#endif + + obj = doFieldmapperSearch(ctx, class_obj, _p, &err); if(err) return err; jsonObject* cur; jsonIterator* itr = jsonNewIterator( obj ); while ((cur = jsonIteratorNext( itr ))) { +#ifdef PCRUD + if(!verifyObjectPCRUD(ctx, cur)) continue; +#endif osrfAppRespond( ctx, cur ); } jsonIteratorFree(itr); @@ -659,19 +682,28 @@ int dispatchCRUDMethod ( osrfMethodContext* ctx ) { } else if (!strcmp(methodtype, "id_list")) { + int _opt_pos = 1; +#ifdef PCRUD + _opt_pos = 2; +#endif + jsonObject* _p = jsonObjectClone( ctx->params ); - if (jsonObjectGetIndex( _p, 1 )) { - jsonObjectRemoveKey( jsonObjectGetIndex( _p, 1 ), "flesh" ); - jsonObjectRemoveKey( jsonObjectGetIndex( _p, 1 ), "flesh_columns" ); +#ifdef PCRUD + jsonObjectRemoveIndex(_p, 0); +#endif + + if (jsonObjectGetIndex( _p, _opt_pos )) { + jsonObjectRemoveKey( jsonObjectGetIndex( _p, _opt_pos ), "flesh" ); + jsonObjectRemoveKey( jsonObjectGetIndex( _p, _opt_pos ), "flesh_columns" ); } else { - jsonObjectSetIndex( _p, 1, jsonNewObjectType(JSON_HASH) ); + jsonObjectSetIndex( _p, _opt_pos, jsonNewObjectType(JSON_HASH) ); } growing_buffer* sel_list = buffer_init(64); buffer_fadd(sel_list, "{ \"%s\":[\"%s\"] }", osrfHashGet( class_obj, "classname" ), osrfHashGet( class_obj, "primarykey" )); char* _s = buffer_release(sel_list); - jsonObjectSetKey( jsonObjectGetIndex( _p, 1 ), "select", jsonParseString(_s) ); + jsonObjectSetKey( jsonObjectGetIndex( _p, _opt_pos ), "select", jsonParseString(_s) ); osrfLogDebug(OSRF_LOG_MARK, "%s: Select qualifer set to [%s]", MODULENAME, _s); free(_s); @@ -682,20 +714,12 @@ int dispatchCRUDMethod ( osrfMethodContext* ctx ) { jsonObject* cur; jsonIterator* itr = jsonNewIterator( obj ); while ((cur = jsonIteratorNext( itr ))) { +#ifdef PCRUD + if(!verifyObjectPCRUD(ctx, cur)) continue; +#endif osrfAppRespond( ctx, - jsonObjectGetIndex( - cur, - atoi( - osrfHashGet( - osrfHashGet( - osrfHashGet( class_obj, "fields" ), - osrfHashGet( class_obj, "primarykey") - ), - "array_position" - ) - ) - ) + oilsFMGetObject( cur, osrfHashGet( class_obj, "primarykey" ) ) ); } jsonIteratorFree(itr); @@ -712,6 +736,7 @@ int dispatchCRUDMethod ( osrfMethodContext* ctx ) { static int verifyObjectClass ( osrfMethodContext* ctx, const jsonObject* param ) { + int ret = 1; osrfHash* meta = (osrfHash*) ctx->method->userData; osrfHash* class = osrfHashGet( meta, "class" ); @@ -734,14 +759,258 @@ static int verifyObjectClass ( osrfMethodContext* ctx, const jsonObject* param ) return 0; } - return 1; + +#ifdef PCRUD + ret = verifyObjectPCRUD( ctx, param ); +#endif + + return ret; +} + +#ifdef PCRUD +static int verifyObjectPCRUD ( osrfMethodContext* ctx, const jsonObject* obj ) { + + dbhandle = writehandle; + + osrfHash* meta = (osrfHash*) ctx->method->userData; + osrfHash* class = osrfHashGet( meta, "class" ); + char* method_type = strdup( osrfHashGet(meta, "methodtype") ); + + if ( ( *method_type == 's' || *method_type == 'i' ) ) { + free(method_type); + method_type = strdup("retrieve"); + } + + osrfHash* pcrud = osrfHashGet( osrfHashGet(class, "permacrud"), method_type ); + free(method_type); + + if (!pcrud) { + // No permacrud for this method type on this class + + growing_buffer* msg = buffer_init(128); + buffer_fadd( + msg, + "%s: %s on class %s has no permacrud IDL entry", + MODULENAME, + osrfHashGet(meta, "methodtype"), + osrfHashGet(class, "classname") + ); + + char* m = buffer_release(msg); + osrfAppSessionStatus( ctx->session, OSRF_STATUS_BADREQUEST, "osrfMethodException", ctx->request, m ); + + free(m); + + return 0; + } + + //XXX turn this into a user id + char* auth = jsonObjectToSimpleString( jsonObjectGetIndex( ctx->params, 0 ) ); + jsonObject* user = oilsUtilsQuickReq("open-ils.auth","open-ils.auth.session.retrieve", jsonNewObject(auth)); + + if (!user) { + free(auth); + return 0; + } + + int userid = atoi( oilsFMGetString( user, "id" ) ); + + jsonObjectFree(user); + free(auth); + + osrfStringArray* permission = osrfHashGet(pcrud, "permission"); + char* global_required = osrfHashGet(pcrud, "global_required"); + osrfStringArray* local_context = osrfHashGet(pcrud, "local_context"); + osrfHash* foreign_context = osrfHashGet(pcrud, "foreign_context"); + + osrfStringArray* context_org_array = osrfNewStringArray(1); + + char* pkey_value = NULL; + int OK = 0; + int err = 0; + if (global_required && strcmp( "true", global_required )) { + // check for perm at top of org tree + jsonObject* _tmp_params = jsonParseString("{\"parent_ou\":null}"); + jsonObject* _list = doFieldmapperSearch(ctx, oilsIDLFindPath("/aou"), _tmp_params, &err); + + jsonObject* _tree_top = jsonObjectGetIndex(_list, 0); + + if (!_tree_top) { + jsonObjectFree(_tmp_params); + jsonObjectFree(_list); + return -1; + } + + osrfStringArrayAdd( context_org_array, oilsFMGetString( _tree_top, "id" ) ); + + jsonObjectFree(_tmp_params); + jsonObjectFree(_list); + + } else { + + jsonObject *param = NULL; + if (obj) param = jsonObjectClone(obj); + if (!param) param = jsonObjectClone(jsonObjectGetIndex( ctx->params, 1 )); + + // XXX if the object has a non-null pkey, check for object-specific perm, + // else context org(s) for group perm check + char* pkey = osrfHashGet(class, "primarykey"); + + if (param->classname) { + pkey_value = oilsFMGetString( param, pkey ); + + } else { + pkey_value = jsonObjectToSimpleString( param ); + + jsonObject* _tmp_params = jsonParseStringFmt("{\"%s\":\"%s\"}", pkey, pkey_value); + jsonObject* _list = doFieldmapperSearch( + ctx, + class, + _tmp_params, + &err + ); + + jsonObjectFree(param); + param = jsonObjectClone(jsonObjectGetIndex(_list, 0)); + + if (!param) { + jsonObjectFree(_tmp_params); + jsonObjectFree(_list); + return -1; + } + + jsonObjectFree(_tmp_params); + jsonObjectFree(_list); + + } + + if (local_context->size > 0) { + int i = 0; + char* lcontext = NULL; + while ( (lcontext = osrfStringArrayGetString(local_context, i++)) ) { + osrfStringArrayAdd( context_org_array, oilsFMGetString( param, lcontext ) ); + } + } + + if (foreign_context->size > 0) { + osrfStringArray* class_list = osrfHashKeys( foreign_context ); + + int i = 0; + char* class_name = NULL; + while ( (class_name = osrfStringArrayGetString(class_list, i++)) ) { + osrfHash* fcontext = osrfHashGet(foreign_context, class_name); + + jsonObject* _tmp_params = jsonParseStringFmt( + "{\"%s\":\"%s\"}", + osrfHashGet(fcontext, "field"), + oilsFMGetString(param, osrfHashGet(fcontext, "fkey")) + ); + + jsonObject* _list = doFieldmapperSearch( + ctx, + class, + _tmp_params, + &err + ); + + + jsonObject* _fparam = jsonObjectGetIndex(_list, 0); + + if (!_fparam) { + jsonObjectFree(_tmp_params); + jsonObjectFree(_list); + return -1; + } + + jsonObjectFree(_tmp_params); + jsonObjectFree(_list); + + char* foreign_field = NULL; + while ( (foreign_field = osrfStringArrayGetString(osrfHashGet(fcontext,"context"), i++)) ) { + osrfStringArrayAdd( context_org_array, oilsFMGetString( _fparam, foreign_field ) ); + } + + jsonObjectFree(_fparam); + } + + osrfStringArrayFree(class_list); + } + + jsonObjectFree(param); + } + + char* context_org; + char* perm; + + int i = 0; + while ( (perm = osrfStringArrayGetString(permission, i++)) ) { + int j = 0; + while ( (context_org = osrfStringArrayGetString(context_org_array, j++)) ) { + dbi_result result; + + if (pkey_value) { + result = dbi_conn_queryf( + writehandle, + "SELECT permission.usr_has_object_perm(%d, '%s', '%s', '%s', %d) AS has_perm;", + userid, + perm, + osrfHashGet(class, "classname"), + pkey_value, + atoi(context_org) + ); + + if (result) { + jsonObject* return_val = oilsMakeJSONFromResult( result ); + char* has_perm = jsonObjectToSimpleString( jsonObjectGetKeyConst(return_val, "has_perm") ); + if ( *has_perm == 't' ) OK = 1; + free(has_perm); + jsonObjectFree(return_val); + dbi_result_free(result); + break; + } + } + + result = dbi_conn_queryf( + writehandle, + "SELECT permission.usr_has_perm(%d, '%s', %d) AS has_perm;", + userid, + perm, + atoi(context_org) + ); + + if (result) { + jsonObject* return_val = oilsMakeJSONFromResult( result ); + char* has_perm = jsonObjectToSimpleString( jsonObjectGetKeyConst(return_val, "has_perm") ); + if ( *has_perm == 't' ) OK = 1; + free(has_perm); + jsonObjectFree(return_val); + dbi_result_free(result); + break; + } + + } + if (OK) break; + } + + if (pkey_value) free(pkey_value); + osrfStringArrayFree(context_org_array); + + if (!OK) return 0; + return 1; } +#endif + static jsonObject* doCreate(osrfMethodContext* ctx, int* err ) { osrfHash* meta = osrfHashGet( (osrfHash*) ctx->method->userData, "class" ); +#ifdef PCRUD + jsonObject* target = jsonObjectGetIndex( ctx->params, 1 ); + jsonObject* options = jsonObjectGetIndex( ctx->params, 2 ); +#else jsonObject* target = jsonObjectGetIndex( ctx->params, 0 ); jsonObject* options = jsonObjectGetIndex( ctx->params, 1 ); +#endif if (!verifyObjectClass(ctx, target)) { *err = -1; @@ -780,9 +1049,8 @@ static jsonObject* doCreate(osrfMethodContext* ctx, int* err ) { char* trans_id = osrfHashGet( (osrfHash*)ctx->session->userData, "xact_id" ); // Set the last_xact_id - osrfHash* last_xact_id; - if ((last_xact_id = oilsIDLFindPath("/%s/fields/last_xact_id", target->classname))) { - int index = atoi( osrfHashGet(last_xact_id, "array_position") ); + int index = oilsIDL_ntop( target->classname, "last_xact_id" ); + if (index > -1) { osrfLogDebug(OSRF_LOG_MARK, "Setting last_xact_id to %s on %s at position %d", trans_id, target->classname, index); jsonObjectSetIndex(target, index, jsonNewObject(trans_id)); } @@ -814,25 +1082,14 @@ static jsonObject* doCreate(osrfMethodContext* ctx, int* err ) { if(!( strcmp( osrfHashGet(osrfHashGet(fields,field_name), "virtual"), "true" ) )) continue; - jsonObject* field_object = jsonObjectGetIndex( target, atoi(osrfHashGet(field, "array_position")) ); + const jsonObject* field_object = oilsFMGetObject( target, field_name ); char* value; if (field_object && field_object->classname) { - value = jsonObjectToSimpleString( - jsonObjectGetIndex( - field_object, - atoi( - osrfHashGet( - osrfHashGet( - oilsIDLFindPath("/%s/fields", field_object->classname), - (char*)oilsIDLFindPath("/%s/primarykey", field_object->classname) - ), - "array_position" - ) - ) - ) - ); - + value = oilsFMGetString( + field_object, + (char*)oilsIDLFindPath("/%s/primarykey", field_object->classname) + ); } else { value = jsonObjectToSimpleString( field_object ); } @@ -927,8 +1184,7 @@ static jsonObject* doCreate(osrfMethodContext* ctx, int* err ) { *err = -1; } else { - int pos = atoi(osrfHashGet( osrfHashGet(fields, pkey), "array_position" )); - char* id = jsonObjectToSimpleString(jsonObjectGetIndex(target, pos)); + char* id = oilsFMGetString(target, pkey); if (!id) { unsigned long long new_id = dbi_conn_sequence_last(writehandle, seq); growing_buffer* _id = buffer_init(10); @@ -954,7 +1210,7 @@ static jsonObject* doCreate(osrfMethodContext* ctx, int* err ) { jsonObjectSetKey( jsonObjectGetIndex(fake_params, 0), - osrfHashGet(meta, "primarykey"), + pkey, jsonNewObject(id) ); @@ -984,16 +1240,24 @@ static jsonObject* doCreate(osrfMethodContext* ctx, int* err ) { static jsonObject* doRetrieve(osrfMethodContext* ctx, int* err ) { + int id_pos = 0; + int order_pos = 1; + +#ifdef PCRUD + id_pos = 1; + order_pos = 2; +#endif + osrfHash* meta = osrfHashGet( (osrfHash*) ctx->method->userData, "class" ); jsonObject* obj; - char* id = jsonObjectToSimpleString(jsonObjectGetIndex(ctx->params, 0)); - jsonObject* order_hash = jsonObjectGetIndex(ctx->params, 1); + char* id = jsonObjectToSimpleString(jsonObjectGetIndex(ctx->params, id_pos)); + jsonObject* order_hash = jsonObjectGetIndex(ctx->params, order_pos); osrfLogDebug( OSRF_LOG_MARK, - "%s retrieving %s object with id %s", + "%s retrieving %s object with primary key value of %s", MODULENAME, osrfHashGet(meta, "fieldmapper"), id @@ -1024,6 +1288,13 @@ static jsonObject* doRetrieve(osrfMethodContext* ctx, int* err ) { jsonObjectFree( list ); jsonObjectFree( fake_params ); +#ifdef PCRUD + if(!verifyObjectPCRUD(ctx, obj)) { + jsonObjectFree(obj); + return jsonNULL; + } +#endif + return obj; } @@ -2646,8 +2917,7 @@ static jsonObject* doFieldmapperSearch ( osrfMethodContext* ctx, osrfHash* meta, osrfLogDebug(OSRF_LOG_MARK, "Query returned at least one row"); do { obj = oilsMakeFieldmapperFromResult( result, meta ); - int pkey_pos = atoi( osrfHashGet( osrfHashGet( fields, pkey ), "array_position" ) ); - char* pkey_val = jsonObjectToSimpleString( jsonObjectGetIndex( obj, pkey_pos ) ); + char* pkey_val = oilsFMGetString( obj, pkey ); if ( osrfHashGet( dedup, pkey_val ) ) { jsonObjectFree(obj); free(pkey_val); @@ -2916,7 +3186,11 @@ static jsonObject* doFieldmapperSearch ( osrfMethodContext* ctx, osrfHash* meta, static jsonObject* doUpdate(osrfMethodContext* ctx, int* err ) { osrfHash* meta = osrfHashGet( (osrfHash*) ctx->method->userData, "class" ); - jsonObject* target = jsonObjectGetIndex(ctx->params, 0); +#ifdef PCRUD + jsonObject* target = jsonObjectGetIndex( ctx->params, 1 ); +#else + jsonObject* target = jsonObjectGetIndex( ctx->params, 0 ); +#endif if (!verifyObjectClass(ctx, target)) { *err = -1; @@ -2952,9 +3226,8 @@ static jsonObject* doUpdate(osrfMethodContext* ctx, int* err ) { char* trans_id = osrfHashGet( (osrfHash*)ctx->session->userData, "xact_id" ); // Set the last_xact_id - osrfHash* last_xact_id; - if ((last_xact_id = oilsIDLFindPath("/%s/fields/last_xact_id", target->classname))) { - int index = atoi( osrfHashGet(last_xact_id, "array_position") ); + int index = oilsIDL_ntop( target->classname, "last_xact_id" ); + if (index > -1) { osrfLogDebug(OSRF_LOG_MARK, "Setting last_xact_id to %s on %s at position %d", trans_id, target->classname, index); jsonObjectSetIndex(target, index, jsonNewObject(trans_id)); } @@ -2962,13 +3235,7 @@ static jsonObject* doUpdate(osrfMethodContext* ctx, int* err ) { char* pkey = osrfHashGet(meta, "primarykey"); osrfHash* fields = osrfHashGet(meta, "fields"); - char* id = - jsonObjectToSimpleString( - jsonObjectGetIndex( - target, - atoi( osrfHashGet( osrfHashGet( fields, pkey ), "array_position" ) ) - ) - ); + char* id = oilsFMGetString( target, pkey ); osrfLogDebug( OSRF_LOG_MARK, @@ -2993,25 +3260,14 @@ static jsonObject* doUpdate(osrfMethodContext* ctx, int* err ) { if(!( strcmp( field_name, pkey ) )) continue; if(!( strcmp( osrfHashGet(osrfHashGet(fields,field_name), "virtual"), "true" ) )) continue; - jsonObject* field_object = jsonObjectGetIndex( target, atoi(osrfHashGet(field, "array_position")) ); + const jsonObject* field_object = oilsFMGetObject( target, field_name ); char* value; if (field_object && field_object->classname) { - value = jsonObjectToSimpleString( - jsonObjectGetIndex( - field_object, - atoi( - osrfHashGet( - osrfHashGet( - oilsIDLFindPath("/%s/fields", field_object->classname), - (char*)oilsIDLFindPath("/%s/primarykey", field_object->classname) - ), - "array_position" - ) - ) - ) - ); - + value = oilsFMGetString( + field_object, + (char*)oilsIDLFindPath("/%s/primarykey", field_object->classname) + ); } else { value = jsonObjectToSimpleString( field_object ); } @@ -3129,21 +3385,27 @@ static jsonObject* doDelete(osrfMethodContext* ctx, int* err ) { char* pkey = osrfHashGet(meta, "primarykey"); + int _obj_pos = 0; +#ifdef PCRUD + _obj_pos = 1; +#endif + char* id; - if (jsonObjectGetIndex(ctx->params, 0)->classname) { - if (!verifyObjectClass(ctx, jsonObjectGetIndex( ctx->params, 0 ))) { + if (jsonObjectGetIndex(ctx->params, _obj_pos)->classname) { + if (!verifyObjectClass(ctx, jsonObjectGetIndex( ctx->params, _obj_pos ))) { *err = -1; return jsonNULL; } - id = jsonObjectToSimpleString( - jsonObjectGetIndex( - jsonObjectGetIndex(ctx->params, 0), - atoi( osrfHashGet( osrfHashGet( osrfHashGet(meta, "fields"), pkey ), "array_position") ) - ) - ); + id = oilsFMGetString( jsonObjectGetIndex(ctx->params, _obj_pos), pkey ); } else { - id = jsonObjectToSimpleString(jsonObjectGetIndex(ctx->params, 0)); +#ifdef PCRUD + if (!verifyObjectPCRUD( ctx, NULL )) { + *err = -1; + return jsonNULL; + } +#endif + id = jsonObjectToSimpleString(jsonObjectGetIndex(ctx->params, _obj_pos)); } osrfLogDebug( diff --git a/Open-ILS/src/c-apps/oils_idl-core.c b/Open-ILS/src/c-apps/oils_idl-core.c index 9e45203122..c756356431 100644 --- a/Open-ILS/src/c-apps/oils_idl-core.c +++ b/Open-ILS/src/c-apps/oils_idl-core.c @@ -15,6 +15,8 @@ #define PERSIST_NS "http://open-ils.org/spec/opensrf/IDL/persistence/v1" #define OBJECT_NS "http://open-ils.org/spec/opensrf/IDL/objects/v1" #define BASE_NS "http://opensrf.org/spec/IDL/base/v1" +#define REPORTER_NS "http://open-ils.org/spec/opensrf/IDL/reporter/v1" +#define PERM_NS "http://open-ils.org/spec/opensrf/IDL/permacrud/v1" static xmlDocPtr idlDoc = NULL; // parse and store the IDL here @@ -95,6 +97,7 @@ osrfHash* oilsIDLInit( const char* idl_filename ) { osrfHash* _tmp; osrfHash* links = osrfNewHash(); osrfHash* fields = osrfNewHash(); + osrfHash* pcrud = osrfNewHash(); osrfHashSet( usrData, fields, "fields" ); osrfHashSet( usrData, links, "links" ); @@ -270,6 +273,157 @@ osrfHash* oilsIDLInit( const char* idl_filename ) { _l = _l->next; } } +/**** Structure of permacrud in memory **** + +{ create : + { permission : [ x, y, z ], + global_required : "true", -- anything else, or missing, is false + local_context : [ f1, f2 ], + foreign_context : { class1 : { fkey : local_class_key, field : class1_field, context : [ a, b, c ] }, ...} + }, + retrieve : null, -- no perm check, or structure similar to the others + update : -- like create + ... + delete : -- like create + ... +} + +**** Structure of permacrud in memory ****/ + + if (!strcmp( (char*)_cur->name, "permacrud" )) { + osrfHashSet( usrData, pcrud, "permacrud" ); + xmlNodePtr _l = _cur->children; + + while(_l) { + if (strcmp( (char*)_l->name, "actions" )) { + _l = _l->next; + continue; + } + + xmlNodePtr _a = _l->children; + + while(_a) { + if ( + strcmp( (char*)_a->name, "create" ) && + strcmp( (char*)_a->name, "retreive" ) && + strcmp( (char*)_a->name, "update" ) && + strcmp( (char*)_a->name, "delete" ) + ) { + _a = _a->next; + continue; + } + + string_tmp = strdup( (char*)_a->name ); + osrfLogDebug(OSRF_LOG_MARK, "Found Permacrud action %s for class %s", string_tmp, osrfHashGet(usrData, "classname") ); + + _tmp = osrfNewHash(); + osrfHashSet( pcrud, _tmp, string_tmp ); + + osrfStringArray* map = osrfNewStringArray(0); + string_tmp = NULL; + if( (string_tmp = (char*)xmlGetProp(_l, BAD_CAST "permission") )) { + char* map_list = strdup( string_tmp ); + osrfLogDebug(OSRF_LOG_MARK, "Permacrud permission list is %s", string_tmp ); + + if (strlen( map_list ) > 0) { + char* st_tmp = NULL; + char* _map_class = strtok_r(map_list, "|", &st_tmp); + osrfStringArrayAdd(map, strdup(_map_class)); + + while ((_map_class = strtok_r(NULL, "|", &st_tmp))) { + osrfStringArrayAdd(map, strdup(_map_class)); + } + } + free(map_list); + osrfHashSet( _tmp, map, "permission"); + } + + osrfHashSet( _tmp, (char*)xmlGetProp(_l, BAD_CAST "global_required"), "global_required"); + + map = osrfNewStringArray(0); + string_tmp = NULL; + if( (string_tmp = (char*)xmlGetProp(_l, BAD_CAST "context_field") )) { + char* map_list = strdup( string_tmp ); + osrfLogDebug(OSRF_LOG_MARK, "Permacrud context_field list is %s", string_tmp ); + + if (strlen( map_list ) > 0) { + char* st_tmp = NULL; + char* _map_class = strtok_r(map_list, "|", &st_tmp); + osrfStringArrayAdd(map, strdup(_map_class)); + + while ((_map_class = strtok_r(NULL, "|", &st_tmp))) { + osrfStringArrayAdd(map, strdup(_map_class)); + } + } + free(map_list); + } + osrfHashSet( _tmp, map, "local_context"); + + xmlNodePtr _f = _l->children; + + while(_f) { + if ( strcmp( (char*)_f->name, "context" ) ) { + _f = _f->next; + continue; + } + + string_tmp = NULL; + if( (string_tmp = (char*)xmlGetProp(_f, BAD_CAST "link")) ) { + osrfLogDebug(OSRF_LOG_MARK, "Permacrud context link definition is %s", string_tmp ); + + osrfHash* _tmp_fcontext = osrfNewHash(); + osrfHash* _flink = oilsIDLFindPath("/%s/links/%s", osrfHashGet(usrData, "classname"), string_tmp); + + osrfHashSet( _tmp_fcontext, osrfNewHash(), osrfHashGet(_flink, "class") ); + _tmp_fcontext = osrfHashGet( _tmp_fcontext, osrfHashGet(_flink, "class") ); + osrfHashSet( _tmp_fcontext, osrfHashGet(_flink, "field"), "fkey" ); + osrfHashSet( _tmp_fcontext, osrfHashGet(_flink, "key"), "field" ); + + map = osrfNewStringArray(0); + string_tmp = NULL; + if( (string_tmp = (char*)xmlGetProp(_f, BAD_CAST "field") )) { + char* map_list = strdup( string_tmp ); + osrfLogDebug(OSRF_LOG_MARK, "Permacrud foreign context field list is %s", string_tmp ); + + if (strlen( map_list ) > 0) { + char* st_tmp = NULL; + char* _map_class = strtok_r(map_list, "|", &st_tmp); + osrfStringArrayAdd(map, strdup(_map_class)); + + while ((_map_class = strtok_r(NULL, "|", &st_tmp))) { + osrfStringArrayAdd(map, strdup(_map_class)); + } + } + free(map_list); + } + osrfHashSet( _tmp_fcontext, map, "context"); + + } else { + + if( (string_tmp = (char*)xmlGetProp(_f, BAD_CAST "field") )) { + char* map_list = strdup( string_tmp ); + osrfLogDebug(OSRF_LOG_MARK, "Permacrud foreign context field list is %s", string_tmp ); + + if (strlen( map_list ) > 0) { + char* st_tmp = NULL; + char* _map_class = strtok_r(map_list, "|", &st_tmp); + osrfStringArrayAdd(osrfHashGet( _tmp, "local_context"), strdup(_map_class)); + + while ((_map_class = strtok_r(NULL, "|", &st_tmp))) { + osrfStringArrayAdd(osrfHashGet( _tmp, "local_context"), strdup(_map_class)); + } + } + free(map_list); + } + + } + _f = _f->next; + } + _a = _a->next; + } + _l = _l->next; + } + } if (!strcmp( (char*)_cur->name, "source_definition" )) { string_tmp = NULL; diff --git a/Open-ILS/src/c-apps/oils_utils.c b/Open-ILS/src/c-apps/oils_utils.c index 3119214100..337ab653bd 100644 --- a/Open-ILS/src/c-apps/oils_utils.c +++ b/Open-ILS/src/c-apps/oils_utils.c @@ -74,12 +74,23 @@ long oilsFMGetObjectId( const jsonObject* obj ) { oilsEvent* oilsUtilsCheckPerms( int userid, int orgid, char* permissions[], int size ) { - if(!permissions) return NULL; + if (!permissions) return NULL; int i; oilsEvent* evt = NULL; - if(orgid == -1) orgid = 1; /* XXX */ - for( i = 0; i != size && permissions[i]; i++ ) { + if (orgid == -1) { + jsonObject* org = oilsUtilsQuickReq( + "open-ils.cstore", + "open-ils.cstore.direct.actor.org_unit.search", + jsonParseString("{\"parent_ou\":null}") + ); + + orgid = (int)jsonObjectGetNumber( oilsFMGetObject( org, "id" ) ); + + jsonObjectFree(org); + } + + for( i = 0; i < size && permissions[i]; i++ ) { char* perm = permissions[i]; jsonObject* params = jsonParseStringFmt("[%d, \"%s\", %d]", userid, perm, orgid); -- 2.11.0