C port of the permacrud service. This touches a lot of code, so expect some
authormiker <miker@dcc99617-32d9-48b4-a31d-7c20da2025e4>
Sun, 14 Dec 2008 21:19:44 +0000 (21:19 +0000)
committermiker <miker@dcc99617-32d9-48b4-a31d-7c20da2025e4>
Sun, 14 Dec 2008 21:19:44 +0000 (21:19 +0000)
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 <permacrud> 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
Open-ILS/examples/fm_IDL.xml
Open-ILS/src/c-apps/Makefile.am
Open-ILS/src/c-apps/oils_cstore.c
Open-ILS/src/c-apps/oils_idl-core.c
Open-ILS/src/c-apps/oils_utils.c

index 65fbb97..4f8375a 100644 (file)
@@ -18,8 +18,8 @@
        <xsl:template name="output-tokens">
                <xsl:param name="list" />
                <xsl:variable name="newlist" select="normalize-space($list)" />
-               <xsl:variable name="first" select="substring-before($newlist, '|')" />
-               <xsl:variable name="remaining" select="substring-after($list, '|')" />
+               <xsl:variable name="first" select="substring-before($newlist, ' ')" />
+               <xsl:variable name="remaining" select="substring-after($list, ' ')" />
                <xsl:choose test="$first">
                        <xsl:when test="$first">
                                <xsl:value-of select="$first" /><xsl:text>
index 27d2ddf..65089ad 100644 (file)
@@ -135,7 +135,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 
 
        <!-- Actually in the DB -->
-       <class id="vibtf" controller="open-ils.cstore" oils_obj:fieldmapper="vandelay::import_bib_trash_fields" oils_persist:tablename="vandelay.import_bib_trash_fields" reporter:label="Import/Overlay Fields for Removal">
+       <class id="vibtf" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="vandelay::import_bib_trash_fields" oils_persist:tablename="vandelay.import_bib_trash_fields" reporter:label="Import/Overlay Fields for Removal">
                <fields oils_persist:primary="id" oils_persist:sequence="vandelay.import_bib_trash_fields_id_seq">
                        <field name="isnew" oils_obj:array_position="0" oils_persist:virtual="true" />
                        <field name="ischanged" oils_obj:array_position="1" oils_persist:virtual="true" />
@@ -150,14 +150,14 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
                <permacrud xmlns="http://open-ils.org/spec/opensrf/IDL/permacrud/v1">
                        <actions>
                                <create permission="CREATE_IMPORT_TRASH_FIELD" context_field="owner"/>
-                               <retrieve permission="CREATE_IMPORT_TRASH_FIELD|UPDATE_IMPORT_TRASH_FIELD|DELETE_IMPORT_TRASH_FIELD" context_field="owner"/>
+                               <retrieve permission="CREATE_IMPORT_TRASH_FIELD UPDATE_IMPORT_TRASH_FIELD DELETE_IMPORT_TRASH_FIELD" context_field="owner"/>
                                <update permission="UPDATE_IMPORT_TRASH_FIELD" context_field="owner"/>
                                <delete permission="DELETE_IMPORT_TRASH_FIELD" context_field="owner"/>
                        </actions>
                </permacrud>
        </class>
 
-       <class id="vii" controller="open-ils.cstore" oils_obj:fieldmapper="vandelay::import_item" oils_persist:tablename="vandelay.import_item" reporter:label="Import Item Attribute Definition">
+       <class id="vii" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="vandelay::import_item" oils_persist:tablename="vandelay.import_item" reporter:label="Import Item Attribute Definition">
                <fields oils_persist:primary="id" oils_persist:sequence="vandelay.import_item_id_seq">
                        <field name="isnew" oils_obj:array_position="0" oils_persist:virtual="true" />
                        <field name="ischanged" oils_obj:array_position="1" oils_persist:virtual="true" />
@@ -194,7 +194,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
                                <create permission="CREATE_IMPORT_ITEM">
                     <context link="definition" field="owner"/>
                                </create>
-                               <retrieve permission="CREATE_IMPORT_ITEM|UPDATE_IMPORT_ITEM|DELETE_IMPORT_ITEM">
+                               <retrieve permission="CREATE_IMPORT_ITEM UPDATE_IMPORT_ITEM DELETE_IMPORT_ITEM">
                     <context link="definition" field="owner"/>
                                </retrieve>
                                <update permission="UPDATE_IMPORT_ITEM">
@@ -207,7 +207,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
                </permacrud>
        </class>
 
-       <class id="viiad" controller="open-ils.cstore" oils_obj:fieldmapper="vandelay::import_item_attr_definition" oils_persist:tablename="vandelay.import_item_attr_definition" reporter:label="Import Item Attribute Definition">
+       <class id="viiad" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="vandelay::import_item_attr_definition" oils_persist:tablename="vandelay.import_item_attr_definition" reporter:label="Import Item Attribute Definition">
                <fields oils_persist:primary="id" oils_persist:sequence="vandelay.import_item_attr_definition_id_seq">
                        <field name="isnew" oils_obj:array_position="0" oils_persist:virtual="true" />
                        <field name="ischanged" oils_obj:array_position="1" oils_persist:virtual="true" />
@@ -243,14 +243,14 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
                <permacrud xmlns="http://open-ils.org/spec/opensrf/IDL/permacrud/v1">
                        <actions>
                                <create permission="CREATE_IMPORT_ITEM_ATTR_DEF" context_field="owner"/>
-                               <retrieve permission="CREATE_IMPORT_ITEM_ATTR_DEF|UPDATE_IMPORT_ITEM_ATTR_DEF|DELETE_IMPORT_ITEM_ATTR_DEF" context_field="owner"/>
+                               <retrieve permission="CREATE_IMPORT_ITEM_ATTR_DEF UPDATE_IMPORT_ITEM_ATTR_DEF DELETE_IMPORT_ITEM_ATTR_DEF" context_field="owner"/>
                                <update permission="UPDATE_IMPORT_ITEM_ATTR_DEF" context_field="owner"/>
                                <delete permission="DELETE_IMPORT_ITEM_ATTR_DEF" context_field="owner"/>
                        </actions>
                </permacrud>
        </class>
 
-       <class id="vbq" controller="open-ils.cstore" oils_obj:fieldmapper="vandelay::bib_queue" oils_persist:tablename="vandelay.bib_queue" reporter:label="Import/Overlay Bib Queue">
+       <class id="vbq" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="vandelay::bib_queue" oils_persist:tablename="vandelay.bib_queue" reporter:label="Import/Overlay Bib Queue">
                <fields oils_persist:primary="id" oils_persist:sequence="vandelay.queue_id_seq">
                        <field name="isnew" oils_obj:array_position="0" oils_persist:virtual="true" />
                        <field name="ischanged" oils_obj:array_position="1" oils_persist:virtual="true" />
@@ -267,14 +267,14 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
                <permacrud xmlns="http://open-ils.org/spec/opensrf/IDL/permacrud/v1">
                        <actions>
                                <create permission="CREATE_BIB_IMPORT_QUEUE" global_required="true"/>
-                               <retrieve permission="CREATE_BIB_IMPORT_QUEUE|UPDATE_BIB_IMPORT_QUEUE|DELETE_BIB_IMPORT_QUEUE" global_required="true"/>
+                               <retrieve permission="CREATE_BIB_IMPORT_QUEUE UPDATE_BIB_IMPORT_QUEUE DELETE_BIB_IMPORT_QUEUE" global_required="true"/>
                                <update permission="UPDATE_BIB_IMPORT_QUEUE" global_required="true"/>
                                <delete permission="DELETE_BIB_IMPORT_QUEUE" global_required="true"/>
                        </actions>
                </permacrud>
        </class>
 
-       <class id="vqbr" controller="open-ils.cstore" oils_obj:fieldmapper="vandelay::queued_bib_record" oils_persist:tablename="vandelay.queued_bib_record" reporter:label="Queued Bib Record">
+       <class id="vqbr" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="vandelay::queued_bib_record" oils_persist:tablename="vandelay.queued_bib_record" reporter:label="Queued Bib Record">
                <fields oils_persist:primary="id" oils_persist:sequence="vandelay.queued_record_id_seq">
                        <field name="isnew" oils_obj:array_position="0" oils_persist:virtual="true" />
                        <field name="ischanged" oils_obj:array_position="1" oils_persist:virtual="true" />
@@ -300,14 +300,14 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
                <permacrud xmlns="http://open-ils.org/spec/opensrf/IDL/permacrud/v1">
                        <actions>
                                <create permission="CREATE_BIB_IMPORT_QUEUE" global_required="true"/>
-                               <retrieve permission="CREATE_BIB_IMPORT_QUEUE|UPDATE_BIB_IMPORT_QUEUE|DELETE_BIB_IMPORT_QUEUE" global_required="true"/>
+                               <retrieve permission="CREATE_BIB_IMPORT_QUEUE UPDATE_BIB_IMPORT_QUEUE DELETE_BIB_IMPORT_QUEUE" global_required="true"/>
                                <update permission="UPDATE_BIB_IMPORT_QUEUE" global_required="true"/>
                                <delete permission="DELETE_BIB_IMPORT_QUEUE" global_required="true"/>
                        </actions>
                </permacrud>
        </class>
 
