From cca47aac03002baf7749946850243f3ba9e773b3 Mon Sep 17 00:00:00 2001 From: Bill Erickson Date: Wed, 23 May 2018 17:01:03 -0400 Subject: [PATCH] LP#1750894 Cascade settings metadata Return info about the supported setting types with each setting value lookup in the cascade settings lookup func. Return that info to the browser. This will make it possible for the browser to determine what setting types are available e.g. if it needs to fall back to local storage or expose an org-setting valuea application option. Signed-off-by: Bill Erickson --- Open-ILS/examples/fm_IDL.xml | 14 +++ .../lib/OpenILS/Application/Actor/Settings.pm | 13 +-- .../upgrade/XXXX.schema.workstation-settings.sql | 125 ++++++++++++++++----- Open-ILS/web/js/ui/default/staff/services/hatch.js | 29 +++-- 4 files changed, 128 insertions(+), 53 deletions(-) diff --git a/Open-ILS/examples/fm_IDL.xml b/Open-ILS/examples/fm_IDL.xml index bb9f9c06ae..2848be8cbf 100644 --- a/Open-ILS/examples/fm_IDL.xml +++ b/Open-ILS/examples/fm_IDL.xml @@ -12403,6 +12403,20 @@ SELECT usr, + + + + + + + + + + diff --git a/Open-ILS/src/perlmods/lib/OpenILS/Application/Actor/Settings.pm b/Open-ILS/src/perlmods/lib/OpenILS/Application/Actor/Settings.pm index c3a49139c1..d76aedb1d7 100644 --- a/Open-ILS/src/perlmods/lib/OpenILS/Application/Actor/Settings.pm +++ b/Open-ILS/src/perlmods/lib/OpenILS/Application/Actor/Settings.pm @@ -72,22 +72,21 @@ sub retrieve_settings { my $ses = OpenSRF::AppSession->create('open-ils.cstore'); my $req = $ses->request('open-ils.cstore.json_query', { from => [ - 'actor.get_setting_batch', + 'actor.get_cascade_setting_batch', $settings_str, $aou_id, $user_id, $ws_id ] }); # The DB responds in setting-name order. while (my $resp = $req->recv) { - my $json = $resp->content->{'actor.get_setting_batch'}; - $client->respond( - {$settings->[0] => OpenSRF::Utils::JSON->JSON2perl($json)}) - if defined $json; - shift @$settings; + my $sumhash = $resp->content; + my $summary = Fieldmapper::actor::cascade_setting_summary->new; + $summary->$_($sumhash->{$_}) for keys %$sumhash; + $summary->value(OpenSRF::Utils::JSON->JSON2perl($summary->value)); + $client->respond($summary); } $ses->kill_me; - return undef; } diff --git a/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.workstation-settings.sql b/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.workstation-settings.sql index ddb927c062..85b3b0d724 100644 --- a/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.workstation-settings.sql +++ b/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.workstation-settings.sql @@ -1,5 +1,15 @@ BEGIN; +/* + +CREATE TYPE actor.cascade_setting_summary AS ( + name TEXT, + value JSON, + has_org_setting BOOLEAN, + has_user_setting BOOLEAN, + has_workstation_setting BOOLEAN +); + -- SELECT evergreen.upgrade_deps_block_check('XXXX', :eg_version); CREATE TABLE config.workstation_setting_type ( @@ -66,41 +76,88 @@ CREATE CONSTRAINT TRIGGER check_setting_is_usr_or_ws AFTER INSERT OR UPDATE ON config.workstation_setting_type FOR EACH ROW EXECUTE PROCEDURE config.setting_is_user_or_ws(); -CREATE OR REPLACE FUNCTION actor.get_setting(setting_name TEXT, - org_id INT, user_id INT, workstation_id INT) RETURNS JSON AS + */ + +CREATE OR REPLACE FUNCTION actor.get_cascade_setting( + setting_name TEXT, org_id INT, user_id INT, workstation_id INT) + RETURNS actor.cascade_setting_summary AS $FUNC$ DECLARE setting_value JSON; + summary actor.cascade_setting_summary; org_setting_type config.org_unit_setting_type%ROWTYPE; BEGIN + summary.name := setting_name; + + -- Collect the org setting type status first in case we exit early. + -- The existance of an org setting type is not considered + -- privileged information. + SELECT INTO org_setting_type * + FROM config.org_unit_setting_type WHERE name = setting_name; + IF FOUND THEN + summary.has_org_setting := TRUE; + ELSE + summary.has_org_setting := FALSE; + END IF; + -- User and workstation settings have the same priority. -- Start with user settings since that's the simplest code path. + -- The workstation_id is ignored if no user_id is provided. IF user_id IS NOT NULL THEN - SELECT INTO setting_value value - FROM actor.usr_setting + + SELECT INTO summary.value value FROM actor.usr_setting WHERE usr = user_id AND name = setting_name; - IF FOUND THEN - RETURN setting_value; - END IF; - END IF; - -- No user setting value found. Next try workstation. - IF workstation_id IS NOT NULL THEN + IF FOUND THEN + -- if we have a value, we have a setting type + summary.has_user_setting := TRUE; - SELECT INTO setting_value value - FROM actor.workstation_setting - WHERE workstation = workstation_id AND name = setting_name; + IF workstation_id THEN + -- Only inform the caller about the workstation + -- setting type disposition when a workstation id is + -- provided. Otherwise, it's NULL to indicate UNKNOWN. + summary.has_workstation_setting := FALSE; + END IF; - IF FOUND THEN - RETURN setting_value; + RETURN summary; END IF; - -- Workstation setting not found. However, since we have a - -- workstation let's use its owning_lib if necessary. - IF org_id IS NULL THEN - SELECT INTO org_id owning_lib - FROM actor.workstation WHERE id = workstation_id; + -- no user setting value, but a setting type may exist + SELECT INTO summary.has_user_setting EXISTS ( + SELECT TRUE FROM config.usr_setting_type + WHERE name = setting_name + ); + + IF workstation_id IS NOT NULL THEN + + IF NOT summary.has_user_setting THEN + -- A workstation setting type may only exist when a user + -- setting type does not. + + SELECT INTO summary.value value + FROM actor.workstation_setting + WHERE workstation = workstation_id AND name = setting_name; + + IF FOUND THEN + -- if we have a value, we have a setting type + summary.has_workstation_setting := TRUE; + RETURN summary; + END IF; + + -- no value, but a setting type may exist + SELECT INTO summary.has_workstation_setting EXISTS ( + SELECT TRUE FROM config.workstation_setting_type + WHERE name = setting_name + ); + END IF; + + -- Finally make use of the workstation to determine the org + -- unit if none is provided. + IF org_id IS NULL AND summary.has_org_setting THEN + SELECT INTO org_id owning_lib + FROM actor.workstation WHERE id = workstation_id; + END IF; END IF; END IF; @@ -108,23 +165,25 @@ BEGIN -- First see if we have any data that needs protecting, then -- check the permission if needed. + IF NOT summary.has_org_setting THEN + RETURN summary; + END IF; + + -- avoid putting the value into the summary until we confirm + -- the value should be visible to the caller. SELECT INTO setting_value value FROM actor.org_unit_ancestor_setting(setting_name, org_id); IF NOT FOUND THEN -- No value found -- perm check is irrelevant. - RETURN NULL; + RETURN summary; END IF; - -- Check view permissions if necessary. - SELECT INTO org_setting_type * - FROM config.org_unit_setting_type WHERE name = setting_name; - IF org_setting_type.view_perm IS NOT NULL THEN IF user_id IS NULL THEN RAISE NOTICE 'Perm check required but no user_id provided'; - RETURN NULL; + RETURN summary; END IF; IF NOT permission.usr_has_perm( @@ -133,27 +192,31 @@ BEGIN THEN RAISE NOTICE 'Perm check failed for user % on %', user_id, org_setting_type.view_perm; - RETURN NULL; + RETURN summary; END IF; END IF; -- Perm check succeeded or was not necessary. - RETURN setting_value; + summary.value := setting_value; + RETURN summary; END; $FUNC$ LANGUAGE PLPGSQL; -CREATE OR REPLACE FUNCTION actor.get_setting_batch(setting_names TEXT[], - org_id INT, user_id INT, workstation_id INT) RETURNS SETOF JSON AS +CREATE OR REPLACE FUNCTION actor.get_cascade_setting_batch( + setting_names TEXT[], org_id INT, user_id INT, workstation_id INT) + RETURNS SETOF actor.cascade_setting_summary AS $FUNC$ -- Returns a row per setting matching the setting name order. If no -- value is applied, NULL is returned to retain name-response ordering. DECLARE setting_name TEXT; + summary actor.cascade_setting_summary; BEGIN FOREACH setting_name IN ARRAY setting_names LOOP - RETURN NEXT * FROM actor.get_setting( + SELECT INTO summary * FROM actor.get_cascade_setting( setting_Name, org_id, user_id, workstation_id); + RETURN NEXT summary; END LOOP; END; $FUNC$ LANGUAGE PLPGSQL; diff --git a/Open-ILS/web/js/ui/default/staff/services/hatch.js b/Open-ILS/web/js/ui/default/staff/services/hatch.js index e9d45689b9..c360b79555 100644 --- a/Open-ILS/web/js/ui/default/staff/services/hatch.js +++ b/Open-ILS/web/js/ui/default/staff/services/hatch.js @@ -361,8 +361,9 @@ angular.module('egCoreMod') } service.getServerItem = function(key) { - if (service.keyCache[key] != undefined) + if (key in service.keyCache) { return $q.when(service.keyCache[key]) + } if (!service.auth) service.auth = $injector.get('egAuth'); if (!service.auth.token()) return $q.when(null); @@ -372,7 +373,10 @@ angular.module('egCoreMod') 'open-ils.actor.settings.retrieve.atomic', [key], service.auth.token() ).then(function(settings) { - service.keyCache[key] = settings[0] ? settings[0][key] : null; + var val = settings[0].value(); + // The server returns null for undefined settings. + // Treat as undefined for backwards compat. + service.keyCache[key] = (val === null) ? undefined : val; return service.keyCache[key]; }); } @@ -464,20 +468,15 @@ angular.module('egCoreMod') 'open-ils.actor.settings.retrieve', keys, service.auth.token() ).then( - function() { - // cache a value of null for any settings that have - // no server values applied - angular.forEach(keys, function(key) { - if (Object.keys(foundValues).indexOf(key) == -1) - service.keyCache[key] = foundValues[key] = null; - }); - return foundValues; - }, - null, + function() { return foundValues; }, + function() {}, function(setting) { - // when streaming we receive one setting per response - var key = Object.keys(setting)[0]; - service.keyCache[key] = foundValues[key] = setting[key]; + var val = setting.value(); + // The server returns null for undefined settings. + // Treat as undefined for backwards compat. + service.keyCache[setting.name()] = + foundValues[setting.name()] = + (val === null) ? undefined : val; } ); } -- 2.11.0