[open-ils-commits] ***SPAM*** [GIT] Evergreen ILS branch master updated. 2986646c02712197449e9c15474088f57b138753

Evergreen Git git at git.evergreen-ils.org
Thu Jul 10 15:59:40 EDT 2014


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "Evergreen ILS".

The branch, master has been updated
       via  2986646c02712197449e9c15474088f57b138753 (commit)
       via  f9f4d186243f8cb8be0958e2e658771e3d821478 (commit)
      from  879b94c4998ca41585fd7dd72eb6decc325d8526 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 2986646c02712197449e9c15474088f57b138753
Author: Bill Erickson <berick at esilibrary.com>
Date:   Fri May 9 14:32:14 2014 -0400

    LP#1254918 limit ACQ batch update fund retrieval by perms
    
    In the ACQ batch update bar along the top of the PO page, limit the
    number of funds which require permission checks on the server by
    limiting the fund search to those at org units where the requesting user
    has the CREATE_PURCHSE_ORDER or MANAGE_FUND permissions.
    
    In other words, if a user only has create-po perms at Branch 1, we can
    specifically request funds at that branch (or below) for display so that
    the server (PCRUD) does not have to inspect unrelated funds for
    permissibility.  This speeds up fund retrieval.
    
    Signed-off-by: Bill Erickson <berick at esilibrary.com>
    Signed-off-by: Ben Shum <bshum at biblio.org>

diff --git a/Open-ILS/web/js/ui/default/acq/common/li_table.js b/Open-ILS/web/js/ui/default/acq/common/li_table.js
index 384607a..c98cec4 100644
--- a/Open-ILS/web/js/ui/default/acq/common/li_table.js
+++ b/Open-ILS/web/js/ui/default/acq/common/li_table.js
@@ -217,32 +217,53 @@ function AcqLiTable() {
             }
         );
 
+        function buildOneBatchWidget(field, args) {
+            (new openils.widget.AutoFieldWidget(args)).build(
+                function(w, aw) {
+                    if (field == "fund") {
+                        dojo.connect(
+                            w, "onChange", function(val) {
+                                self._updateFundSelectorStyle(aw, val);
+                            }
+                        );
+                        if (w.store)
+                            self._ensureCSSFundClasses(w.store);
+                    }
+
+                    dojo.style(w.domNode, {"width": "10em"});
+                    w.attr(
+                        "disabled",
+                        dojo.indexOf(disabled_fields, field) != -1
+                    );
+                    self.batchUpdateWidgets[field] = w;
+                }
+            );
+        }
+
         dojo.forEach(
             ["owning_lib","location","collection_code","circ_modifier","fund"],
             function(field) {
                 var args = self.afwCopyFieldArgs(field,"CREATE_PURCHASE_ORDER");
                 args.parentNode = dojo.byId("acq-bu-" + field);
 
-                (new openils.widget.AutoFieldWidget(args)).build(
-                    function(w, aw) {
-                        if (field == "fund") {
-                            dojo.connect(
-                                w, "onChange", function(val) {
-                                    self._updateFundSelectorStyle(aw, val);
-                                }
-                            );
-                            if (w.store)
-                                self._ensureCSSFundClasses(w.store);
-                        }
+                if (field == 'fund') {
+                    // The list of funds can be huge. Before fetching
+                    // funds for PO modification, see where the user has
+                    // perms and limit the retreived funds accordingly.
+                    // Note: this code only runs once per page load, so
+                    // no caching is required.
+                    new openils.User().getPermOrgList(
+                        ['CREATE_PURCHASE_ORDER', 'MANAGE_FUND'],
+                        function(orgs) { 
+                            args.searchFilter.org = orgs;
+                            buildOneBatchWidget(field, args);
+                        },
+                        true, true // descendants, id_list
+                    );
+                    return; 
+                }
 
-                        dojo.style(w.domNode, {"width": "10em"});
-                        w.attr(
-                            "disabled",
-                            dojo.indexOf(disabled_fields, field) != -1
-                        );
-                        self.batchUpdateWidgets[field] = w;
-                    }
-                );
+                buildOneBatchWidget(field, args);
             }
         );
 