-       <class id="vqbrad" controller="open-ils.cstore" oils_obj:fieldmapper="vandelay::bib_attr_definition" oils_persist:tablename="vandelay.bib_attr_definition" reporter:label="Queued Bib Record Attribute Definition">
+       <class id="vqbrad" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="vandelay::bib_attr_definition" oils_persist:tablename="vandelay.bib_attr_definition" reporter:label="Queued Bib Record Attribute Definition">
                <fields oils_persist:primary="id" oils_persist:sequence="vandelay.bib_attr_definition_id_seq">
                        <field name="isnew" oils_obj:array_position="0" oils_persist:virtual="true" />
                        <field name="ischanged" oils_obj:array_position="1" oils_persist:virtual="true" />
@@ -325,7 +325,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
                                <create permission="CREATE_BIB_IMPORT_FIELD_DEF" global_required="true"/>
                 <retrieve/>
                 <!--
-                               <retrieve permission="CREATE_BIB_IMPORT_IMPORT_FIELD_DEF|UPDATE_BIB_IMPORT_IMPORT_FIELD_DEF|DELETE_BIB_IMPORT_IMPORT_FIELD_DEF" global_required="true"/>
+                               <retrieve permission="CREATE_BIB_IMPORT_IMPORT_FIELD_DEF UPDATE_BIB_IMPORT_IMPORT_FIELD_DEF DELETE_BIB_IMPORT_IMPORT_FIELD_DEF" global_required="true"/>
                 -->
                                <update permission="UPDATE_BIB_IMPORT_IMPORT_FIELD_DEF" global_required="true"/>
                                <delete permission="DELETE_BIB_IMPORT_IMPORT_FIELD_DEF" global_required="true"/>
@@ -333,7 +333,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
                </permacrud>
        </class>
 
-       <class id="vqbra" controller="open-ils.cstore" oils_obj:fieldmapper="vandelay::queued_bib_record_attr" oils_persist:tablename="vandelay.queued_bib_record_attr" reporter:label="Queued Bib Record Attribute">
+       <class id="vqbra" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="vandelay::queued_bib_record_attr" oils_persist:tablename="vandelay.queued_bib_record_attr" reporter:label="Queued Bib Record Attribute">
                <fields oils_persist:primary="id" oils_persist:sequence="vandelay.queued_bib_record_attr_id_seq">
                        <field name="isnew" oils_obj:array_position="0" oils_persist:virtual="true" />
                        <field name="ischanged" oils_obj:array_position="1" oils_persist:virtual="true" />
@@ -350,14 +350,14 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
                <permacrud xmlns="http://open-ils.org/spec/opensrf/IDL/permacrud/v1">
                        <actions>
                                <create permission="CREATE_BIB_IMPORT_QUEUE" global_required="true"/>
-                               <retrieve permission="CREATE_BIB_IMPORT_QUEUE|UPDATE_BIB_IMPORT_QUEUE|DELETE_BIB_IMPORT_QUEUE" global_required="true"/>
+                               <retrieve permission="CREATE_BIB_IMPORT_QUEUE UPDATE_BIB_IMPORT_QUEUE DELETE_BIB_IMPORT_QUEUE" global_required="true"/>
                                <update permission="UPDATE_BIB_IMPORT_QUEUE" global_required="true"/>
                                <delete permission="DELETE_BIB_IMPORT_QUEUE" global_required="true"/>
                        </actions>
                </permacrud>
        </class>
 
-       <class id="vbm" controller="open-ils.cstore" oils_obj:fieldmapper="vandelay::bib_match" oils_persist:tablename="vandelay.bib_match" reporter:label="Queued Bib Record Match">
+       <class id="vbm" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="vandelay::bib_match" oils_persist:tablename="vandelay.bib_match" reporter:label="Queued Bib Record Match">
                <fields oils_persist:primary="id" oils_persist:sequence="vandelay.bib_match_id_seq">
                        <field name="isnew" oils_obj:array_position="0" oils_persist:virtual="true" />
                        <field name="ischanged" oils_obj:array_position="1" oils_persist:virtual="true" />
@@ -376,14 +376,14 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
                <permacrud xmlns="http://open-ils.org/spec/opensrf/IDL/permacrud/v1">
                        <actions>
                                <create permission="CREATE_BIB_IMPORT_QUEUE" global_required="true"/>
-                               <retrieve permission="CREATE_BIB_IMPORT_QUEUE|UPDATE_BIB_IMPORT_QUEUE|DELETE_BIB_IMPORT_QUEUE" global_required="true"/>
+                               <retrieve permission="CREATE_BIB_IMPORT_QUEUE UPDATE_BIB_IMPORT_QUEUE DELETE_BIB_IMPORT_QUEUE" global_required="true"/>
                                <update permission="UPDATE_BIB_IMPORT_QUEUE" global_required="true"/>
                                <delete permission="DELETE_BIB_IMPORT_QUEUE" global_required="true"/>
                        </actions>
                </permacrud>
        </class>
 
-       <class id="vaq" controller="open-ils.cstore" oils_obj:fieldmapper="vandelay::authority_queue" oils_persist:tablename="vandelay.authority_queue" reporter:label="Import/Overlay Authority Queue">
+       <class id="vaq" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="vandelay::authority_queue" oils_persist:tablename="vandelay.authority_queue" reporter:label="Import/Overlay Authority Queue">
                <fields oils_persist:primary="id" oils_persist:sequence="vandelay.queue_id_seq">
                        <field name="isnew" oils_obj:array_position="0" oils_persist:virtual="true" />
                        <field name="ischanged" oils_obj:array_position="1" oils_persist:virtual="true" />
@@ -400,14 +400,14 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
                <permacrud xmlns="http://open-ils.org/spec/opensrf/IDL/permacrud/v1">
                        <actions>
                                <create permission="CREATE_AUTHORITY_IMPORT_QUEUE" global_required="true"/>
-                               <retrieve permission="CREATE_AUTHORITY_IMPORT_QUEUE|UPDATE_AUTHORITY_IMPORT_QUEUE|DELETE_AUTHORITY_IMPORT_QUEUE" global_required="true"/>
+                               <retrieve permission="CREATE_AUTHORITY_IMPORT_QUEUE UPDATE_AUTHORITY_IMPORT_QUEUE DELETE_AUTHORITY_IMPORT_QUEUE" global_required="true"/>
                                <update permission="UPDATE_AUTHORITY_IMPORT_QUEUE" global_required="true"/>
                                <delete permission="DELETE_AUTHORITY_IMPORT_QUEUE" global_required="true"/>
                        </actions>
                </permacrud>
        </class>
 
-       <class id="vqar" controller="open-ils.cstore" oils_obj:fieldmapper="vandelay::queued_authority_record" oils_persist:tablename="vandelay.queued_authority_record" reporter:label="Queued Authority Record">
+       <class id="vqar" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="vandelay::queued_authority_record" oils_persist:tablename="vandelay.queued_authority_record" reporter:label="Queued Authority Record">
                <fields oils_persist:primary="id" oils_persist:sequence="vandelay.queued_record_id_seq">
                        <field name="isnew" oils_obj:array_position="0" oils_persist:virtual="true" />
                        <field name="ischanged" oils_obj:array_position="1" oils_persist:virtual="true" />
@@ -431,14 +431,14 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
                <permacrud xmlns="http://open-ils.org/spec/opensrf/IDL/permacrud/v1">
                        <actions>
                                <create permission="CREATE_AUTHORITY_IMPORT_QUEUE" global_required="true"/>
-                               <retrieve permission="CREATE_AUTHORITY_IMPORT_QUEUE|UPDATE_AUTHORITY_IMPORT_QUEUE|DELETE_AUTHORITY_IMPORT_QUEUE" global_required="true"/>
+                               <retrieve permission="CREATE_AUTHORITY_IMPORT_QUEUE UPDATE_AUTHORITY_IMPORT_QUEUE DELETE_AUTHORITY_IMPORT_QUEUE" global_required="true"/>
                                <update permission="UPDATE_AUTHORITY_IMPORT_QUEUE" global_required="true"/>
                                <delete permission="DELETE_AUTHORITY_IMPORT_QUEUE" global_required="true"/>
                        </actions>
                </permacrud>
        </class>
 
-       <class id="vqarad" controller="open-ils.cstore" oils_obj:fieldmapper="vandelay::authority_attr_definition" oils_persist:tablename="vandelay.authority_attr_definition" reporter:label="Queued Authority Record Attribute Definition">
+       <class id="vqarad" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="vandelay::authority_attr_definition" oils_persist:tablename="vandelay.authority_attr_definition" reporter:label="Queued Authority Record Attribute Definition">
                <fields oils_persist:primary="id" oils_persist:sequence="vandelay.authority_attr_definition_id_seq">
                        <field name="isnew" oils_obj:array_position="0" oils_persist:virtual="true" />
                        <field name="ischanged" oils_obj:array_position="1" oils_persist:virtual="true" />
@@ -456,7 +456,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
                                <create permission="CREATE_AUTHORITY_IMPORT_IMPORT_FIELD_DEF" global_required="true"/>
                 <retrieve/>
                 <!--
