LP#1513554 - Prevent deletion of reserved rows.
authorChris Sharp <csharp@georgialibraries.org>
Thu, 5 Nov 2015 18:30:51 +0000 (13:30 -0500)
committerJason Stephenson <jstephenson@mvlc.org>
Fri, 13 Nov 2015 21:08:37 +0000 (16:08 -0500)
It was previously possible to delete reserved rows in
the acq.cancel_reasons table via the UI.  We take a belt
and suspenders approach here:

1) Grey out the checkboxes beside cancel reasons with an
   ID lower than 2000.
2) Create a trigger on the acq.cancel_reason table that
   prevents deletion of rows with an ID lower than 2000.

The trigger executes a new generally available function
for use in similar situations in the future.

Signed-off-by: Chris Sharp <csharp@georgialibraries.org>
Signed-off-by: Kathy Lussier <klussier@masslnc.org>
Signed-off-by: Jason Stephenson <jstephenson@mvlc.org>
Open-ILS/src/sql/Pg/000.functions.general.sql
Open-ILS/src/sql/Pg/200.schema.acq.sql
Open-ILS/src/sql/Pg/t/lp1513554_do_not_delete_reserved_cancel_reasons.pg [new file with mode: 0644]
Open-ILS/src/sql/Pg/upgrade/XXXX.schema.no_delete_acq_cancel_reasons.sql [new file with mode: 0644]
Open-ILS/web/js/ui/default/conify/global/acq/cancel_reason.js

index d62bd70..0cfa909 100644 (file)
@@ -76,4 +76,13 @@ $$ LANGUAGE PLPERLU;
 COMMENT ON FUNCTION evergreen.could_be_serial_holding_code(TEXT) IS
     'Return true if parameter is valid JSON representing an array that at minimum doesn''t make MARC::Field balk and only has subfield labels exactly one character long.  Otherwise false.';
 
+CREATE OR REPLACE FUNCTION evergreen.protect_reserved_rows_from_delete() RETURNS trigger AS $protect_reserved$
+BEGIN
+IF OLD.id < TG_ARGV[0]::INT THEN
+    RAISE EXCEPTION 'Cannot delete row with reserved ID %', OLD.id;
+END IF;
+END
+$protect_reserved$
+LANGUAGE plpgsql;
+
 COMMIT;
index 3405ad2..0359ed7 100644 (file)
@@ -358,6 +358,11 @@ CREATE TABLE acq.cancel_reason (
 
 SELECT SETVAL('acq.cancel_reason_id_seq'::TEXT, 2000);
 
+DROP TRIGGER IF EXISTS acq_no_deleted_reserved_cancel_reasons ON acq.cancel_reason;
+
+CREATE TRIGGER acq_no_deleted_reserved_cancel_reasons BEFORE DELETE ON acq.cancel_reason
+    FOR EACH ROW EXECUTE PROCEDURE evergreen.protect_reserved_rows_from_delete(2000);
+
 CREATE TABLE acq.purchase_order (
        id              SERIAL                          PRIMARY KEY,
        owner           INT                             NOT NULL REFERENCES actor.usr (id) DEFERRABLE INITIALLY DEFERRED,
diff --git a/Open-ILS/src/sql/Pg/t/lp1513554_do_not_delete_reserved_cancel_reasons.pg b/Open-ILS/src/sql/Pg/t/lp1513554_do_not_delete_reserved_cancel_reasons.pg
new file mode 100644 (file)
index 0000000..8042860
--- /dev/null
@@ -0,0 +1,13 @@
+BEGIN;
+
+SELECT plan(1);
+
+SELECT throws_ok(
+    'delete from acq.cancel_reason where id = 1', 
+    'P0001', 
+    'Cannot delete row with reserved ID 1'
+);
+
+SELECT * FROM finish();
+
+ROLLBACK;
diff --git a/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.no_delete_acq_cancel_reasons.sql b/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.no_delete_acq_cancel_reasons.sql
new file mode 100644 (file)
index 0000000..54581fc
--- /dev/null
@@ -0,0 +1,21 @@
+BEGIN;
+
+SELECT evergreen.upgrade_deps_block_check('XXXX', :eg_version);
+
+CREATE OR REPLACE FUNCTION evergreen.protect_reserved_rows_from_delete() RETURNS trigger AS $protect_reserved$
+BEGIN
+IF OLD.id < TG_ARGV[0]::INT THEN
+    RAISE EXCEPTION 'Cannot delete row with reserved ID %', OLD.id; 
+END IF;
+END
+$protect_reserved$
+LANGUAGE plpgsql;
+
+DROP TRIGGER IF EXISTS acq_no_deleted_reserved_cancel_reasons ON acq.cancel_reason;
+
+CREATE TRIGGER acq_no_deleted_reserved_cancel_reasons BEFORE DELETE ON acq.cancel_reason
+    FOR EACH ROW EXECUTE PROCEDURE evergreen.protect_reserved_rows_from_delete(2000);
+
+ALTER TABLE acq.cancel_reason ENABLE TRIGGER acq_no_deleted_reserved_cancel_reasons;
+
+COMMIT;
index 6cd329f..86d8c61 100644 (file)
@@ -19,6 +19,11 @@ function setup() {
         );
     };
 
+    crGrid.disableSelectorForRow = function(rowIdx) {
+        var item = crGrid.getItem(rowIdx);
+        return (crGrid.store.getValue(item, 'id') < 2000);
+    }
+
     new openils.User().buildPermOrgSelector(
         'ADMIN_ACQ_CANCEL_CAUSE', contextOrgSelector, null, connect);
 }