commit f9f4d186243f8cb8be0958e2e658771e3d821478
Author: Mike Rylander <mrylander at gmail.com>
Date:   Fri May 2 17:00:43 2014 -0400

    LP#1254918: Allow skiping of user-object perms
    
    Previous to this commit, permissions in Evergreen check a cominbation
    of:
     * user-object permissions (does the user have a direct permission
       mapping to the object in question)
     * user-context permissions (does the user have the permission at the
       object's context location, whose field is defined in the IDL)
     * user-global permission (lacking a context location, does the user
       have the permission globally (at the top of the org tree) and therefore
       can apply the action to all objects of this typ)
    
    In practice, there are almost no user-object permissions.  When retrieving
    just on object from the database, the cost of this check is negligable to
    the point that we can completely ignore it.  However, when retrieving a
    large set of objects, such as the list of all funds in a large, consortial
    environment, the cost to check the user-object permission adds up to a
    noticable amount of time.
    
    To address this, we add a new construct to the IDL instructing the PCRUD
    infrastructure to skip user-object permission checking in those cases where
    the design and use of the system makes user-specific object permissions
    needless or superfluous.  This is embodied in a new XML attribute on the
    <pcrud> element: ignore_object_perms.  When set to "true", pcrud will skip
    all user-object permission checks, resulting in faster time-to-first-result.
    
    Additionally, we add a new "owning_user" attribute on the <action> element
    of the <pcrud> section. This new attribute specifies the field containing
    the actor.usr.id of the user that "owns" the object.  This allows PCRUD to
    test ownership of an object directly, and if the requesting user and owning
    user are the same, the action is allowed.
    
    Finaly, when "global_required" is "true" for the permission check, and there
    is no "owning_user" attribute defined for the class in the IDL, we skip the
    above-mentioned user-object permission check.  When "global_required" is
    "false" or there is an "owning_user" attribute, we check for user permissions.
    
    In all cases, the "ignore_object_perms" attribute is honored, and in its
    presence we skip non-owner user-object permissions.
    
    The net result is an immediate increase in speed for retrieval of objects
    in the presence of the "global_required" attribute, and a mechanism to
    increase the speed of specific cases of context-aware retrival by the use
    of "ignore_object_perms".
    
    We use this new mechanism to speed the retrieval of fund objects in the
    ACQ interfaces that draw available-fund dropdowns.
    
    Signed-off-by: Mike Rylander <mrylander at gmail.com>
    Signed-off-by: Bill Erickson <berick at esilibrary.com>
    Signed-off-by: Ben Shum <bshum at biblio.org>

diff --git a/Open-ILS/examples/fm_IDL.xml b/Open-ILS/examples/fm_IDL.xml
index f318da8..e574b29 100644
--- a/Open-ILS/examples/fm_IDL.xml
+++ b/Open-ILS/examples/fm_IDL.xml
@@ -7676,7 +7676,7 @@ SELECT  usr,
             <link field="combined_balance" reltype="might_have" key="fund" map="" class="acqfcb"/>
             <link field="spent_balance" reltype="might_have" key="fund" map="" class="acqfsb"/>
 		</links>
-        <permacrud xmlns="http://open-ils.org/spec/opensrf/IDL/permacrud/v1">
+        <permacrud xmlns="http://open-ils.org/spec/opensrf/IDL/permacrud/v1" ignore_object_perms="true">
             <actions>
                 <create permission="ADMIN_ACQ_FUND" context_field="org"/>
                 <retrieve permission="ADMIN_ACQ_FUND VIEW_FUND MANAGE_FUND" context_field="org"/>
diff --git a/Open-ILS/examples/permacrud.xsd b/Open-ILS/examples/permacrud.xsd
index 451ac4b..22750b7 100644
--- a/Open-ILS/examples/permacrud.xsd
+++ b/Open-ILS/examples/permacrud.xsd
@@ -47,6 +47,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
   </xs:sequence>
   <xs:attribute name="permission" use="required"/>
   <xs:attribute name="context_field"/>
+  <xs:attribute name="owning_user"/>
   <xs:attribute name="global_required"/>
  </xs:complexType>
 </xs:element>
@@ -58,6 +59,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
   </xs:sequence>
   <xs:attribute name="permission"/>
   <xs:attribute name="context_field"/>
+  <xs:attribute name="owning_user"/>
   <xs:attribute name="global_required"/>
  </xs:complexType>
 </xs:element>
@@ -69,6 +71,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
   </xs:sequence>
   <xs:attribute name="permission" use="required"/>
   <xs:attribute name="context_field"/>
+  <xs:attribute name="owning_user"/>
   <xs:attribute name="global_required"/>
  </xs:complexType>
 </xs:element>
@@ -80,6 +83,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
   </xs:sequence>
   <xs:attribute name="permission" use="required"/>
   <xs:attribute name="context_field"/>
+  <xs:attribute name="owning_user"/>
   <xs:attribute name="global_required"/>
  </xs:complexType>
 </xs:element>
@@ -100,6 +104,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
   <xs:sequence>
    <xs:element ref="permacrud:actions" minOccurs="1" maxOccurs="1"/>
   </xs:sequence>
+  <xs:attribute name="ignore_object_perms"/>
  </xs:complexType>
 </xs:element>
 
diff --git a/Open-ILS/src/c-apps/oils_idl-core.c b/Open-ILS/src/c-apps/oils_idl-core.c
index 5d432ab..707991e 100644
--- a/Open-ILS/src/c-apps/oils_idl-core.c
+++ b/Open-ILS/src/c-apps/oils_idl-core.c
@@ -282,6 +282,7 @@ osrfHash* oilsIDLInit( const char* idl_filename ) {
 { create :
     { permission : [ x, y, z ],
       global_required : "true", -- anything else, or missing, is false
+      ignore_object_perms : "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 ] }, ...}
     },
@@ -298,6 +299,7 @@ osrfHash* oilsIDLInit( const char* idl_filename ) {
 					osrfHash* pcrud = osrfNewHash();
 					osrfHashSet( class_def_hash, pcrud, "permacrud" );
 					xmlNodePtr _l = _cur->children;
+					char * ignore_object_perms = (char*) xmlGetProp(_cur, BAD_CAST "ignore_object_perms");
 
 					while(_l) {
 						if (strcmp( (char*)_l->name, "actions" )) {
@@ -325,6 +327,9 @@ osrfHash* oilsIDLInit( const char* idl_filename ) {
 							osrfHash* action_def_hash = osrfNewHash();
 							osrfHashSet( pcrud, action_def_hash, action_name );
 
+							// Set the class-wide ignore_object_perms flag
+					    	osrfHashSet( action_def_hash, ignore_object_perms, "ignore_object_perms");
+
 							// Tokenize permission attribute into an osrfStringArray
 							prop_str = (char*) xmlGetProp(_a, BAD_CAST "permission");
 							if( prop_str )
@@ -335,6 +340,9 @@ osrfHash* oilsIDLInit( const char* idl_filename ) {
 							xmlFree( prop_str );
 
 					    	osrfHashSet( action_def_hash,
+								(char*)xmlGetNoNsProp(_a, BAD_CAST "owning_user"), "owning_user");
+
+					    	osrfHashSet( action_def_hash,
 								(char*)xmlGetNoNsProp(_a, BAD_CAST "global_required"), "global_required");
 
 							// Tokenize context_field attribute into an osrfStringArray
diff --git a/Open-ILS/src/c-apps/oils_sql.c b/Open-ILS/src/c-apps/oils_sql.c
index dac5d8c..6d3d25c 100644
--- a/Open-ILS/src/c-apps/oils_sql.c
+++ b/Open-ILS/src/c-apps/oils_sql.c
@@ -1561,6 +1561,12 @@ static int verifyObjectPCRUD ( osrfMethodContext* ctx, osrfHash *class, const js
 	// for storing lists of integers, so we fake it with a list of strings.)
 	osrfStringArray* context_org_array = osrfNewStringArray( 1 );
 
+	const char* context_org = NULL;
+    const char* pkey = NULL;
+    jsonObject *param = NULL;
+	const char* perm = NULL;
+	int OK = 0;
+	int i = 0;
 	int err = 0;
 	const char* pkey_value = NULL;
 	if( str_is_true( osrfHashGet(pcrud, "global_required") ) ) {
@@ -1595,8 +1601,8 @@ static int verifyObjectPCRUD ( osrfMethodContext* ctx, osrfHash *class, const js
 
 	    osrfLogDebug( OSRF_LOG_MARK, "global-level permissions not required, "
 				"fetching context org ids" );
-	    const char* pkey = osrfHashGet( class, "primarykey" );
-		jsonObject *param = NULL;
+
+        pkey = osrfHashGet( class, "primarykey" );
 
 		if( !pkey ) {
 			// There is no primary key, so we can't do a fresh lookup.  Use the row
@@ -1627,6 +1633,8 @@ static int verifyObjectPCRUD ( osrfMethodContext* ctx, osrfHash *class, const js
 
 			param = jsonObjectExtractIndex( _list, 0 );
 			jsonObjectFree( _list );
+
+            fetch = 0;
 		}
 
 		if( !param ) {
@@ -1842,20 +1850,166 @@ static int verifyObjectPCRUD ( osrfMethodContext* ctx, osrfHash *class, const js
 				osrfHashIteratorFree( class_itr );
 			}
 		}
-
-		jsonObjectFree( param );
 	}
 
-	const char* context_org = NULL;
-	const char* perm = NULL;
-	int OK = 0;
+    // If there is an owning_user attached to the action, we allow that user and users with
+    // object perms on the object. CREATE can't use this. We only do this when there is no
+    // context org for this action, and when we're not ignoring object perms.
+    if (
+        *method_type != 'c' &&
+        !str_is_true( osrfHashGet(pcrud, "ignore_object_perms") ) && // Always honor
+        context_org_array->size == 0
+    ) {
+        char* owning_user_field = osrfHashGet( pcrud, "owning_user" );
+        if (owning_user_field) {
+
+            if (!param) { // We didn't get it during the context lookup
+			    pkey = osrfHashGet( class, "primarykey" );
+		
+				if( !pkey  ) {
+					// There is no primary key, so we can't do a fresh lookup.  Use the row
+					// image that we already have.  If it doesn't have everything we need, too bad.
+					fetch = 0;
+					param = jsonObjectClone( obj );
+					osrfLogDebug( OSRF_LOG_MARK, "No primary key; using clone of object" );
+				} else if( obj->classname ) {
+					pkey_value = oilsFMGetStringConst( obj, pkey );
+					if( !fetch )
+						param = jsonObjectClone( obj );
+					osrfLogDebug( OSRF_LOG_MARK, "Object supplied, using primary key value of %s",
+						pkey_value );
+				} else {
+					pkey_value = jsonObjectGetString( obj );
+					fetch = 1;
+					osrfLogDebug( OSRF_LOG_MARK, "Object not supplied, using primary key value "
+						"of %s and retrieving from the database", pkey_value );
+				}
+		
+				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 );
+				}
+            }
+	
+			if( !param ) {
+				// The row doesn't exist.  Complain, and deny access.
+				osrfLogDebug( OSRF_LOG_MARK,
+						"Object not found in the database with primary key %s of %s",
+						pkey, pkey_value );
+	
+				growing_buffer* msg = buffer_init( 128 );
+				buffer_fadd(
+					msg,
+					"%s: no object found with primary key %s of %s",
+					modulename,
+					pkey,
+					pkey_value
+				);
+	
+				char* m = buffer_release( msg );
+				osrfAppSessionStatus(
+					ctx->session,
+					OSRF_STATUS_INTERNALSERVERERROR,
+					"osrfMethodException",
+					ctx->request,
+					m
+				);
+	
+				free( m );
+				return 0;
+			} else {
+
+    	        int ownerid = atoi( oilsFMGetStringConst( param, owning_user_field ) );
+
+                // Allow the owner to do whatever
+                if (ownerid == userid)
+                    OK = 1;
+
+                i = 0;
+	            while( !OK && (perm = osrfStringArrayGetString(permission, i++)) ) {
+            		dbi_result result;
+
+					osrfLogDebug(
+						OSRF_LOG_MARK,
+						"Checking object permission [%s] for user %d "
+								"on object %s (class %s)",
+						perm,
+						userid,
+						pkey_value,
+						osrfHashGet( class, "classname" )
+					);
+	
+					result = dbi_conn_queryf(
+						writehandle,
+						"SELECT permission.usr_has_object_perm(%d, '%s', '%s', '%s') AS has_perm;",
+						userid,
+						perm,
+						osrfHashGet( class, "classname" ),
+						pkey_value
+					);
+	
+					if( result ) {
+						osrfLogDebug(
+							OSRF_LOG_MARK,
+							"Received a result for object permission [%s] "
+									"for user %d on object %s (class %s)",
+							perm,
+							userid,
+							pkey_value,
+							osrfHashGet( class, "classname" )
+						);
+	
+						if( dbi_result_first_row( result )) {
+							jsonObject* return_val = oilsMakeJSONFromResult( result );
+							const char* has_perm = jsonObjectGetString(
+									jsonObjectGetKeyConst( return_val, "has_perm" ));
+	
+							osrfLogDebug(
+								OSRF_LOG_MARK,
+								"Status of object permission [%s] for user %d "
+										"on object %s (class %s) is %s",
+								perm,
+								userid,
+								pkey_value,
+								osrfHashGet(class, "classname"),
+								has_perm
+							);
+	
+							if( *has_perm == 't' )
+								OK = 1;
+							jsonObjectFree( return_val );
+						}
+	
+						dbi_result_free( result );
+						if( OK )
+                            break;
+					} else {
+						const char* msg;
+						int errnum = dbi_conn_error( writehandle, &msg );
+						osrfLogWarning( OSRF_LOG_MARK,
+							"Unable to call check object permissions: %d, %s",
+							errnum, msg ? msg : "(No description available)" );
+						if( !oilsIsDBConnected( writehandle ))
+							osrfAppSessionPanic( ctx->session );
+					}
+				}
+            }
+        }
+    }
 
 	// For every combination of permission and context org unit: call a stored procedure
 	// to determine if the user has this permission in the context of this org unit.
 	// If the answer is yes at any point, then we're done, and the user has permission.
 	// In other words permissions are additive.
-	int i = 0;
-	while( (perm = osrfStringArrayGetString(permission, i++)) ) {
+	i = 0;
+	while( !OK && (perm = osrfStringArrayGetString(permission, i++)) ) {
 		dbi_result result;
 
         osrfStringArray* pcache = NULL;
@@ -1905,7 +2059,14 @@ static int verifyObjectPCRUD ( osrfMethodContext* ctx, osrfHash *class, const js
                 }
             }
 
-			if( pkey_value ) {
+			if(
+                pkey_value &&
+                !str_is_true( osrfHashGet(pcrud, "ignore_object_perms") ) && // Always honor
+                (
+                    !str_is_true( osrfHashGet(pcrud, "global_required") ) ||
+                    osrfHashGet(pcrud, "owning_user") 
+                )
+            ) {
 				osrfLogDebug(
 					OSRF_LOG_MARK,
 					"Checking object permission [%s] for user %d "
@@ -4231,7 +4392,7 @@ char* SELECT (
 
 					// Look up the field in the IDL
 					const char* col_name = jsonObjectGetString( selfield );
-					osrfHash* field_def;
+					osrfHash* field_def = NULL;
 
 					if (!osrfStringArrayContains(
 							osrfHashGet(
@@ -4319,7 +4480,7 @@ char* SELECT (
 							jsonObjectGetKeyConst( selfield, "column" ) );
 
 					// Get the field definition from the IDL
-					osrfHash* field_def;
+					osrfHash* field_def = NULL;
 					if (!osrfStringArrayContains(
 							osrfHashGet(
 								osrfHashGet( class_field_set, col_name ),
@@ -5046,7 +5207,7 @@ static char* buildOrderByFromArray( osrfMethodContext* ctx, const jsonObject* or
 		const char* field =
 			jsonObjectGetString( jsonObjectGetKeyConst( order_spec, "field" ));
 
-		jsonObject* compare_to = jsonObjectGetKeyConst( order_spec, "compare" );
+		jsonObject* compare_to = jsonObjectGetKey( order_spec, "compare" );
 
 		if( !field || !class_alias ) {
 			osrfLogError( OSRF_LOG_MARK,

-----------------------------------------------------------------------

Summary of changes:
 Open-ILS/examples/fm_IDL.xml                      |    2 +-
 Open-ILS/examples/permacrud.xsd                   |    5 +
 Open-ILS/src/c-apps/oils_idl-core.c               |    8 +
 Open-ILS/src/c-apps/oils_sql.c                    |  187 +++++++++++++++++++--
 Open-ILS/web/js/ui/default/acq/common/li_table.js |   61 +++++---
 5 files changed, 229 insertions(+), 34 deletions(-)


hooks/post-receive
-- 
Evergreen ILS


More information about the open-ils-commits mailing list