-                               <retrieve permission="CREATE_AUTHORITY_IMPORT_IMPORT_FIELD_DEF|UPDATE_AUTHORITY_IMPORT_IMPORT_FIELD_DEF|DELETE_AUTHORITY_IMPORT_IMPORT_FIELD_DEF" global_required="true"/>
+                               <retrieve permission="CREATE_AUTHORITY_IMPORT_IMPORT_FIELD_DEF UPDATE_AUTHORITY_IMPORT_IMPORT_FIELD_DEF DELETE_AUTHORITY_IMPORT_IMPORT_FIELD_DEF" global_required="true"/>
                 -->
                                <update permission="UPDATE_AUTHORITY_IMPORT_IMPORT_FIELD_DEF" global_required="true"/>
                                <delete permission="DELETE_AUTHORITY_IMPORT_IMPORT_FIELD_DEF" global_required="true"/>
@@ -464,7 +464,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
                </permacrud>
        </class>
 
-       <class id="vqara" controller="open-ils.cstore" oils_obj:fieldmapper="vandelay::queued_authority_record_attr" oils_persist:tablename="vandelay.queued_authority_record_attr" reporter:label="Queued Authority Record Attribute">
+       <class id="vqara" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="vandelay::queued_authority_record_attr" oils_persist:tablename="vandelay.queued_authority_record_attr" reporter:label="Queued Authority Record Attribute">
                <fields oils_persist:primary="id" oils_persist:sequence="vandelay.queued_authority_record_attr_id_seq">
                        <field name="isnew" oils_obj:array_position="0" oils_persist:virtual="true" />
                        <field name="ischanged" oils_obj:array_position="1" oils_persist:virtual="true" />
@@ -481,14 +481,14 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
                <permacrud xmlns="http://open-ils.org/spec/opensrf/IDL/permacrud/v1">
                        <actions>
                                <create permission="CREATE_AUTHORITY_IMPORT_QUEUE" global_required="true"/>
-                               <retrieve permission="CREATE_AUTHORITY_IMPORT_QUEUE|UPDATE_AUTHORITY_IMPORT_QUEUE|DELETE_AUTHORITY_IMPORT_QUEUE" global_required="true"/>
+                               <retrieve permission="CREATE_AUTHORITY_IMPORT_QUEUE UPDATE_AUTHORITY_IMPORT_QUEUE DELETE_AUTHORITY_IMPORT_QUEUE" global_required="true"/>
                                <update permission="UPDATE_AUTHORITY_IMPORT_QUEUE" global_required="true"/>
                                <delete permission="DELETE_AUTHORITY_IMPORT_QUEUE" global_required="true"/>
                        </actions>
                </permacrud>
        </class>
 
-       <class id="vam" controller="open-ils.cstore" oils_obj:fieldmapper="vandelay::authority_match" oils_persist:tablename="vandelay.authority_match" reporter:label="Queued Authority Record Match">
+       <class id="vam" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="vandelay::authority_match" oils_persist:tablename="vandelay.authority_match" reporter:label="Queued Authority Record Match">
                <fields oils_persist:primary="id" oils_persist:sequence="vandelay.authority_match_id_seq">
                        <field name="isnew" oils_obj:array_position="0" oils_persist:virtual="true" />
                        <field name="ischanged" oils_obj:array_position="1" oils_persist:virtual="true" />
@@ -506,7 +506,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
                <permacrud xmlns="http://open-ils.org/spec/opensrf/IDL/permacrud/v1">
                        <actions>
                                <create permission="CREATE_AUTHORITY_IMPORT_QUEUE" global_required="true"/>
-                               <retrieve permission="CREATE_AUTHORITY_IMPORT_QUEUE|UPDATE_AUTHORITY_IMPORT_QUEUE|DELETE_AUTHORITY_IMPORT_QUEUE" global_required="true"/>
+                               <retrieve permission="CREATE_AUTHORITY_IMPORT_QUEUE UPDATE_AUTHORITY_IMPORT_QUEUE DELETE_AUTHORITY_IMPORT_QUEUE" global_required="true"/>
                                <update permission="UPDATE_AUTHORITY_IMPORT_QUEUE" global_required="true"/>
                                <delete permission="DELETE_AUTHORITY_IMPORT_QUEUE" global_required="true"/>
                        </actions>
@@ -534,7 +534,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
                </links>
        </class>
 
-    <class id="czs" controller="open-ils.cstore" oils_obj:fieldmapper="config::z3950_source" oils_persist:tablename="config.z3950_source" reporter:label="Z39.50 Source">
+    <class id="czs" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="config::z3950_source" oils_persist:tablename="config.z3950_source" reporter:label="Z39.50 Source">
         <fields oils_persist:primary="name">
             <field name="isnew" oils_obj:array_position="0" oils_persist:virtual="true" />
             <field name="ischanged" oils_obj:array_position="1" oils_persist:virtual="true" />
@@ -594,7 +594,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
                </links>
        </class>
 
-       <class id="ccm" controller="open-ils.cstore" oils_obj:fieldmapper="config::circ_modifier" oils_persist:tablename="config.circ_modifier" reporter:label="Circulation Modifier">
+       <class id="ccm" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="config::circ_modifier" oils_persist:tablename="config.circ_modifier" reporter:label="Circulation Modifier">
                <fields oils_persist:primary="code">
                        <field name="isnew" oils_obj:array_position="0" oils_persist:virtual="true" />
                        <field name="ischanged" oils_obj:array_position="1" oils_persist:virtual="true" />
@@ -616,7 +616,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
         </permacrud>
        </class>
 
-       <class id="ccpbt" controller="open-ils.cstore" oils_obj:fieldmapper="container::copy_bucket_type" oils_persist:tablename="container.copy_bucket_type" reporter:label="Copy Bucket Type" oils_persist:field_safe="true">
+       <class id="ccpbt" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="container::copy_bucket_type" oils_persist:tablename="container.copy_bucket_type" reporter:label="Copy Bucket Type" oils_persist:field_safe="true">
                <fields oils_persist:primary="code">
                        <field name="isnew" oils_obj:array_position="0" oils_persist:virtual="true" />
                        <field name="ischanged" oils_obj:array_position="1" oils_persist:virtual="true" />
@@ -628,14 +628,14 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
         <permacrud xmlns="http://open-ils.org/spec/opensrf/IDL/permacrud/v1">
             <actions>
                 <create permission="CREATE_COPY_BTYPE" global_required="true"/>
-                <retrieve permission="CREATE_COPY_BTYPE|UPDATE_COPY_BTYPE|DELETE_COPY_BTYPE" global_required="true"/>
+                <retrieve permission="CREATE_COPY_BTYPE UPDATE_COPY_BTYPE DELETE_COPY_BTYPE" global_required="true"/>
                 <update permission="UPDATE_COPY_BTYPE" global_required="true"/>
                 <delete permission="DELETE_COPY_BTYPE" global_required="true"/>
             </actions>
         </permacrud>
        </class>
 
-       <class id="ccnbt" controller="open-ils.cstore" oils_obj:fieldmapper="container::call_number_bucket_type" oils_persist:tablename="container.call_number_bucket_type" reporter:label="Call Number Bucket Type" oils_persist:field_safe="true">
+       <class id="ccnbt" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="container::call_number_bucket_type" oils_persist:tablename="container.call_number_bucket_type" reporter:label="Call Number Bucket Type" oils_persist:field_safe="true">
                <fields oils_persist:primary="code">
                        <field name="isnew" oils_obj:array_position="0" oils_persist:virtual="true" />
                        <field name="ischanged" oils_obj:array_position="1" oils_persist:virtual="true" />
@@ -647,14 +647,14 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
         <permacrud xmlns="http://open-ils.org/spec/opensrf/IDL/permacrud/v1">
             <actions>
                 <create permission="CREATE_CN_BTYPE" global_required="true"/>
-                <retrieve permission="CREATE_CN_BTYPE|UPDATE_CN_BTYPE|DELETE_CN_BTYPE" global_required="true"/>
+                <retrieve permission="CREATE_CN_BTYPE UPDATE_CN_BTYPE DELETE_CN_BTYPE" global_required="true"/>
                 <update permission="UPDATE_CN_BTYPE" global_required="true"/>
                 <delete permission="DELETE_CN_BTYPE" global_required="true"/>
             </actions>
         </permacrud>
        </class>
 
-       <class id="cbrebt" controller="open-ils.cstore" oils_obj:fieldmapper="container::biblio_record_entry_bucket_type" oils_persist:tablename="container.biblio_record_entry_bucket_type" reporter:label="Bibliographic Record Bucket Type" oils_persist:field_safe="true">
+       <class id="cbrebt" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="container::biblio_record_entry_bucket_type" oils_persist:tablename="container.biblio_record_entry_bucket_type" reporter:label="Bibliographic Record Bucket Type" oils_persist:field_safe="true">
                <fields oils_persist:primary="code">
                        <field name="isnew" oils_obj:array_position="0" oils_persist:virtual="true" />
                        <field name="ischanged" oils_obj:array_position="1" oils_persist:virtual="true" />
@@ -666,14 +666,14 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
         <permacrud xmlns="http://open-ils.org/spec/opensrf/IDL/permacrud/v1">
             <actions>
                 <create permission="CREATE_BIB_BTYPE" global_required="true"/>
-                <retrieve permission="CREATE_BIB_BTYPE|UPDATE_BIB_BTYPE|DELETE_BIB_BTYPE" global_required="true"/>
+                <retrieve permission="CREATE_BIB_BTYPE UPDATE_BIB_BTYPE DELETE_BIB_BTYPE" global_required="true"/>
                 <update permission="UPDATE_BIB_BTYPE" global_required="true"/>
                 <delete permission="DELETE_BIB_BTYPE" global_required="true"/>
             </actions>
         </permacrud>
        </class>
 
-       <class id="cubt" controller="open-ils.cstore" oils_obj:fieldmapper="container::user_bucket_type" oils_persist:tablename="container.user_bucket_type" reporter:label="User Bucket Type" oils_persist:field_safe="true">
+       <class id="cubt" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="container::user_bucket_type" oils_persist:tablename="container.user_bucket_type" reporter:label="User Bucket Type" oils_persist:field_safe="true">
                <fields oils_persist:primary="code">
                        <field name="isnew" oils_obj:array_position="0" oils_persist:virtual="true" />
                        <field name="ischanged" oils_obj:array_position="1" oils_persist:virtual="true" />
@@ -685,14 +685,14 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
         <permacrud xmlns="http://open-ils.org/spec/opensrf/IDL/permacrud/v1">
             <actions>
                 <create permission="CREATE_USER_BTYPE" global_required="true"/>
-                <retrieve permission="CREATE_USER_BTYPE|UPDATE_USER_BTYPE|DELETE_USER_BTYPE" global_required="true"/>
+                <retrieve permission="CREATE_USER_BTYPE UPDATE_USER_BTYPE DELETE_USER_BTYPE" global_required="true"/>
                 <update permission="UPDATE_USER_BTYPE" global_required="true"/>
                 <delete permission="DELETE_USER_BTYPE" global_required="true"/>
             </actions>
         </permacrud>
        </class>
 
-       <class id="cvrfm" controller="open-ils.cstore" oils_obj:fieldmapper="config::videorecording_format_map" oils_persist:tablename="config.videorecording_format_map" reporter:label="Videorecording Format" oils_persist:field_safe="true">
+       <class id="cvrfm" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="config::videorecording_format_map" oils_persist:tablename="config.videorecording_format_map" reporter:label="Videorecording Format" oils_persist:field_safe="true">
                <fields oils_persist:primary="code">
                        <field name="isnew" oils_obj:array_position="0" oils_persist:virtual="true" />
                        <field name="ischanged" oils_obj:array_position="1" oils_persist:virtual="true" />
@@ -704,7 +704,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
         <permacrud xmlns="http://open-ils.org/spec/opensrf/IDL/permacrud/v1">
             <actions>
                 <create permission="CREATE_MARC_CODE" global_required="true"/>
-                <retrieve permission="CREATE_MARC_CODE|UPDATE_MARC_CODE|DELETE_MARC_CODE" global_required="true"/>
+                <retrieve permission="CREATE_MARC_CODE UPDATE_MARC_CODE DELETE_MARC_CODE" global_required="true"/>
                 <update permission="UPDATE_MARC_CODE" global_required="true"/>
                 <delete permission="DELETE_MARC_CODE" global_required="true"/>
             </actions>
@@ -939,7 +939,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
                        <link field="org_unit" reltype="has_a" key="id" map="" class="aou"/>
                </links>
        </class>
-       <class id="atc" controller="open-ils.cstore" oils_obj:fieldmapper="action::transit_copy" oils_persist:tablename="action.transit_copy" reporter:core="true" reporter:label="Copy Transit">
+       <class id="atc" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="action::transit_copy" oils_persist:tablename="action.transit_copy" reporter:core="true" reporter:label="Copy Transit">
                <fields oils_persist:primary="id" oils_persist:sequence="action.transit_copy_id_seq">
                        <field name="isnew" oils_obj:array_position="0" oils_persist:virtual="true" />
                        <field name="ischanged" oils_obj:array_position="1" oils_persist:virtual="true" />
@@ -968,8 +968,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
                     <context link="target_copy" field="circ_lib"/>
                 </create>
                 <retrieve/>
-                <update permission="UPDATE_TRANSIT" context_field="dest|source"/>
-                <delete permission="DELETE_TRANSIT" context_field="dest|source"/>
+                <update permission="UPDATE_TRANSIT" context_field="dest source"/>
+                <delete permission="DELETE_TRANSIT" context_field="dest source"/>
             </actions>
         </permacrud>
        </class>
@@ -1050,7 +1050,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
                        <link field="record" reltype="has_a" key="id" map="" class="are"/>
                </links>
        </class>
-       <class id="clm" controller="open-ils.cstore" oils_obj:fieldmapper="config::language_map" oils_persist:tablename="config.language_map" reporter:label="Language Map" oils_persist:field_safe="true">
+       <class id="clm" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="config::language_map" oils_persist:tablename="config.language_map" reporter:label="Language Map" oils_persist:field_safe="true">
                <fields oils_persist:primary="code" oils_persist:sequence="">
                        <field name="isnew" oils_obj:array_position="0" oils_persist:virtual="true" />
                        <field name="ischanged" oils_obj:array_position="1" oils_persist:virtual="true" />
@@ -1062,7 +1062,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
         <permacrud xmlns="http://open-ils.org/spec/opensrf/IDL/permacrud/v1">
             <actions>
                 <create permission="CREATE_MARC_CODE" global_required="true"/>
-                <retrieve permission="CREATE_MARC_CODE|UPDATE_MARC_CODE|DELETE_MARC_CODE" global_required="true"/>
+                <retrieve permission="CREATE_MARC_CODE UPDATE_MARC_CODE DELETE_MARC_CODE" global_required="true"/>
                 <update permission="UPDATE_MARC_CODE" global_required="true"/>
                 <delete permission="DELETE_MARC_CODE" global_required="true"/>
             </actions>
@@ -1096,7 +1096,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
                        <link field="xact" reltype="has_a" key="id" map="" class="mbt"/>
                </links>
        </class>
-       <class id="cxt" controller="open-ils.cstore" oils_obj:fieldmapper="config::xml_transform" oils_persist:tablename="config.xml_transform" reporter:label="XML/XSLT Transform Definition">
+       <class id="cxt" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="config::xml_transform" oils_persist:tablename="config.xml_transform" reporter:label="XML/XSLT Transform Definition">
                <fields oils_persist:primary="name">
                        <field name="isnew" oils_obj:array_position="0" oils_persist:virtual="true" />
                        <field name="ischanged" oils_obj:array_position="1" oils_persist:virtual="true" />
@@ -1117,7 +1117,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
             </actions>
         </permacrud>
        </class>
-       <class id="cmf" controller="open-ils.cstore" oils_obj:fieldmapper="config::metabib_field" oils_persist:tablename="config.metabib_field">
+       <class id="cmf" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="config::metabib_field" oils_persist:tablename="config.metabib_field">
                <fields oils_persist:primary="id" oils_persist:sequence="config.metabib_field_id_seq">
                        <field name="isnew" oils_obj:array_position="0" oils_persist:virtual="true" />
                        <field name="ischanged" oils_obj:array_position="1" oils_persist:virtual="true" />
@@ -1141,7 +1141,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
             </actions>
         </permacrud>
        </class>
-       <class id="cam" controller="open-ils.cstore" oils_obj:fieldmapper="config::audience_map" oils_persist:tablename="config.audience_map" reporter:label="Audience Map" oils_persist:field_safe="true">
+       <class id="cam" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="config::audience_map" oils_persist:tablename="config.audience_map" reporter:label="Audience Map" oils_persist:field_safe="true">
                <fields oils_persist:primary="code" oils_persist:sequence="">
                        <field name="isnew" oils_obj:array_position="0" oils_persist:virtual="true" />
                        <field name="ischanged" oils_obj:array_position="1" oils_persist:virtual="true" />
@@ -1154,13 +1154,13 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
         <permacrud xmlns="http://open-ils.org/spec/opensrf/IDL/permacrud/v1">
             <actions>
                 <create permission="CREATE_MARC_CODE" global_required="true"/>
-                <retrieve permission="CREATE_MARC_CODE|UPDATE_MARC_CODE|DELETE_MARC_CODE" global_required="true"/>
+                <retrieve permission="CREATE_MARC_CODE UPDATE_MARC_CODE DELETE_MARC_CODE" global_required="true"/>
                 <update permission="UPDATE_MARC_CODE" global_required="true"/>
                 <delete permission="DELETE_MARC_CODE" global_required="true"/>
             </actions>
         </permacrud>
        </class>
-       <class id="cifm" controller="open-ils.cstore" oils_obj:fieldmapper="config::item_form_map" oils_persist:tablename="config.item_form_map" reporter:label="Item Form Map" oils_persist:field_safe="true">
+       <class id="cifm" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="config::item_form_map" oils_persist:tablename="config.item_form_map" reporter:label="Item Form Map" oils_persist:field_safe="true">
                <fields oils_persist:primary="code" oils_persist:sequence="">
                        <field name="isnew" oils_obj:array_position="0" oils_persist:virtual="true" />
                        <field name="ischanged" oils_obj:array_position="1" oils_persist:virtual="true" />
@@ -1172,13 +1172,13 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
         <permacrud xmlns="http://open-ils.org/spec/opensrf/IDL/permacrud/v1">
             <actions>
                 <create permission="CREATE_MARC_CODE" global_required="true"/>
-                <retrieve permission="CREATE_MARC_CODE|UPDATE_MARC_CODE|DELETE_MARC_CODE" global_required="true"/>
+                <retrieve permission="CREATE_MARC_CODE UPDATE_MARC_CODE DELETE_MARC_CODE" global_required="true"/>
                 <update permission="UPDATE_MARC_CODE" global_required="true"/>
                 <delete permission="DELETE_MARC_CODE" global_required="true"/>
             </actions>
         </permacrud>
        </class>
-       <class id="acn" controller="open-ils.cstore" oils_obj:fieldmapper="asset::call_number" oils_persist:tablename="asset.call_number" reporter:label="Call Number/Volume">
+       <class id="acn" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="asset::call_number" oils_persist:tablename="asset.call_number" reporter:label="Call Number/Volume">
                <fields oils_persist:primary="id" oils_persist:sequence="asset.call_number_id_seq">
                        <field name="isnew" oils_obj:array_position="0" oils_persist:virtual="true" />
                        <field name="ischanged" oils_obj:array_position="1" oils_persist:virtual="true" />
@@ -1234,7 +1234,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
                </fields>
                <links/>
        </class>
-       <class id="mct" controller="open-ils.cstore" oils_obj:fieldmapper="money::collections_tracker" oils_persist:tablename="money.collections_tracker">
+       <class id="mct" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="money::collections_tracker" oils_persist:tablename="money.collections_tracker">
                <fields oils_persist:primary="id" oils_persist:sequence="money.collections_tracker_id_seq">
                        <field name="isnew" oils_obj:array_position="0" oils_persist:virtual="true" />
                        <field name="ischanged" oils_obj:array_position="1" oils_persist:virtual="true" />
@@ -1258,7 +1258,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
             </actions>
         </permacrud>
        </class>
-       <class id="bre" controller="open-ils.cstore" oils_obj:fieldmapper="biblio::record_entry" oils_persist:tablename="biblio.record_entry" reporter:core="true" reporter:label="Bibliographic Record">
+       <class id="bre" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="biblio::record_entry" oils_persist:tablename="biblio.record_entry" reporter:core="true" reporter:label="Bibliographic Record">
                <fields oils_persist:primary="id" oils_persist:sequence="biblio.record_entry_id_seq">
                        <field name="isnew" oils_obj:array_position="0" oils_persist:virtual="true" />
                        <field name="ischanged" oils_obj:array_position="1" oils_persist:virtual="true" />
@@ -1308,13 +1308,13 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
                </links>
         <permacrud xmlns="http://open-ils.org/spec/opensrf/IDL/permacrud/v1">
             <actions>
-                <create permission="CREATE_MARC|IMPORT_MARC" global_required="true"/>
+                <create permission="CREATE_MARC IMPORT_MARC" global_required="true"/>
                 <retrieve/>
                 <update permission="UPDATE_MARC" global_required="true"/>
             </actions>
         </permacrud>
        </class>
-       <class id="aouhoo" controller="open-ils.cstore" oils_obj:fieldmapper="actor::org_unit::hours_of_operation" oils_persist:tablename="actor.hours_of_operation">
+       <class id="aouhoo" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="actor::org_unit::hours_of_operation" oils_persist:tablename="actor.hours_of_operation">
                <fields oils_persist:primary="id" oils_persist:sequence="">
                        <field name="isnew" oils_obj:array_position="0" oils_persist:virtual="true" />
                        <field name="ischanged" oils_obj:array_position="1" oils_persist:virtual="true" />
@@ -1348,7 +1348,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
             </actions>
         </permacrud>
        </class>
-       <class id="aoucd" controller="open-ils.cstore" oils_obj:fieldmapper="actor::org_unit::closed_date" oils_persist:tablename="actor.org_unit_closed">
+       <class id="aoucd" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="actor::org_unit::closed_date" oils_persist:tablename="actor.org_unit_closed">
                <fields oils_persist:primary="id" oils_persist:sequence="actor.org_unit_closed_id_seq">
                        <field name="isnew" oils_obj:array_position="0" oils_persist:virtual="true" />
                        <field name="ischanged" oils_obj:array_position="1" oils_persist:virtual="true" />
@@ -1371,7 +1371,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
             </actions>
         </permacrud>
        </class>
-       <class id="crcd" controller="open-ils.cstore" oils_obj:fieldmapper="config::rules::circ_duration" oils_persist:tablename="config.rule_circ_duration">
+       <class id="crcd" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="config::rules::circ_duration" oils_persist:tablename="config.rule_circ_duration">
                <fields oils_persist:primary="id" oils_persist:sequence="config.rule_circ_duration_id_seq">
                        <field name="isnew" oils_obj:array_position="0" oils_persist:virtual="true" />
                        <field name="ischanged" oils_obj:array_position="1" oils_persist:virtual="true" />
@@ -1530,7 +1530,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
                        <link field="org_unit" reltype="has_a" key="id" map="" class="aou"/>
                </links>
        </class>
-       <class id="acpn" controller="open-ils.cstore" oils_obj:fieldmapper="asset::copy_note" oils_persist:tablename="asset.copy_note" reporter:label="Copy Note">
+       <class id="acpn" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="asset::copy_note" oils_persist:tablename="asset.copy_note" reporter:label="Copy Note">
                <fields oils_persist:primary="id" oils_persist:sequence="asset.copy_note_id_seq">
                        <field name="isnew" oils_obj:array_position="0" oils_persist:virtual="true" />
                        <field name="ischanged" oils_obj:array_position="1" oils_persist:virtual="true" />
@@ -1597,7 +1597,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
                        <link field="source_records" reltype="has_many" key="metarecord" map="source" class="mmrsm"/>
                </links>
        </class>
-       <class id="cnal" controller="open-ils.cstore" oils_obj:fieldmapper="config::net_access_level" oils_persist:tablename="config.net_access_level">
+       <class id="cnal" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="config::net_access_level" oils_persist:tablename="config.net_access_level">
                <fields oils_persist:primary="id" oils_persist:sequence="config.net_access_level_id_seq">
                        <field name="isnew" oils_obj:array_position="0" oils_persist:virtual="true" />
                        <field name="ischanged" oils_obj:array_position="1" oils_persist:virtual="true" />
@@ -1615,7 +1615,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
             </actions>
         </permacrud>
        </class>
-       <class id="ppl" controller="open-ils.cstore" oils_obj:fieldmapper="permission::perm_list" oils_persist:tablename="permission.perm_list">
+       <class id="ppl" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="permission::perm_list" oils_persist:tablename="permission.perm_list">
                <fields oils_persist:primary="id" oils_persist:sequence="permission.perm_list_id_seq">
                        <field name="isnew" oils_obj:array_position="0" oils_persist:virtual="true" />
                        <field name="ischanged" oils_obj:array_position="1" oils_persist:virtual="true" />
@@ -1628,7 +1628,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
         <permacrud xmlns="http://open-ils.org/spec/opensrf/IDL/permacrud/v1">
             <actions>
                 <create permission="CREATE_PERM" global_required="true"/>
-                <retrieve permission="CREATE_PERM|UPDATE_PERM|DELETE_PERM" global_required="true"/>
+                <retrieve permission="CREATE_PERM UPDATE_PERM DELETE_PERM" global_required="true"/>
                 <update permission="UPDATE_PERM" global_required="true"/>
                 <delete permission="DELETE_PERM" global_required="true"/>
             </actions>
@@ -1741,7 +1741,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
                </links>
        </class>
 
-       <class id="csp" controller="open-ils.cstore" oils_obj:fieldmapper="config::standing_penalty" oils_persist:tablename="config.standing_penalty">
+       <class id="csp" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="config::standing_penalty" oils_persist:tablename="config.standing_penalty">
                <fields oils_persist:primary="id" oils_persist:sequence="config.standing_penalty_id_seq">
                        <field name="isnew" oils_obj:array_position="0" oils_persist:virtual="true" />
                        <field name="ischanged" oils_obj:array_position="1" oils_persist:virtual="true" />
@@ -1755,13 +1755,13 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
         <permacrud xmlns="http://open-ils.org/spec/opensrf/IDL/permacrud/v1">
             <actions>
                 <create permission="CREATE_STANDING_PENALTY" global_required="true"/>
-                <retrieve permission="CREATE_STANDING_PENALTY|UPDATE_STANDING_PENALTY|DELETE_STANDING_PENALTY" global_required="true"/>
+                <retrieve permission="CREATE_STANDING_PENALTY UPDATE_STANDING_PENALTY DELETE_STANDING_PENALTY" global_required="true"/>
                 <update permission="UPDATE_STANDING_PENALTY" global_required="true"/>
                 <delete permission="DELETE_STANDING_PENALTY" global_required="true"/>
             </actions>
         </permacrud>
        </class>
-       <class id="pgpt" controller="open-ils.cstore" oils_obj:fieldmapper="permission::grp_penalty_threshold" oils_persist:tablename="permission.grp_penalty_threshold">
+       <class id="pgpt" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="permission::grp_penalty_threshold" oils_persist:tablename="permission.grp_penalty_threshold">
                <fields oils_persist:primary="id" oils_persist:sequence="permission.grp_penalty_threshold_id_seq">
                        <field name="isnew" oils_obj:array_position="0" oils_persist:virtual="true" />
                        <field name="ischanged" oils_obj:array_position="1" oils_persist:virtual="true" />
@@ -1781,14 +1781,14 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
             <actions>
                 <create permission="CREATE_GROUP_PENALTY_THRESHOLD" context_field='org_unit'/>
                 <retrieve 
-                    permission="VIEW_GROUP_PENALTY_THRESHOLD|CREATE_GROUP_PENALTY_THRESHOLD|UPDATE_GROUP_PENALTY_THRESHOLD|DELETE_GROUP_PENALTY_THRESHOLD" 
+                    permission="VIEW_GROUP_PENALTY_THRESHOLD CREATE_GROUP_PENALTY_THRESHOLD UPDATE_GROUP_PENALTY_THRESHOLD DELETE_GROUP_PENALTY_THRESHOLD" 
                     context_field='org_unit'/>
                 <update permission="UPDATE_GROUP_PENALTY_THRESHOLD" context_field='org_unit'/>
                 <delete permission="DELETE_GROUP_PENALTY_THRESHOLD" context_field='org_unit'/>
             </actions>
         </permacrud>
        </class>
-       <class id="ccs" controller="open-ils.cstore" oils_obj:fieldmapper="config::copy_status" oils_persist:tablename="config.copy_status">
+       <class id="ccs" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="config::copy_status" oils_persist:tablename="config.copy_status">
                <fields oils_persist:primary="id" oils_persist:sequence="config.copy_status_id_seq">
                        <field name="isnew" oils_obj:array_position="0" oils_persist:virtual="true" />
                        <field name="ischanged" oils_obj:array_position="1" oils_persist:virtual="true" />
@@ -1802,7 +1802,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
         <permacrud xmlns="http://open-ils.org/spec/opensrf/IDL/permacrud/v1">
             <actions>
                 <create permission="CREATE_COPY_STATUS" global_required="true"/>
-                <retrieve permission="CREATE_COPY_STATUS|UPDATE_COPY_STATUS|DELETE_COPY_STATUS" global_required="true"/>
+                <retrieve permission="CREATE_COPY_STATUS UPDATE_COPY_STATUS DELETE_COPY_STATUS" global_required="true"/>
                 <update permission="UPDATE_COPY_STATUS" global_required="true"/>
                 <delete permission="DELETE_COPY_STATUS" global_required="true"/>
             </actions>
@@ -1850,7 +1850,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
                        <link field="usr" reltype="has_a" key="id" map="" class="au"/>
                </links>
        </class>
-       <class id="acnn" controller="open-ils.cstore" oils_obj:fieldmapper="asset::call_number_note" oils_persist:tablename="asset.call_number_note">
+       <class id="acnn" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="asset::call_number_note" oils_persist:tablename="asset.call_number_note">
                <fields oils_persist:primary="id" oils_persist:sequence="asset.call_number_note_id_seq">
                        <field name="isnew" oils_obj:array_position="0" oils_persist:virtual="true" />
                        <field name="ischanged" oils_obj:array_position="1" oils_persist:virtual="true" />
@@ -1883,7 +1883,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
             </actions>
         </permacrud>
        </class>
-       <class id="arn" controller="open-ils.cstore" oils_obj:fieldmapper="authority::record_note" oils_persist:tablename="authority.record_note">
+       <class id="arn" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="authority::record_note" oils_persist:tablename="authority.record_note">
                <fields oils_persist:primary="id" oils_persist:sequence="authority.record_note_id_seq">
                        <field name="isnew" oils_obj:array_position="0" oils_persist:virtual="true" />
                        <field name="ischanged" oils_obj:array_position="1" oils_persist:virtual="true" />
@@ -2161,7 +2161,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
                        <link field="notify_staff" reltype="has_a" key="id" map="" class="au"/>
                </links>
        </class>
-       <class id="acpl" controller="open-ils.cstore" oils_obj:fieldmapper="asset::copy_location" oils_persist:tablename="asset.copy_location" reporter:label="Copy/Shelving Location">
+       <class id="acpl" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="asset::copy_location" oils_persist:tablename="asset.copy_location" reporter:label="Copy/Shelving Location">
                <fields oils_persist:primary="id" oils_persist:sequence="asset.copy_location_id_seq">
                        <field name="isnew" oils_obj:array_position="0" oils_persist:virtual="true" />
                        <field name="ischanged" oils_obj:array_position="1" oils_persist:virtual="true" />
@@ -2202,7 +2202,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
                        <link field="stat_cat" reltype="has_a" key="id" map="" class="asc"/>
                </links>
        </class>
-       <class id="citm" controller="open-ils.cstore" oils_obj:fieldmapper="config::item_type_map" oils_persist:tablename="config.item_type_map" reporter:label="Item Type Map" oils_persist:field_safe="true">
+       <class id="citm" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="config::item_type_map" oils_persist:tablename="config.item_type_map" reporter:label="Item Type Map" oils_persist:field_safe="true">
                <fields oils_persist:primary="code">
                        <field name="isnew" oils_obj:array_position="0" oils_persist:virtual="true" />
                        <field name="ischanged" oils_obj:array_position="1" oils_persist:virtual="true" />
@@ -2214,13 +2214,13 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
         <permacrud xmlns="http://open-ils.org/spec/opensrf/IDL/permacrud/v1">
             <actions>
                 <create permission="CREATE_MARC_CODE" global_required="true"/>
-                <retrieve permission="CREATE_MARC_CODE|UPDATE_MARC_CODE|DELETE_MARC_CODE" global_required="true"/>
+                <retrieve permission="CREATE_MARC_CODE UPDATE_MARC_CODE DELETE_MARC_CODE" global_required="true"/>
                 <update permission="UPDATE_MARC_CODE" global_required="true"/>
                 <delete permission="DELETE_MARC_CODE" global_required="true"/>
             </actions>
         </permacrud>
        </class>
-       <class id="cblvl" controller="open-ils.cstore" oils_obj:fieldmapper="config::bib_level_map" oils_persist:tablename="config.bib_level_map" reporter:label="Bib Level Map" oils_persist:field_safe="true">
+       <class id="cblvl" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="config::bib_level_map" oils_persist:tablename="config.bib_level_map" reporter:label="Bib Level Map" oils_persist:field_safe="true">
                <fields oils_persist:primary="code">
                        <field name="isnew" oils_obj:array_position="0" oils_persist:virtual="true" />
                        <field name="ischanged" oils_obj:array_position="1" oils_persist:virtual="true" />
@@ -2232,13 +2232,13 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
         <permacrud xmlns="http://open-ils.org/spec/opensrf/IDL/permacrud/v1">
             <actions>
                 <create permission="CREATE_MARC_CODE" global_required="true"/>
-                <retrieve permission="CREATE_MARC_CODE|UPDATE_MARC_CODE|DELETE_MARC_CODE" global_required="true"/>
+                <retrieve permission="CREATE_MARC_CODE UPDATE_MARC_CODE DELETE_MARC_CODE" global_required="true"/>
                 <update permission="UPDATE_MARC_CODE" global_required="true"/>
                 <delete permission="DELETE_MARC_CODE" global_required="true"/>
             </actions>
         </permacrud>
        </class>
-       <class id="sra" controller="open-ils.cstore" oils_obj:fieldmapper="search::relevance_adjustment" oils_persist:tablename="search.relevance_adjustment" reporter:label="Relevance Adjustment">
+       <class id="sra" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="search::relevance_adjustment" oils_persist:tablename="search.relevance_adjustment" reporter:label="Relevance Adjustment">
                <fields oils_persist:primary="id" oils_persist:sequence="search.relevance_adjustment_id_seq">
                        <field name="isnew" oils_obj:array_position="0" oils_persist:virtual="true" />
                        <field name="ischanged" oils_obj:array_position="1" oils_persist:virtual="true" />
@@ -2255,13 +2255,13 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
         <permacrud xmlns="http://open-ils.org/spec/opensrf/IDL/permacrud/v1">
             <actions>
                 <create permission="CREATE_RELEVANCE_ADJUSTMENT" global_required="true"/>
-                <retrieve permission="CREATE_RELEVANCE_ADJUSTMENT|UPDATE_RELEVANCE_ADJUSTMENT|DELETE_RELEVANCE_ADJUSTMENT" global_required="true"/>
+                <retrieve permission="CREATE_RELEVANCE_ADJUSTMENT UPDATE_RELEVANCE_ADJUSTMENT DELETE_RELEVANCE_ADJUSTMENT" global_required="true"/>
                 <update permission="UPDATE_RELEVANCE_ADJUSTMENT" global_required="true"/>
                 <delete permission="DELETE_RELEVANCE_ADJUSTMENT" global_required="true"/>
             </actions>
         </permacrud>
        </class>
-       <class id="lasso" controller="open-ils.cstore" oils_obj:fieldmapper="actor::org_lasso" oils_persist:tablename="actor.org_lasso">
+       <class id="lasso" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="actor::org_lasso" oils_persist:tablename="actor.org_lasso">
                <fields oils_persist:primary="id" oils_persist:sequence="actor.org_lasso_id_seq">
                        <field name="isnew" oils_obj:array_position="0" oils_persist:virtual="true" />
                        <field name="ischanged" oils_obj:array_position="1" oils_persist:virtual="true" />
@@ -2273,13 +2273,13 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
         <permacrud xmlns="http://open-ils.org/spec/opensrf/IDL/permacrud/v1">
             <actions>
                 <create permission="CREATE_LASSO" global_required="true"/>
-                <retrieve permission="CREATE_LASSO|UPDATE_LASSO|DELETE_LASSO" global_required="true"/>
+                <retrieve permission="CREATE_LASSO UPDATE_LASSO DELETE_LASSO" global_required="true"/>
                 <update permission="UPDATE_LASSO" global_required="true"/>
                 <delete permission="DELETE_LASSO" global_required="true"/>
             </actions>
         </permacrud>
        </class>
-       <class id="lmap" controller="open-ils.cstore" oils_obj:fieldmapper="actor::org_lasso_map" oils_persist:tablename="actor.org_lasso_map">
+       <class id="lmap" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="actor::org_lasso_map" oils_persist:tablename="actor.org_lasso_map">
                <fields oils_persist:primary="id" oils_persist:sequence="actor.org_lasso_map_id_seq">
                        <field name="isnew" oils_obj:array_position="0" oils_persist:virtual="true" />
                        <field name="ischanged" oils_obj:array_position="1" oils_persist:virtual="true" />
@@ -2295,7 +2295,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
         <permacrud xmlns="http://open-ils.org/spec/opensrf/IDL/permacrud/v1">
             <actions>
                 <create permission="CREATE_LASSO_MAP" global_required="true"/>
-                <retrieve permission="CREATE_LASSO_MAP|UPDATE_LASSO_MAP|DELETE_LASSO_MAP" global_required="true"/>
+                <retrieve permission="CREATE_LASSO_MAP UPDATE_LASSO_MAP DELETE_LASSO_MAP" global_required="true"/>
                 <update permission="UPDATE_LASSO_MAP" global_required="true"/>
                 <delete permission="DELETE_LASSO_MAP" global_required="true"/>
             </actions>
@@ -2332,7 +2332,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
                </fields>
                <links/>
        </class>
-       <class id="asv" controller="open-ils.cstore" oils_obj:fieldmapper="action::survey" oils_persist:tablename="action.survey" reporter:label="Survey">
+       <class id="asv" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="action::survey" oils_persist:tablename="action.survey" reporter:label="Survey">
                <fields oils_persist:primary="id" oils_persist:sequence="action.survey_id_seq">
                        <field name="isnew" oils_obj:array_position="0" oils_persist:virtual="true" />
                        <field name="ischanged" oils_obj:array_position="1" oils_persist:virtual="true" />
@@ -2364,7 +2364,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
             </actions>
         </permacrud>
        </class>
-       <class id="aoa" controller="open-ils.cstore" oils_obj:fieldmapper="actor::org_address" oils_persist:tablename="actor.org_address">
+       <class id="aoa" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="actor::org_address" oils_persist:tablename="actor.org_address">
                <fields oils_persist:primary="id" oils_persist:sequence="actor.org_address_id_seq">
                        <field name="isnew" oils_obj:array_position="0" oils_persist:virtual="true" />
                        <field name="ischanged" oils_obj:array_position="1" oils_persist:virtual="true" />
@@ -2444,7 +2444,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
                        <link field="bib_rec" reltype="might_have" key="id" map="" class="rhrr"/>
                </links>
        </class>
-       <class id="aou" controller="open-ils.cstore" oils_obj:fieldmapper="actor::org_unit" oils_persist:tablename="actor.org_unit" reporter:label="Organizational Unit" oils_persist:field_safe="true">
+       <class id="aou" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="actor::org_unit" oils_persist:tablename="actor.org_unit" reporter:label="Organizational Unit" oils_persist:field_safe="true">
                <fields oils_persist:primary="id" oils_persist:sequence="actor.org_unit_id_seq">
                        <field name="isnew" oils_obj:array_position="0" oils_persist:virtual="true" />
                        <field name="ischanged" oils_obj:array_position="1" oils_persist:virtual="true" />
@@ -2489,7 +2489,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
         <permacrud xmlns="http://open-ils.org/spec/opensrf/IDL/permacrud/v1">
             <actions>
                 <create permission="CREATE_ORG_UNIT" context_field="parent_ou"/>
-                <retrieve permission="CREATE_ORG_UNIT|UPDATE_ORG_UNIT|DELETE_ORG_UNIT">
+                <retrieve permission="CREATE_ORG_UNIT UPDATE_ORG_UNIT DELETE_ORG_UNIT">
                     <context field="id"/>
                     <context field="parent_ou"/>
                                </retrieve>
@@ -2648,7 +2648,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
                        <link field="owning_lib" reltype="has_a" key="id" map="" class="aou"/>
                </links>
        </class>
-       <class id="aout" controller="open-ils.cstore" oils_obj:fieldmapper="actor::org_unit_type" oils_persist:tablename="actor.org_unit_type" reporter:label="Organizational Unit Type">
+       <class id="aout" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="actor::org_unit_type" oils_persist:tablename="actor.org_unit_type" reporter:label="Organizational Unit Type">
                <fields oils_persist:primary="id" oils_persist:sequence="actor.org_unit_type_id_seq">
                        <field name="isnew" oils_obj:array_position="0" oils_persist:virtual="true" />
                        <field name="ischanged" oils_obj:array_position="1" oils_persist:virtual="true" />
@@ -2671,7 +2671,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
         <permacrud xmlns="http://open-ils.org/spec/opensrf/IDL/permacrud/v1">
             <actions>
                 <create permission="CREATE_ORG_TYPE" global_required="true"/>
-                <retrieve permission="CREATE_ORG_UNIT|UPDATE_ORG_UNIT|DELETE_ORG_UNIT" global_required="true"/>
+                <retrieve permission="CREATE_ORG_UNIT UPDATE_ORG_UNIT DELETE_ORG_UNIT" global_required="true"/>
                 <update permission="UPDATE_ORG_TYPE" global_required="true"/>
                 <delete permission="DELETE_ORG_TYPE" global_required="true"/>
             </actions>
@@ -2738,7 +2738,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
                        <link field="payment_total" reltype="might_have" key="xact" map="" class="rxpt"/>
                </links>
        </class>
-       <class id="cbs" controller="open-ils.cstore" oils_obj:fieldmapper="config::bib_source" oils_persist:tablename="config.bib_source">
+       <class id="cbs" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="config::bib_source" oils_persist:tablename="config.bib_source">
                <fields oils_persist:primary="id" oils_persist:sequence="config.bib_source_id_seq">
                        <field name="isnew" oils_obj:array_position="0" oils_persist:virtual="true" />
                        <field name="ischanged" oils_obj:array_position="1" oils_persist:virtual="true" />
@@ -2829,7 +2829,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
                        <link field="usr" reltype="has_a" key="id" map="" class="au"/>
                </links>
        </class>
-       <class id="clfm" controller="open-ils.cstore" oils_obj:fieldmapper="config::lit_form_map" oils_persist:tablename="config.lit_form_map" reporter:label="Literary Form" oils_persist:field_safe="true">
+       <class id="clfm" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="config::lit_form_map" oils_persist:tablename="config.lit_form_map" reporter:label="Literary Form" oils_persist:field_safe="true">
                <fields oils_persist:primary="code" oils_persist:sequence="">
                        <field name="isnew" oils_obj:array_position="0" oils_persist:virtual="true" />
                        <field name="ischanged" oils_obj:array_position="1" oils_persist:virtual="true" />
@@ -2842,7 +2842,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
         <permacrud xmlns="http://open-ils.org/spec/opensrf/IDL/permacrud/v1">
             <actions>
                 <create permission="CREATE_MARC_CODE" global_required="true"/>
-                <retrieve permission="CREATE_MARC_CODE|UPDATE_MARC_CODE|DELETE_MARC_CODE" global_required="true"/>
+                <retrieve permission="CREATE_MARC_CODE UPDATE_MARC_CODE DELETE_MARC_CODE" global_required="true"/>
                 <update permission="UPDATE_MARC_CODE" global_required="true"/>
                 <delete permission="DELETE_MARC_CODE" global_required="true"/>
             </actions>
@@ -2981,7 +2981,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
                        <link field="xact" reltype="has_a" key="id" map="" class="mbt"/>
                </links>
        </class>
-       <class id="acp" controller="open-ils.cstore" oils_obj:fieldmapper="asset::copy" oils_persist:tablename="asset.copy" reporter:core="true" reporter:label="Item">
+       <class id="acp" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="asset::copy" oils_persist:tablename="asset.copy" reporter:core="true" reporter:label="Item">
                <fields oils_persist:primary="id" oils_persist:sequence="asset.copy_id_seq">
                        <field name="isnew" oils_obj:array_position="0" oils_persist:virtual="true" />
                        <field name="ischanged" oils_obj:array_position="1" oils_persist:virtual="true" />
@@ -3074,7 +3074,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
                </fields>
                <links/>
        </class>
-       <class id="pgt" controller="open-ils.cstore" oils_obj:fieldmapper="permission::grp_tree" oils_persist:tablename="permission.grp_tree" reporter:label="Permission Group">
+       <class id="pgt" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="permission::grp_tree" oils_persist:tablename="permission.grp_tree" reporter:label="Permission Group">
                <fields oils_persist:primary="id" oils_persist:sequence="permission.grp_tree_id_seq">
                        <field name="isnew" oils_obj:array_position="0" oils_persist:virtual="true" />
                        <field name="ischanged" oils_obj:array_position="1" oils_persist:virtual="true" />
@@ -3095,7 +3095,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
         <permacrud xmlns="http://open-ils.org/spec/opensrf/IDL/permacrud/v1">
             <actions>
                 <create permission="CREATE_PERM" global_required="true"/>
-                <retrieve permission="CREATE_PERM|UPDATE_PERM|DELETE_PERM" global_required="true"/>
+                <retrieve permission="CREATE_PERM UPDATE_PERM DELETE_PERM" global_required="true"/>
                 <update permission="UPDATE_PERM" global_required="true"/>
                 <delete permission="DELETE_PERM" global_required="true"/>
             </actions>
@@ -3196,7 +3196,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
                        <link field="stat_cat" reltype="has_a" key="id" map="" class="actsc"/>
                </links>
        </class>
-       <class id="pgpm" controller="open-ils.cstore" oils_obj:fieldmapper="permission::grp_perm_map" oils_persist:tablename="permission.grp_perm_map">
+       <class id="pgpm" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="permission::grp_perm_map" oils_persist:tablename="permission.grp_perm_map">
                <fields oils_persist:primary="id" oils_persist:sequence="permission.grp_perm_map_id_seq">
                        <field name="isnew" oils_obj:array_position="0" oils_persist:virtual="true" />
                        <field name="ischanged" oils_obj:array_position="1" oils_persist:virtual="true" />
@@ -3214,7 +3214,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
         <permacrud xmlns="http://open-ils.org/spec/opensrf/IDL/permacrud/v1">
             <actions>
                 <create permission="ASSIGN_GROUP_PERM" global_required="true"/>
-                <retrieve permission="ASSIGN_GROUP_PERM|UPDATE_GROUP_PERM|REMOVE_GROUP_PERM" global_required="true"/>
+                <retrieve permission="ASSIGN_GROUP_PERM UPDATE_GROUP_PERM REMOVE_GROUP_PERM" global_required="true"/>
                 <update permission="UPDATE_GROUP_PERM" global_required="true"/>
                 <delete permission="REMOVE_GROUP_PERM" global_required="true"/>
             </actions>
@@ -3429,7 +3429,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
                        <link field="owner" reltype="has_a" key="id" map="" class="aou"/>
                </links>
        </class>
-       <class id="ahtc" controller="open-ils.cstore" oils_obj:fieldmapper="action::hold_transit_copy" oils_persist:tablename="action.hold_transit_copy" reporter:core="true" reporter:label="Hold Transit">
+       <class id="ahtc" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="action::hold_transit_copy" oils_persist:tablename="action.hold_transit_copy" reporter:core="true" reporter:label="Hold Transit">
                <fields oils_persist:primary="id" oils_persist:sequence="action.transit_copy_id_seq">
                        <field name="isnew" oils_obj:array_position="0" oils_persist:virtual="true" />
                        <field name="ischanged" oils_obj:array_position="1" oils_persist:virtual="true" />
@@ -3460,8 +3460,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
                     <context link="target_copy" field="circ_lib"/>
                 </create>
                 <retrieve/>
-                <update permission="UPDATE_TRANSIT" context_field="dest|source"/>
-                <delete permission="DELETE_TRANSIT" context_field="dest|source"/>
+                <update permission="UPDATE_TRANSIT" context_field="dest source"/>
+                <delete permission="DELETE_TRANSIT" context_field="dest source"/>
             </actions>
         </permacrud>
        </class>
@@ -3501,7 +3501,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
                        <link field="usr" reltype="has_a" key="id" map="" class="au"/>
                </links>
        </class>
-       <class id="i18n" controller="open-ils.cstore" oils_obj:fieldmapper="config::i18n_core" oils_persist:tablename="config.i18n_core" oils_persist:field_safe="true">
+       <class id="i18n" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="config::i18n_core" oils_persist:tablename="config.i18n_core" oils_persist:field_safe="true">
                <fields oils_persist:primary="id" oils_persist:sequence="config.i18n_core_id_seq">
                        <field name="isnew" oils_obj:array_position="0" oils_persist:virtual="true" />
                        <field name="ischanged" oils_obj:array_position="1" oils_persist:virtual="true" />
@@ -3518,13 +3518,13 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
         <permacrud xmlns="http://open-ils.org/spec/opensrf/IDL/permacrud/v1">
             <actions>
                 <create permission="CREATE_TRANSLATION" global_required="true"/>
-                <retrieve permission="CREATE_TRANSLATION|UPDATE_TRANSLATION|DELETE_TRANSLATION" global_required="true"/>
+                <retrieve permission="CREATE_TRANSLATION UPDATE_TRANSLATION DELETE_TRANSLATION" global_required="true"/>
                 <update permission="UPDATE_TRANSLATION" global_required="true"/>
                 <delete permission="DELETE_TRANSLATION" global_required="true"/>
             </actions>
         </permacrud>
        </class>
-       <class id="i18n_l" controller="open-ils.cstore" oils_obj:fieldmapper="config::i18n_locale" oils_persist:tablename="config.i18n_locale" oils_persist:field_safe="true">
+       <class id="i18n_l" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="config::i18n_locale" oils_persist:tablename="config.i18n_locale" oils_persist:field_safe="true">
                <fields oils_persist:primary="code">
                        <field name="isnew" oils_obj:array_position="0" oils_persist:virtual="true" />
                        <field name="ischanged" oils_obj:array_position="1" oils_persist:virtual="true" />
@@ -3538,13 +3538,13 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
         <permacrud xmlns="http://open-ils.org/spec/opensrf/IDL/permacrud/v1">
             <actions>
                 <create permission="CREATE_LOCALE" global_required="true"/>
-                <retrieve permission="CREATE_LOCALE|UPDATE_LOCALE|DELETE_LOCALE" global_required="true"/>
+                <retrieve permission="CREATE_LOCALE UPDATE_LOCALE DELETE_LOCALE" global_required="true"/>
                 <update permission="UPDATE_LOCALE" global_required="true"/>
                 <delete permission="DELETE_LOCALE" global_required="true"/>
             </actions>
         </permacrud>
        </class>
-       <class id="cbt" controller="open-ils.cstore" oils_obj:fieldmapper="config::billing_type" oils_persist:tablename="config.billing_type">
+       <class id="cbt" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="config::billing_type" oils_persist:tablename="config.billing_type">
                <fields oils_persist:primary="id" oils_persist:sequence="config.billing_type_id_seq">
                        <field name="isnew" oils_obj:array_position="0" oils_persist:virtual="true" />
                        <field name="ischanged" oils_obj:array_position="1" oils_persist:virtual="true" />
@@ -3560,13 +3560,13 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
         <permacrud xmlns="http://open-ils.org/spec/opensrf/IDL/permacrud/v1">
             <actions>
                 <create permission="CREATE_BILLING_TYPE" context_field="owner"/>
-                <retrieve permission="VIEW_BILLING_TYPE|CREATE_BILLING_TYPE|UPDATE_BILLING_TYPE|DELETE_BILLING_TYPE" context_field="owner"/>
+                <retrieve permission="VIEW_BILLING_TYPE CREATE_BILLING_TYPE UPDATE_BILLING_TYPE DELETE_BILLING_TYPE" context_field="owner"/>
                 <update permission="UPDATE_BILLING_TYPE" context_field="owner"/>
                 <delete permission="DELETE_BILLING_TYPE" context_field="owner"/>
             </actions>
         </permacrud>
        </class>
-       <class id="acqct" controller="open-ils.cstore open-ils.reporter-store" oils_obj:fieldmapper="acq::currency_type" oils_persist:tablename="acq.currency_type">
+       <class id="acqct" controller="open-ils.cstore open-ils.reporter-store open-ils.pcrud" oils_obj:fieldmapper="acq::currency_type" oils_persist:tablename="acq.currency_type">
                <fields oils_persist:primary="code">
                        <field name="isnew" oils_obj:array_position="0" oils_persist:virtual="true" />
                        <field name="ischanged" oils_obj:array_position="1" oils_persist:virtual="true" />
@@ -3618,7 +3618,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
                </links>
        </class>
 
-       <class id="acqfs" controller="open-ils.cstore open-ils.reporter-store" oils_obj:fieldmapper="acq::funding_source" oils_persist:tablename="acq.funding_source">
+       <class id="acqfs" controller="open-ils.cstore open-ils.reporter-store open-ils.pcrud" oils_obj:fieldmapper="acq::funding_source" oils_persist:tablename="acq.funding_source">
                <fields oils_persist:primary="id" oils_persist:sequence="acq.funding_source_id_seq">
                        <field name="isnew" oils_obj:array_position="0" oils_persist:virtual="true" />
                        <field name="ischanged" oils_obj:array_position="1" oils_persist:virtual="true" />
index 2db42f5..1145d48 100644 (file)
@@ -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
index ae10adb..c4c6f8a 100644 (file)
@@ -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 <dbi/dbi.h>
 
 #include <time.h>
 #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(
index 9e45203..c756356 100644 (file)
@@ -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;
index 3119214..337ab65 100644 (file)
@@ -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);