</permacrud>
</class>
- <!-- ********************************************************************************************************************* -->
+ <class id="cwst" controller="open-ils.cstore open-ils.pcrud"
+ oils_obj:fieldmapper="config::workstation_setting_type"
+ oils_persist:tablename="config.workstation_setting_type"
+ reporter:label="Workstation Setting Type">
+ <fields oils_persist:primary="name">
+ <field name="name" reporter:datatype="text"/>
+ <field name="label" reporter:datatype="text" oils_persist:i18n="true"/>
+ <field name="description" reporter:datatype="text" oils_persist:i18n="true"/>
+ <field name="datatype" reporter:datatype="text"/>
+ <field name="fm_class" reporter:datatype="text"/>
+ <field name="grp" reporter:datatype="link"/>
+ </fields>
+ <links>
+ <link field="name" reltype="has_many" key="name" map="" class="aous"/>
+ <link field="grp" reltype="has_a" key="name" map="" class="csg"/>
+ </links>
+ <permacrud xmlns="http://open-ils.org/spec/opensrf/IDL/permacrud/v1">
+ <actions>
+ <create permission="ADMIN_WORKSTATION_SETTING_TYPE" global_required="true"/>
+ <retrieve/>
+ <update permission="ADMIN_WORKSTATION_SETTING_TYPE" global_required="true"/>
+ <delete permission="ADMIN_WORKSTATION_SETTING_TYPE" global_required="true"/>
+ </actions>
+ </permacrud>
+ </class>
+ <!-- no pcrud access is granted for now, because it's assumed these
+ setting values will be applied and retrived via the API. -->
+ <class id="awss"
+ controller="open-ils.cstore"
+ oils_obj:fieldmapper="actor::workstation_setting"
+ oils_persist:tablename="actor.workstation_setting"
+ reporter:label="Workstation Setting">
+ <fields oils_persist:primary="id" oils_persist:sequence="actor.workstation_setting_id_seq">
+ <field reporter:label="Setting ID" name="id" reporter:datatype="id" />
+ <field reporter:label="Name" name="name" reporter:datatype="link"/>
+ <field reporter:label="Value" name="value" reporter:datatype="text"/>
+ <field reporter:label="Workstation" name="workstation" reporter:datatype="link"/>
+ </fields>
+ <links>
+ <link field="name" reltype="has_a" key="name" map="" class="cwst"/>
+ <link field="workstation" reltype="has_a" key="id" map="" class="aws"/>
+ </links>
+ </class>
+
+ <!-- ********************************************************************************************************************* -->
</IDL>
<!--
lib/OpenILS/Application/Actor/Friends.pm
lib/OpenILS/Application/Actor/Stage.pm
lib/OpenILS/Application/Actor/UserGroups.pm
+lib/OpenILS/Application/Actor/Settings.pm
lib/OpenILS/Application/AppUtils.pm
lib/OpenILS/Application/Booking.pm
lib/OpenILS/Application/Cat.pm
use OpenILS::Application::Actor::UserGroups;
use OpenILS::Application::Actor::Friends;
use OpenILS::Application::Actor::Stage;
+use OpenILS::Application::Actor::Settings;
use OpenILS::Utils::CStoreEditor qw/:funcs/;
use OpenILS::Utils::Penalty;
--- /dev/null
+package OpenILS::Application::Actor::Settings;
+use strict; use warnings;
+use base 'OpenILS::Application';
+use OpenSRF::AppSession;
+use OpenSRF::Utils::Logger q/$logger/;
+use OpenILS::Application::AppUtils;
+use OpenILS::Utils::CStoreEditor q/:funcs/;
+use OpenILS::Utils::Fieldmapper;
+use OpenSRF::Utils::JSON;
+use OpenILS::Event;
+my $U = "OpenILS::Application::AppUtils";
+
+# Setting names may only contains letters, numbers, unders, and dots.
+my $name_regex = qr/[^a-zA-Z0-9_\.]/;
+
+__PACKAGE__->register_method (
+ method => 'retrieve_settings',
+ api_name => 'open-ils.actor.settings.retrieve',
+ stream => 1,
+ signature => {
+ desc => q/
+ Returns org unit, user, and workstation setting values
+ for the requested setting types.
+
+ The API makes a best effort to find the correct setting
+ value based on the available context data.
+
+ If no auth token is provided, only publicly visible org
+ unit settings may be returned.
+
+ If no workstation is linked to the provided auth token, only
+ user settings and perm-visible org unit settings may be
+ returned.
+
+ If no org unit is provided, but a workstation is linked to the
+ auth token, the owning lib of the workstation is used as the
+ context org unit.
+ /,
+ params => [
+ {desc => 'settings. List of setting names', type => 'array'},
+ {desc => 'authtoken. Optional', type => 'string'},
+ {desc => 'org_id. Optional', type => 'number'}
+ ],
+ return => {
+ desc => q/
+ Stream of setting name=>value pairs in the same order
+ as the provided list of setting names. No key-value
+ pair is returned for settings that have no value defined./,
+ type => 'string'
+ }
+ }
+);
+
+sub retrieve_settings {
+ my ($self, $client, $settings, $auth, $org_id) = @_;
+
+ my ($aou_id, $user_id, $ws_id, $evt) = get_context($auth, $org_id);
+ return $evt if $evt; # bogus auth token
+
+ return OpenILS::Event->new('BAD_PARAMS',
+ desc => 'Cannot retrieve settings without a user or org unit')
+ unless ($user_id || $aou_id);
+
+ # Setting names may only contains letters, numbers, unders, and dots.
+ s/$name_regex//g foreach @$settings;
+
+ # Encode as a db-friendly array.
+ my $settings_str = '{' . join(',', @$settings) . '}';
+
+ # Some settings could be bulky, so fetch them as a stream from
+ # cstore, relaying values back to the caller as they arrive.
+ my $ses = OpenSRF::AppSession->create('open-ils.cstore');
+ my $req = $ses->request('open-ils.cstore.json_query', {
+ from => [
+ 'actor.get_cascade_setting_batch',
+ $settings_str, $aou_id, $user_id, $ws_id
+ ]
+ });
+
+ while (my $resp = $req->recv) {
+ my $summary = $resp->content;
+ $summary->{value} = OpenSRF::Utils::JSON->JSON2perl($summary->{value});
+ $client->respond($summary);
+ }
+
+ $ses->kill_me;
+ return undef;
+}
+
+# Returns ($org_id, $user_id, $ws_id, $evt);
+# Any value may be undef.
+sub get_context {
+ my ($auth, $org_id) = @_;
+
+ return ($org_id) unless $auth;
+
+ my $e = new_editor(authtoken => $auth);
+ return (undef, undef, undef, $e->event) unless $e->checkauth;
+
+ my $user_id = $e->requestor->id;
+ my $ws_id = $e->requestor->wsid;
+
+ # default to the workstation org if needed.
+ $org_id = $e->requestor->ws_ou if $ws_id && !$org_id;
+
+ return ($org_id, $user_id, $ws_id);
+}
+
+__PACKAGE__->register_method (
+ method => 'apply_user_or_ws_setting',
+ api_name => 'open-ils.actor.settings.apply.user_or_ws',
+ stream => 1,
+ signature => {
+ desc => q/
+ Apply values to user or workstation settings, depending
+ on which is supported via local configuration.
+
+ The API ignores nonexistent settings and only returns error
+ events when an auth, permission, or internal error occurs.
+ /,
+ params => [
+ {desc => 'authtoken', type => 'string'},
+ {desc => 'settings. Hash of key/value pairs', type => 'object'},
+ ],
+ return => {
+ desc => 'Returns the number of applied settings on succes, Event on error.',
+ type => 'number or event'
+ }
+ }
+);
+
+sub apply_user_or_ws_setting {
+ my ($self, $client, $auth, $settings) = @_;
+
+ my $e = new_editor(authtoken => $auth, xact => 1);
+ return $e->die_event unless $e->checkauth;
+
+ my $applied = 0;
+ my $ws_allowed = 0;
+
+ for my $name (keys %$settings) {
+ $name =~ s/$name_regex//g;
+ my $val = $$settings{$name};
+ my $stype = $e->retrieve_config_usr_setting_type($name);
+
+ if ($stype) {
+ my $evt = apply_user_setting($e, $name, $val);
+ return $evt if $evt;
+ $applied++;
+
+ } elsif ($e->requestor->wsid) {
+ $stype = $e->retrieve_config_workstation_setting_type($name);
+ next unless $stype; # no such workstation setting, skip.
+
+ if (!$ws_allowed) {
+ # Confirm the caller has permission to apply workstation
+ # settings at the logged-in workstation before applying.
+ # Do the perm check here so it's only needed once per batch.
+ return $e->die_event unless
+ $ws_allowed = $e->allowed('APPLY_WORKSTATION_SETTING');
+ }
+
+ my $evt = apply_workstation_setting($e, $name, $val);
+ return $evt if $evt;
+ $applied++;
+ }
+ }
+
+ $e->commit if $applied > 0;
+ $e->rollback if $applied == 0;
+
+ return $applied;
+}
+
+# CUD for user settings.
+# Returns undef on success, Event on error.
+# NOTE: This code was copied as-is from
+# open-ils.actor.patron.settings.update, because it lets us
+# manage the batch of updates within a single transaction. Also
+# worth noting the APIs in this mod could eventually replace
+# open-ils.actor.patron.settings.update. Maybe.
+sub apply_user_setting {
+ my ($e, $name, $val) = @_;
+ my $user_id = $e->requestor->id;
+
+ my $set = $e->search_actor_user_setting(
+ {usr => $user_id, name => $name})->[0];
+
+ if (defined $val) {
+ $val = OpenSRF::Utils::JSON->perl2JSON($val);
+ if ($set) {
+ $set->value($val);
+ $e->update_actor_user_setting($set) or return $e->die_event;
+ } else {
+ $set = Fieldmapper::actor::user_setting->new;
+ $set->usr($user_id);
+ $set->name($name);
+ $set->value($val);
+ $e->create_actor_user_setting($set) or return $e->die_event;
+ }
+ } elsif ($set) {
+ $e->delete_actor_user_setting($set) or return $e->die_event;
+ }
+
+ return undef;
+}
+
+# CUD for workstation settings.
+# Assumes ->wsid contains a value and permissions have been checked.
+# Returns undef on success, Event on error.
+sub apply_workstation_setting {
+ my ($e, $name, $val) = @_;
+ my $ws_id = $e->requestor->wsid;
+
+ my $set = $e->search_actor_workstation_setting(
+ {workstation => $ws_id, name => $name})->[0];
+
+ if (defined $val) {
+ $val = OpenSRF::Utils::JSON->perl2JSON($val);
+
+ if ($set) {
+ $set->value($val);
+ $e->update_actor_workstation_setting($set) or return $e->die_event;
+ } else {
+ $set = Fieldmapper::actor::workstation_setting->new;
+ $set->workstation($ws_id);
+ $set->name($name);
+ $set->value($val);
+ $e->create_actor_workstation_setting($set) or return $e->die_event;
+ }
+ } elsif ($set) {
+ $e->delete_actor_workstation_setting($set) or return $e->die_event;
+ }
+
+ return undef;
+}
+
+__PACKAGE__->register_method (
+ method => 'applied_settings',
+ api_name => 'open-ils.actor.settings.staff.applied.names',
+ stream => 1,
+ authoritative => 1,
+ signature => {
+ desc => q/
+ Returns a list of setting names where a value is applied to
+ the current user or workstation.
+
+ This is a staff-only API created primarily to support the
+ getKeys() functionality used in the browser client for
+ server-managed settings.
+ /,
+ params => [
+ {desc => 'authtoken', type => 'string'},
+ {desc =>
+ 'prefix. Limit keys to those starting with $prefix',
+ type => 'string'
+ },
+ ],
+ return => {
+ desc => 'List of strings, Event on error',
+ type => 'array'
+ }
+ }
+);
+
+sub applied_settings {
+ my ($self, $client, $auth, $prefix) = @_;
+
+ my $e = new_editor(authtoken => $auth);
+ return $e->event unless $e->checkauth;
+ return $e->event unless $e->allowed('STAFF_LOGIN');
+
+ my $query = {
+ select => {awss => ['name']},
+ from => 'awss',
+ where => {
+ workstation => $e->requestor->wsid
+ }
+ };
+
+ $query->{where}->{name} = {like => "$prefix%"} if $prefix;
+
+ for my $key (@{$e->json_query($query)}) {
+ $client->respond($key->{name});
+ }
+
+ $query = {
+ select => {aus => ['name']},
+ from => 'aus',
+ where => {
+ usr => $e->requestor->id
+ }
+ };
+
+ $query->{where}->{name} = {like => "$prefix%"} if $prefix;
+
+ for my $key (@{$e->json_query($query)}) {
+ $client->respond($key->{name});
+ }
+
+ return undef;
+}
+
+
+
+1;
);
+CREATE TABLE config.workstation_setting_type (
+ name TEXT PRIMARY KEY,
+ label TEXT UNIQUE NOT NULL,
+ grp TEXT REFERENCES config.settings_group (name),
+ description TEXT,
+ datatype TEXT NOT NULL DEFAULT 'string',
+ fm_class TEXT,
+ --
+ -- define valid datatypes
+ --
+ CONSTRAINT cwst_valid_datatype CHECK ( datatype IN
+ ( 'bool', 'integer', 'float', 'currency', 'interval',
+ 'date', 'string', 'object', 'array', 'link' ) ),
+ --
+ -- fm_class is meaningful only for 'link' datatype
+ --
+ CONSTRAINT cwst_no_empty_link CHECK
+ ( ( datatype = 'link' AND fm_class IS NOT NULL ) OR
+ ( datatype <> 'link' AND fm_class IS NULL ) )
+);
+
+-- Prevent setting types from being both user and workstation settings.
+CREATE OR REPLACE FUNCTION config.setting_is_user_or_ws()
+RETURNS TRIGGER AS $FUNC$
+BEGIN
+
+ IF TG_TABLE_NAME = 'usr_setting_type' THEN
+ PERFORM TRUE FROM config.workstation_setting_type cwst
+ WHERE cwst.name = NEW.name;
+ IF NOT FOUND THEN
+ RETURN NULL;
+ END IF;
+ END IF;
+
+ IF TG_TABLE_NAME = 'workstation_setting_type' THEN
+ PERFORM TRUE FROM config.usr_setting_type cust
+ WHERE cust.name = NEW.name;
+ IF NOT FOUND THEN
+ RETURN NULL;
+ END IF;
+ END IF;
+
+ RAISE EXCEPTION
+ '% Cannot be used as both a user setting and a workstation setting.',
+ NEW.name;
+END;
+$FUNC$ LANGUAGE PLPGSQL STABLE;
+
+CREATE CONSTRAINT TRIGGER check_setting_is_usr_or_ws
+ AFTER INSERT OR UPDATE ON config.usr_setting_type
+ FOR EACH ROW EXECUTE PROCEDURE config.setting_is_user_or_ws();
+
+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();
+
+
+
-- Some handy functions, based on existing ones, to provide optional ingest normalization
CREATE OR REPLACE FUNCTION public.left_trunc( TEXT, INT ) RETURNS TEXT AS $func$
END LOOP;
END $$ LANGUAGE PLPGSQL;
+CREATE TABLE actor.workstation_setting (
+ id SERIAL PRIMARY KEY,
+ workstation INT NOT NULL REFERENCES actor.workstation (id)
+ ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
+ name TEXT NOT NULL REFERENCES config.workstation_setting_type (name)
+ ON DELETE CASCADE ON UPDATE CASCADE DEFERRABLE INITIALLY DEFERRED,
+ value JSON NOT NULL
+);
+
+CREATE INDEX actor_workstation_setting_workstation_idx
+ ON actor.workstation_setting (workstation);
+
+CREATE TYPE actor.cascade_setting_summary AS (
+ name TEXT,
+ value JSON,
+ has_org_setting BOOLEAN,
+ has_user_setting BOOLEAN,
+ has_workstation_setting BOOLEAN
+);
+
+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 summary.value value FROM actor.usr_setting
+ WHERE usr = user_id AND name = setting_name;
+
+ IF FOUND THEN
+ -- if we have a value, we have a setting type
+ summary.has_user_setting := TRUE;
+
+ IF workstation_id IS NOT NULL 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;
+
+ RETURN summary;
+ END IF;
+
+ -- 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;
+
+ -- Some org unit settings are protected by a view permission.
+ -- 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 summary;
+ END IF;
+
+ 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 summary;
+ END IF;
+
+ IF NOT permission.usr_has_perm(
+ user_id, (SELECT code FROM permission.perm_list
+ WHERE id = org_setting_type.view_perm), org_id)
+ THEN
+ RAISE NOTICE 'Perm check failed for user % on %',
+ user_id, org_setting_type.view_perm;
+ RETURN summary;
+ END IF;
+ END IF;
+
+ -- Perm check succeeded or was not necessary.
+ summary.value := setting_value;
+ RETURN summary;
+END;
+$FUNC$ LANGUAGE PLPGSQL;
+
+
+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
+ 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;
+
+
COMMIT;
'VIEW_PERMIT_CHECKOUT',
'VIEW_USER',
'VIEW_USER_FINES_SUMMARY',
- 'VIEW_USER_TRANSACTIONS');
+ 'VIEW_USER_TRANSACTIONS',
+ 'APPLY_WORKSTATION_SETTING'
+ );
INSERT INTO permission.grp_perm_map (grp, perm, depth, grantable)
SELECT
AND control_set = 1
AND ahf.heading_purpose = 'related'
AND ahf.heading_type = 'genre_form_term';
+
+INSERT INTO permission.perm_list (id, code, description) VALUES
+ (607, 'APPLY_WORKSTATION_SETTING',
+ oils_i18n_gettext(607, 'APPLY_WORKSTATION_SETTING', 'ppl', 'description'));
+
+INSERT INTO config.workstation_setting_type (name, grp, datatype, label)
+VALUES (
+ 'eg.circ.checkin.no_precat_alert', 'circ', 'bool',
+ oils_i18n_gettext(
+ 'eg.circ.checkin.no_precat_alert',
+ 'Checkin: Ignore Precataloged Items',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.circ.checkin.noop', 'circ', 'bool',
+ oils_i18n_gettext(
+ 'eg.circ.checkin.noop',
+ 'Checkin: Suppress Holds and Transits',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.circ.checkin.void_overdues', 'circ', 'bool',
+ oils_i18n_gettext(
+ 'eg.circ.checkin.void_overdues',
+ 'Checkin: Amnesty Mode',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.circ.checkin.auto_print_holds_transits', 'circ', 'bool',
+ oils_i18n_gettext(
+ 'eg.circ.checkin.auto_print_holds_transits',
+ 'Checkin: Auto-Print Holds and Transits',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.circ.checkin.clear_expired', 'circ', 'bool',
+ oils_i18n_gettext(
+ 'eg.circ.checkin.clear_expired',
+ 'Checkin: Clear Holds Shelf',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.circ.checkin.retarget_holds', 'circ', 'bool',
+ oils_i18n_gettext(
+ 'eg.circ.checkin.retarget_holds',
+ 'Checkin: Retarget Local Holds',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.circ.checkin.retarget_holds_all', 'circ', 'bool',
+ oils_i18n_gettext(
+ 'eg.circ.checkin.retarget_holds_all',
+ 'Checkin: Retarget All Statuses',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.circ.checkin.hold_as_transit', 'circ', 'bool',
+ oils_i18n_gettext(
+ 'eg.circ.checkin.hold_as_transit',
+ 'Checkin: Capture Local Holds as Transits',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.circ.checkin.manual_float', 'circ', 'bool',
+ oils_i18n_gettext(
+ 'eg.circ.checkin.manual_float',
+ 'Checkin: Manual Floating Active',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.circ.patron.summary.collapse', 'circ', 'bool',
+ oils_i18n_gettext(
+ 'eg.circ.patron.summary.collapse',
+ 'Collaps Patron Summary Display',
+ 'cwst', 'label'
+ )
+), (
+ 'circ.bills.receiptonpay', 'circ', 'bool',
+ oils_i18n_gettext(
+ 'circ.bills.receiptonpay',
+ 'Print Receipt On Payment',
+ 'cwst', 'label'
+ )
+), (
+ 'circ.renew.strict_barcode', 'circ', 'bool',
+ oils_i18n_gettext(
+ 'circ.renew.strict_barcode',
+ 'Renew: Strict Barcode',
+ 'cwst', 'label'
+ )
+), (
+ 'circ.checkin.strict_barcode', 'circ', 'bool',
+ oils_i18n_gettext(
+ 'circ.checkin.strict_barcode',
+ 'Checkin: Strict Barcode',
+ 'cwst', 'label'
+ )
+), (
+ 'cat.holdings_show_copies', 'cat', 'bool',
+ oils_i18n_gettext(
+ 'cat.holdings_show_copies',
+ 'Holdings View Show Copies',
+ 'cwst', 'label'
+ )
+), (
+ 'cat.holdings_show_empty', 'cat', 'bool',
+ oils_i18n_gettext(
+ 'cat.holdings_show_empty',
+ 'Holdings View Show Empty Volumes',
+ 'cwst', 'label'
+ )
+), (
+ 'cat.holdings_show_vols', 'cat', 'bool',
+ oils_i18n_gettext(
+ 'cat.holdings_show_vols',
+ 'Holdings View Show Volumes',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.circ.patron.search.include_inactive', 'circ', 'bool',
+ oils_i18n_gettext(
+ 'eg.circ.patron.search.include_inactive',
+ 'Patron Search Include Inactive',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.circ.patron.search.show_extras', 'circ', 'bool',
+ oils_i18n_gettext(
+ 'eg.circ.patron.search.show_extras',
+ 'Patron Search Show Extra Search Options',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.grid.circ.checkin.checkin', 'gui', 'object',
+ oils_i18n_gettext(
+ 'eg.grid.circ.checkin.checkin',
+ 'Grid Config: circ.checkin.checkin',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.grid.circ.checkin.capture', 'gui', 'object',
+ oils_i18n_gettext(
+ 'eg.grid.circ.checkin.capture',
+ 'Grid Config: circ.checkin.capture',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.grid.admin.server.config.copy_tag_type', 'gui', 'object',
+ oils_i18n_gettext(
+ 'eg.grid.admin.server.config.copy_tag_type',
+ 'Grid Config: admin.server.config.copy_tag_type',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.grid.admin.server.config.metabib_field_virtual_map.grid', 'gui', 'object',
+ oils_i18n_gettext(
+ 'eg.grid.admin.server.config.metabib_field_virtual_map.grid',
+ 'Grid Config: admin.server.config.metabib_field_virtual_map.grid',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.grid.admin.server.config.metabib_field.grid', 'gui', 'object',
+ oils_i18n_gettext(
+ 'eg.grid.admin.server.config.metabib_field.grid',
+ 'Grid Config: admin.server.config.metabib_field.grid',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.grid.admin.server.config.marc_field', 'gui', 'object',
+ oils_i18n_gettext(
+ 'eg.grid.admin.server.config.marc_field',
+ 'Grid Config: admin.server.config.marc_field',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.grid.admin.server.asset.copy_tag', 'gui', 'object',
+ oils_i18n_gettext(
+ 'eg.grid.admin.server.asset.copy_tag',
+ 'Grid Config: admin.server.asset.copy_tag',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.grid.admin.local.circ.neg_balance_users', 'gui', 'object',
+ oils_i18n_gettext(
+ 'eg.grid.admin.local.circ.neg_balance_users',
+ 'Grid Config: admin.local.circ.neg_balance_users',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.grid.admin.local.rating.badge', 'gui', 'object',
+ oils_i18n_gettext(
+ 'eg.grid.admin.local.rating.badge',
+ 'Grid Config: admin.local.rating.badge',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.grid.admin.workstation.work_log', 'gui', 'object',
+ oils_i18n_gettext(
+ 'eg.grid.admin.workstation.work_log',
+ 'Grid Config: admin.workstation.work_log',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.grid.admin.workstation.patron_log', 'gui', 'object',
+ oils_i18n_gettext(
+ 'eg.grid.admin.workstation.patron_log',
+ 'Grid Config: admin.workstation.patron_log',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.grid.admin.serials.pattern_template', 'gui', 'object',
+ oils_i18n_gettext(
+ 'eg.grid.admin.serials.pattern_template',
+ 'Grid Config: admin.serials.pattern_template',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.grid.serials.copy_templates', 'gui', 'object',
+ oils_i18n_gettext(
+ 'eg.grid.serials.copy_templates',
+ 'Grid Config: serials.copy_templates',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.grid.cat.record_overlay.holdings', 'gui', 'object',
+ oils_i18n_gettext(
+ 'eg.grid.cat.record_overlay.holdings',
+ 'Grid Config: cat.record_overlay.holdings',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.grid.cat.bucket.record.search', 'gui', 'object',
+ oils_i18n_gettext(
+ 'eg.grid.cat.bucket.record.search',
+ 'Grid Config: cat.bucket.record.search',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.grid.cat.bucket.record.view', 'gui', 'object',
+ oils_i18n_gettext(
+ 'eg.grid.cat.bucket.record.view',
+ 'Grid Config: cat.bucket.record.view',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.grid.cat.bucket.record.pending', 'gui', 'object',
+ oils_i18n_gettext(
+ 'eg.grid.cat.bucket.record.pending',
+ 'Grid Config: cat.bucket.record.pending',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.grid.cat.bucket.copy.view', 'gui', 'object',
+ oils_i18n_gettext(
+ 'eg.grid.cat.bucket.copy.view',
+ 'Grid Config: cat.bucket.copy.view',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.grid.cat.bucket.copy.pending', 'gui', 'object',
+ oils_i18n_gettext(
+ 'eg.grid.cat.bucket.copy.pending',
+ 'Grid Config: cat.bucket.copy.pending',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.grid.cat.items', 'gui', 'object',
+ oils_i18n_gettext(
+ 'eg.grid.cat.items',
+ 'Grid Config: cat.items',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.grid.cat.volcopy.copies', 'gui', 'object',
+ oils_i18n_gettext(
+ 'eg.grid.cat.volcopy.copies',
+ 'Grid Config: cat.volcopy.copies',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.grid.cat.volcopy.copies.complete', 'gui', 'object',
+ oils_i18n_gettext(
+ 'eg.grid.cat.volcopy.copies.complete',
+ 'Grid Config: cat.volcopy.copies.complete',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.grid.cat.peer_bibs', 'gui', 'object',
+ oils_i18n_gettext(
+ 'eg.grid.cat.peer_bibs',
+ 'Grid Config: cat.peer_bibs',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.grid.cat.catalog.holds', 'gui', 'object',
+ oils_i18n_gettext(
+ 'eg.grid.cat.catalog.holds',
+ 'Grid Config: cat.catalog.holds',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.grid.cat.holdings', 'gui', 'object',
+ oils_i18n_gettext(
+ 'eg.grid.cat.holdings',
+ 'Grid Config: cat.holdings',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.grid.cat.z3950_results', 'gui', 'object',
+ oils_i18n_gettext(
+ 'eg.grid.cat.z3950_results',
+ 'Grid Config: cat.z3950_results',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.grid.circ.holds.shelf', 'gui', 'object',
+ oils_i18n_gettext(
+ 'eg.grid.circ.holds.shelf',
+ 'Grid Config: circ.holds.shelf',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.grid.circ.holds.pull', 'gui', 'object',
+ oils_i18n_gettext(
+ 'eg.grid.circ.holds.pull',
+ 'Grid Config: circ.holds.pull',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.grid.circ.in_house_use', 'gui', 'object',
+ oils_i18n_gettext(
+ 'eg.grid.circ.in_house_use',
+ 'Grid Config: circ.in_house_use',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.grid.circ.renew', 'gui', 'object',
+ oils_i18n_gettext(
+ 'eg.grid.circ.renew',
+ 'Grid Config: circ.renew',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.grid.circ.transits.list', 'gui', 'object',
+ oils_i18n_gettext(
+ 'eg.grid.circ.transits.list',
+ 'Grid Config: circ.transits.list',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.grid.circ.patron.holds', 'gui', 'object',
+ oils_i18n_gettext(
+ 'eg.grid.circ.patron.holds',
+ 'Grid Config: circ.patron.holds',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.grid.circ.pending_patrons.list', 'gui', 'object',
+ oils_i18n_gettext(
+ 'eg.grid.circ.pending_patrons.list',
+ 'Grid Config: circ.pending_patrons.list',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.grid.circ.patron.items_out.noncat', 'gui', 'object',
+ oils_i18n_gettext(
+ 'eg.grid.circ.patron.items_out.noncat',
+ 'Grid Config: circ.patron.items_out.noncat',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.grid.circ.patron.items_out', 'gui', 'object',
+ oils_i18n_gettext(
+ 'eg.grid.circ.patron.items_out',
+ 'Grid Config: circ.patron.items_out',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.grid.circ.patron.billhistory_payments', 'gui', 'object',
+ oils_i18n_gettext(
+ 'eg.grid.circ.patron.billhistory_payments',
+ 'Grid Config: circ.patron.billhistory_payments',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.grid.user.bucket.view', 'gui', 'object',
+ oils_i18n_gettext(
+ 'eg.grid.user.bucket.view',
+ 'Grid Config: user.bucket.view',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.grid.user.bucket.pending', 'gui', 'object',
+ oils_i18n_gettext(
+ 'eg.grid.user.bucket.pending',
+ 'Grid Config: user.bucket.pending',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.grid.circ.patron.staff_messages', 'gui', 'object',
+ oils_i18n_gettext(
+ 'eg.grid.circ.patron.staff_messages',
+ 'Grid Config: circ.patron.staff_messages',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.grid.circ.patron.archived_messages', 'gui', 'object',
+ oils_i18n_gettext(
+ 'eg.grid.circ.patron.archived_messages',
+ 'Grid Config: circ.patron.archived_messages',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.grid.circ.patron.bills', 'gui', 'object',
+ oils_i18n_gettext(
+ 'eg.grid.circ.patron.bills',
+ 'Grid Config: circ.patron.bills',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.grid.circ.patron.checkout', 'gui', 'object',
+ oils_i18n_gettext(
+ 'eg.grid.circ.patron.checkout',
+ 'Grid Config: circ.patron.checkout',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.grid.serials.mfhd_grid', 'gui', 'object',
+ oils_i18n_gettext(
+ 'eg.grid.serials.mfhd_grid',
+ 'Grid Config: serials.mfhd_grid',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.grid.serials.view_item_grid', 'gui', 'object',
+ oils_i18n_gettext(
+ 'eg.grid.serials.view_item_grid',
+ 'Grid Config: serials.view_item_grid',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.grid.serials.dist_stream_grid', 'gui', 'object',
+ oils_i18n_gettext(
+ 'eg.grid.serials.dist_stream_grid',
+ 'Grid Config: serials.dist_stream_grid',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.grid.circ.patron.search', 'gui', 'object',
+ oils_i18n_gettext(
+ 'eg.grid.circ.patron.search',
+ 'Grid Config: circ.patron.search',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.cat.record.summary.collapse', 'gui', 'bool',
+ oils_i18n_gettext(
+ 'eg.cat.record.summary.collapse',
+ 'Collapse Bib Record Summary',
+ 'cwst', 'label'
+ )
+), (
+ 'cat.marcedit.flateditor', 'gui', 'bool',
+ oils_i18n_gettext(
+ 'cat.marcedit.flateditor',
+ 'Use Flat MARC Editor',
+ 'cwst', 'label'
+ )
+), (
+ 'cat.marcedit.stack_subfields', 'gui', 'bool',
+ oils_i18n_gettext(
+ 'cat.marcedit.stack_subfields',
+ 'MARC Editor Stack Subfields',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.offline.print_receipt', 'gui', 'bool',
+ oils_i18n_gettext(
+ 'eg.offline.print_receipt',
+ 'Offline Print Receipt',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.offline.strict_barcode', 'gui', 'bool',
+ oils_i18n_gettext(
+ 'eg.offline.strict_barcode',
+ 'Offline Use Strict Barcode',
+ 'cwst', 'label'
+ )
+), (
+ 'cat.default_bib_marc_template', 'gui', 'string',
+ oils_i18n_gettext(
+ 'cat.default_bib_marc_template',
+ 'Default MARC Template',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.audio.disable', 'gui', 'bool',
+ oils_i18n_gettext(
+ 'eg.audio.disable',
+ 'Disable Staff Client Notification Audio',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.search.adv_pane', 'gui', 'string',
+ oils_i18n_gettext(
+ 'eg.search.adv_pane',
+ 'Catalog Advanced Search Default Pane',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.print.template_context.bills_current', 'gui', 'string',
+ oils_i18n_gettext(
+ 'eg.print.template_context.bills_current',
+ 'Print Template Context: bills_current',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.print.template.bills_current', 'gui', 'string',
+ oils_i18n_gettext(
+ 'eg.print.template.bills_current',
+ 'Print Template: bills_current',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.print.template_context.bills_historical', 'gui', 'string',
+ oils_i18n_gettext(
+ 'eg.print.template_context.bills_historical',
+ 'Print Template Context: bills_historical',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.print.template.bills_historical', 'gui', 'string',
+ oils_i18n_gettext(
+ 'eg.print.template.bills_historical',
+ 'Print Template: bills_historical',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.print.template_context.bill_payment', 'gui', 'string',
+ oils_i18n_gettext(
+ 'eg.print.template_context.bill_payment',
+ 'Print Template Context: bill_payment',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.print.template.bill_payment', 'gui', 'string',
+ oils_i18n_gettext(
+ 'eg.print.template.bill_payment',
+ 'Print Template: bill_payment',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.print.template_context.checkin', 'gui', 'string',
+ oils_i18n_gettext(
+ 'eg.print.template_context.checkin',
+ 'Print Template Context: checkin',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.print.template.checkin', 'gui', 'string',
+ oils_i18n_gettext(
+ 'eg.print.template.checkin',
+ 'Print Template: checkin',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.print.template_context.checkout', 'gui', 'string',
+ oils_i18n_gettext(
+ 'eg.print.template_context.checkout',
+ 'Print Template Context: checkout',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.print.template.checkout', 'gui', 'string',
+ oils_i18n_gettext(
+ 'eg.print.template.checkout',
+ 'Print Template: checkout',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.print.template_context.hold_transit_slip', 'gui', 'string',
+ oils_i18n_gettext(
+ 'eg.print.template_context.hold_transit_slip',
+ 'Print Template Context: hold_transit_slip',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.print.template.hold_transit_slip', 'gui', 'string',
+ oils_i18n_gettext(
+ 'eg.print.template.hold_transit_slip',
+ 'Print Template: hold_transit_slip',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.print.template_context.hold_shelf_slip', 'gui', 'string',
+ oils_i18n_gettext(
+ 'eg.print.template_context.hold_shelf_slip',
+ 'Print Template Context: hold_shelf_slip',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.print.template.hold_shelf_slip', 'gui', 'string',
+ oils_i18n_gettext(
+ 'eg.print.template.hold_shelf_slip',
+ 'Print Template: hold_shelf_slip',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.print.template_context.holds_for_bib', 'gui', 'string',
+ oils_i18n_gettext(
+ 'eg.print.template_context.holds_for_bib',
+ 'Print Template Context: holds_for_bib',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.print.template.holds_for_bib', 'gui', 'string',
+ oils_i18n_gettext(
+ 'eg.print.template.holds_for_bib',
+ 'Print Template: holds_for_bib',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.print.template_context.holds_for_patron', 'gui', 'string',
+ oils_i18n_gettext(
+ 'eg.print.template_context.holds_for_patron',
+ 'Print Template Context: holds_for_patron',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.print.template.holds_for_patron', 'gui', 'string',
+ oils_i18n_gettext(
+ 'eg.print.template.holds_for_patron',
+ 'Print Template: holds_for_patron',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.print.template_context.hold_pull_list', 'gui', 'string',
+ oils_i18n_gettext(
+ 'eg.print.template_context.hold_pull_list',
+ 'Print Template Context: hold_pull_list',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.print.template.hold_pull_list', 'gui', 'string',
+ oils_i18n_gettext(
+ 'eg.print.template.hold_pull_list',
+ 'Print Template: hold_pull_list',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.print.template_context.hold_shelf_list', 'gui', 'string',
+ oils_i18n_gettext(
+ 'eg.print.template_context.hold_shelf_list',
+ 'Print Template Context: hold_shelf_list',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.print.template.hold_shelf_list', 'gui', 'string',
+ oils_i18n_gettext(
+ 'eg.print.template.hold_shelf_list',
+ 'Print Template: hold_shelf_list',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.print.template_context.in_house_use_list', 'gui', 'string',
+ oils_i18n_gettext(
+ 'eg.print.template_context.in_house_use_list',
+ 'Print Template Context: in_house_use_list',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.print.template.in_house_use_list', 'gui', 'string',
+ oils_i18n_gettext(
+ 'eg.print.template.in_house_use_list',
+ 'Print Template: in_house_use_list',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.print.template_context.item_status', 'gui', 'string',
+ oils_i18n_gettext(
+ 'eg.print.template_context.item_status',
+ 'Print Template Context: item_status',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.print.template.item_status', 'gui', 'string',
+ oils_i18n_gettext(
+ 'eg.print.template.item_status',
+ 'Print Template: item_status',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.print.template_context.items_out', 'gui', 'string',
+ oils_i18n_gettext(
+ 'eg.print.template_context.items_out',
+ 'Print Template Context: items_out',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.print.template.items_out', 'gui', 'string',
+ oils_i18n_gettext(
+ 'eg.print.template.items_out',
+ 'Print Template: items_out',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.print.template_context.patron_address', 'gui', 'string',
+ oils_i18n_gettext(
+ 'eg.print.template_context.patron_address',
+ 'Print Template Context: patron_address',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.print.template.patron_address', 'gui', 'string',
+ oils_i18n_gettext(
+ 'eg.print.template.patron_address',
+ 'Print Template: patron_address',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.print.template_context.patron_data', 'gui', 'string',
+ oils_i18n_gettext(
+ 'eg.print.template_context.patron_data',
+ 'Print Template Context: patron_data',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.print.template.patron_data', 'gui', 'string',
+ oils_i18n_gettext(
+ 'eg.print.template.patron_data',
+ 'Print Template: patron_data',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.print.template_context.patron_note', 'gui', 'string',
+ oils_i18n_gettext(
+ 'eg.print.template_context.patron_note',
+ 'Print Template Context: patron_note',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.print.template.patron_note', 'gui', 'string',
+ oils_i18n_gettext(
+ 'eg.print.template.patron_note',
+ 'Print Template: patron_note',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.print.template_context.renew', 'gui', 'string',
+ oils_i18n_gettext(
+ 'eg.print.template_context.renew',
+ 'Print Template Context: renew',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.print.template.renew', 'gui', 'string',
+ oils_i18n_gettext(
+ 'eg.print.template.renew',
+ 'Print Template: renew',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.print.template_context.transit_list', 'gui', 'string',
+ oils_i18n_gettext(
+ 'eg.print.template_context.transit_list',
+ 'Print Template Context: transit_list',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.print.template.transit_list', 'gui', 'string',
+ oils_i18n_gettext(
+ 'eg.print.template.transit_list',
+ 'Print Template: transit_list',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.print.template_context.transit_slip', 'gui', 'string',
+ oils_i18n_gettext(
+ 'eg.print.template_context.transit_slip',
+ 'Print Template Context: transit_slip',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.print.template.transit_slip', 'gui', 'string',
+ oils_i18n_gettext(
+ 'eg.print.template.transit_slip',
+ 'Print Template: transit_slip',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.print.template_context.offline_checkout', 'gui', 'string',
+ oils_i18n_gettext(
+ 'eg.print.template_context.offline_checkout',
+ 'Print Template Context: offline_checkout',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.print.template.offline_checkout', 'gui', 'string',
+ oils_i18n_gettext(
+ 'eg.print.template.offline_checkout',
+ 'Print Template: offline_checkout',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.print.template_context.offline_renew', 'gui', 'string',
+ oils_i18n_gettext(
+ 'eg.print.template_context.offline_renew',
+ 'Print Template Context: offline_renew',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.print.template.offline_renew', 'gui', 'string',
+ oils_i18n_gettext(
+ 'eg.print.template.offline_renew',
+ 'Print Template: offline_renew',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.print.template_context.offline_checkin', 'gui', 'string',
+ oils_i18n_gettext(
+ 'eg.print.template_context.offline_checkin',
+ 'Print Template Context: offline_checkin',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.print.template.offline_checkin', 'gui', 'string',
+ oils_i18n_gettext(
+ 'eg.print.template.offline_checkin',
+ 'Print Template: offline_checkin',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.print.template_context.offline_in_house_use', 'gui', 'string',
+ oils_i18n_gettext(
+ 'eg.print.template_context.offline_in_house_use',
+ 'Print Template Context: offline_in_house_use',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.print.template.offline_in_house_use', 'gui', 'string',
+ oils_i18n_gettext(
+ 'eg.print.template.offline_in_house_use',
+ 'Print Template: offline_in_house_use',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.serials.stream_names', 'gui', 'array',
+ oils_i18n_gettext(
+ 'eg.serials.stream_names',
+ 'Serials Local Stream Names',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.serials.items.do_print_routing_lists', 'gui', 'bool',
+ oils_i18n_gettext(
+ 'eg.serials.items.do_print_routing_lists',
+ 'Serials Print Routing Lists',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.serials.items.receive_and_barcode', 'gui', 'bool',
+ oils_i18n_gettext(
+ 'eg.serials.items.receive_and_barcode',
+ 'Serials Barcode On Receive',
+ 'cwst', 'label'
+ )
+);
+
+
+-- More values with fm_class'es
+INSERT INTO config.workstation_setting_type (name, grp, datatype, fm_class, label)
+VALUES (
+ 'eg.search.search_lib', 'gui', 'link', 'aou',
+ oils_i18n_gettext(
+ 'eg.search.search_lib',
+ 'Staff Catalog Default Search Library',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.search.pref_lib', 'gui', 'link', 'aou',
+ oils_i18n_gettext(
+ 'eg.search.pref_lib',
+ 'Staff Catalog Preferred Library',
+ 'cwst', 'label'
+ )
+);
+
+
+
--- /dev/null
+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 (
+ name TEXT PRIMARY KEY,
+ label TEXT UNIQUE NOT NULL,
+ grp TEXT REFERENCES config.settings_group (name),
+ description TEXT,
+ datatype TEXT NOT NULL DEFAULT 'string',
+ fm_class TEXT,
+ --
+ -- define valid datatypes
+ --
+ CONSTRAINT cwst_valid_datatype CHECK ( datatype IN
+ ( 'bool', 'integer', 'float', 'currency', 'interval',
+ 'date', 'string', 'object', 'array', 'link' ) ),
+ --
+ -- fm_class is meaningful only for 'link' datatype
+ --
+ CONSTRAINT cwst_no_empty_link CHECK
+ ( ( datatype = 'link' AND fm_class IS NOT NULL ) OR
+ ( datatype <> 'link' AND fm_class IS NULL ) )
+);
+
+CREATE TABLE actor.workstation_setting (
+ id SERIAL PRIMARY KEY,
+ workstation INT NOT NULL REFERENCES actor.workstation (id)
+ ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
+ name TEXT NOT NULL REFERENCES config.workstation_setting_type (name)
+ ON DELETE CASCADE ON UPDATE CASCADE DEFERRABLE INITIALLY DEFERRED,
+ value JSON NOT NULL
+);
+
+
+CREATE INDEX actor_workstation_setting_workstation_idx
+ ON actor.workstation_setting (workstation);
+
+CREATE OR REPLACE FUNCTION config.setting_is_user_or_ws()
+RETURNS TRIGGER AS $FUNC$
+BEGIN
+
+ IF TG_TABLE_NAME = 'usr_setting_type' THEN
+ PERFORM TRUE FROM config.workstation_setting_type cwst
+ WHERE cwst.name = NEW.name;
+ IF NOT FOUND THEN
+ RETURN NULL;
+ END IF;
+ END IF;
+
+ IF TG_TABLE_NAME = 'workstation_setting_type' THEN
+ PERFORM TRUE FROM config.usr_setting_type cust
+ WHERE cust.name = NEW.name;
+ IF NOT FOUND THEN
+ RETURN NULL;
+ END IF;
+ END IF;
+
+ RAISE EXCEPTION
+ '% Cannot be used as both a user setting and a workstation setting.',
+ NEW.name;
+END;
+$FUNC$ LANGUAGE PLPGSQL STABLE;
+
+CREATE CONSTRAINT TRIGGER check_setting_is_usr_or_ws
+ AFTER INSERT OR UPDATE ON config.usr_setting_type
+ FOR EACH ROW EXECUTE PROCEDURE config.setting_is_user_or_ws();
+
+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_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 summary.value value FROM actor.usr_setting
+ WHERE usr = user_id AND name = setting_name;
+
+ IF FOUND THEN
+ -- if we have a value, we have a setting type
+ summary.has_user_setting := TRUE;
+
+ IF workstation_id IS NOT NULL 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;
+
+ RETURN summary;
+ END IF;
+
+ -- 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;
+
+ -- Some org unit settings are protected by a view permission.
+ -- 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 summary;
+ END IF;
+
+ 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 summary;
+ END IF;
+
+ IF NOT permission.usr_has_perm(
+ user_id, (SELECT code FROM permission.perm_list
+ WHERE id = org_setting_type.view_perm), org_id)
+ THEN
+ RAISE NOTICE 'Perm check failed for user % on %',
+ user_id, org_setting_type.view_perm;
+ RETURN summary;
+ END IF;
+ END IF;
+
+ -- Perm check succeeded or was not necessary.
+ summary.value := setting_value;
+ RETURN summary;
+END;
+$FUNC$ LANGUAGE PLPGSQL;
+
+
+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
+ 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;
+
+COMMIT;
+
+
+
--- /dev/null
+BEGIN;
+
+INSERT INTO permission.perm_list (id, code, description) VALUES
+ (607, 'APPLY_WORKSTATION_SETTING',
+ oils_i18n_gettext(607, 'APPLY_WORKSTATION_SETTING', 'ppl', 'description'));
+
+INSERT INTO config.workstation_setting_type (name, grp, datatype, label)
+VALUES (
+ 'eg.circ.checkin.no_precat_alert', 'circ', 'bool',
+ oils_i18n_gettext(
+ 'eg.circ.checkin.no_precat_alert',
+ 'Checkin: Ignore Precataloged Items',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.circ.checkin.noop', 'circ', 'bool',
+ oils_i18n_gettext(
+ 'eg.circ.checkin.noop',
+ 'Checkin: Suppress Holds and Transits',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.circ.checkin.void_overdues', 'circ', 'bool',
+ oils_i18n_gettext(
+ 'eg.circ.checkin.void_overdues',
+ 'Checkin: Amnesty Mode',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.circ.checkin.auto_print_holds_transits', 'circ', 'bool',
+ oils_i18n_gettext(
+ 'eg.circ.checkin.auto_print_holds_transits',
+ 'Checkin: Auto-Print Holds and Transits',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.circ.checkin.clear_expired', 'circ', 'bool',
+ oils_i18n_gettext(
+ 'eg.circ.checkin.clear_expired',
+ 'Checkin: Clear Holds Shelf',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.circ.checkin.retarget_holds', 'circ', 'bool',
+ oils_i18n_gettext(
+ 'eg.circ.checkin.retarget_holds',
+ 'Checkin: Retarget Local Holds',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.circ.checkin.retarget_holds_all', 'circ', 'bool',
+ oils_i18n_gettext(
+ 'eg.circ.checkin.retarget_holds_all',
+ 'Checkin: Retarget All Statuses',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.circ.checkin.hold_as_transit', 'circ', 'bool',
+ oils_i18n_gettext(
+ 'eg.circ.checkin.hold_as_transit',
+ 'Checkin: Capture Local Holds as Transits',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.circ.checkin.manual_float', 'circ', 'bool',
+ oils_i18n_gettext(
+ 'eg.circ.checkin.manual_float',
+ 'Checkin: Manual Floating Active',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.circ.patron.summary.collapse', 'circ', 'bool',
+ oils_i18n_gettext(
+ 'eg.circ.patron.summary.collapse',
+ 'Collaps Patron Summary Display',
+ 'cwst', 'label'
+ )
+), (
+ 'circ.bills.receiptonpay', 'circ', 'bool',
+ oils_i18n_gettext(
+ 'circ.bills.receiptonpay',
+ 'Print Receipt On Payment',
+ 'cwst', 'label'
+ )
+), (
+ 'circ.renew.strict_barcode', 'circ', 'bool',
+ oils_i18n_gettext(
+ 'circ.renew.strict_barcode',
+ 'Renew: Strict Barcode',
+ 'cwst', 'label'
+ )
+), (
+ 'circ.checkin.strict_barcode', 'circ', 'bool',
+ oils_i18n_gettext(
+ 'circ.checkin.strict_barcode',
+ 'Checkin: Strict Barcode',
+ 'cwst', 'label'
+ )
+), (
+ 'cat.holdings_show_copies', 'cat', 'bool',
+ oils_i18n_gettext(
+ 'cat.holdings_show_copies',
+ 'Holdings View Show Copies',
+ 'cwst', 'label'
+ )
+), (
+ 'cat.holdings_show_empty', 'cat', 'bool',
+ oils_i18n_gettext(
+ 'cat.holdings_show_empty',
+ 'Holdings View Show Empty Volumes',
+ 'cwst', 'label'
+ )
+), (
+ 'cat.holdings_show_vols', 'cat', 'bool',
+ oils_i18n_gettext(
+ 'cat.holdings_show_vols',
+ 'Holdings View Show Volumes',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.circ.patron.search.include_inactive', 'circ', 'bool',
+ oils_i18n_gettext(
+ 'eg.circ.patron.search.include_inactive',
+ 'Patron Search Include Inactive',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.circ.patron.search.show_extras', 'circ', 'bool',
+ oils_i18n_gettext(
+ 'eg.circ.patron.search.show_extras',
+ 'Patron Search Show Extra Search Options',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.grid.circ.checkin.checkin', 'gui', 'object',
+ oils_i18n_gettext(
+ 'eg.grid.circ.checkin.checkin',
+ 'Grid Config: circ.checkin.checkin',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.grid.circ.checkin.capture', 'gui', 'object',
+ oils_i18n_gettext(
+ 'eg.grid.circ.checkin.capture',
+ 'Grid Config: circ.checkin.capture',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.grid.admin.server.config.copy_tag_type', 'gui', 'object',
+ oils_i18n_gettext(
+ 'eg.grid.admin.server.config.copy_tag_type',
+ 'Grid Config: admin.server.config.copy_tag_type',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.grid.admin.server.config.metabib_field_virtual_map.grid', 'gui', 'object',
+ oils_i18n_gettext(
+ 'eg.grid.admin.server.config.metabib_field_virtual_map.grid',
+ 'Grid Config: admin.server.config.metabib_field_virtual_map.grid',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.grid.admin.server.config.metabib_field.grid', 'gui', 'object',
+ oils_i18n_gettext(
+ 'eg.grid.admin.server.config.metabib_field.grid',
+ 'Grid Config: admin.server.config.metabib_field.grid',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.grid.admin.server.config.marc_field', 'gui', 'object',
+ oils_i18n_gettext(
+ 'eg.grid.admin.server.config.marc_field',
+ 'Grid Config: admin.server.config.marc_field',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.grid.admin.server.asset.copy_tag', 'gui', 'object',
+ oils_i18n_gettext(
+ 'eg.grid.admin.server.asset.copy_tag',
+ 'Grid Config: admin.server.asset.copy_tag',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.grid.admin.local.circ.neg_balance_users', 'gui', 'object',
+ oils_i18n_gettext(
+ 'eg.grid.admin.local.circ.neg_balance_users',
+ 'Grid Config: admin.local.circ.neg_balance_users',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.grid.admin.local.rating.badge', 'gui', 'object',
+ oils_i18n_gettext(
+ 'eg.grid.admin.local.rating.badge',
+ 'Grid Config: admin.local.rating.badge',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.grid.admin.workstation.work_log', 'gui', 'object',
+ oils_i18n_gettext(
+ 'eg.grid.admin.workstation.work_log',
+ 'Grid Config: admin.workstation.work_log',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.grid.admin.workstation.patron_log', 'gui', 'object',
+ oils_i18n_gettext(
+ 'eg.grid.admin.workstation.patron_log',
+ 'Grid Config: admin.workstation.patron_log',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.grid.admin.serials.pattern_template', 'gui', 'object',
+ oils_i18n_gettext(
+ 'eg.grid.admin.serials.pattern_template',
+ 'Grid Config: admin.serials.pattern_template',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.grid.serials.copy_templates', 'gui', 'object',
+ oils_i18n_gettext(
+ 'eg.grid.serials.copy_templates',
+ 'Grid Config: serials.copy_templates',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.grid.cat.record_overlay.holdings', 'gui', 'object',
+ oils_i18n_gettext(
+ 'eg.grid.cat.record_overlay.holdings',
+ 'Grid Config: cat.record_overlay.holdings',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.grid.cat.bucket.record.search', 'gui', 'object',
+ oils_i18n_gettext(
+ 'eg.grid.cat.bucket.record.search',
+ 'Grid Config: cat.bucket.record.search',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.grid.cat.bucket.record.view', 'gui', 'object',
+ oils_i18n_gettext(
+ 'eg.grid.cat.bucket.record.view',
+ 'Grid Config: cat.bucket.record.view',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.grid.cat.bucket.record.pending', 'gui', 'object',
+ oils_i18n_gettext(
+ 'eg.grid.cat.bucket.record.pending',
+ 'Grid Config: cat.bucket.record.pending',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.grid.cat.bucket.copy.view', 'gui', 'object',
+ oils_i18n_gettext(
+ 'eg.grid.cat.bucket.copy.view',
+ 'Grid Config: cat.bucket.copy.view',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.grid.cat.bucket.copy.pending', 'gui', 'object',
+ oils_i18n_gettext(
+ 'eg.grid.cat.bucket.copy.pending',
+ 'Grid Config: cat.bucket.copy.pending',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.grid.cat.items', 'gui', 'object',
+ oils_i18n_gettext(
+ 'eg.grid.cat.items',
+ 'Grid Config: cat.items',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.grid.cat.volcopy.copies', 'gui', 'object',
+ oils_i18n_gettext(
+ 'eg.grid.cat.volcopy.copies',
+ 'Grid Config: cat.volcopy.copies',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.grid.cat.volcopy.copies.complete', 'gui', 'object',
+ oils_i18n_gettext(
+ 'eg.grid.cat.volcopy.copies.complete',
+ 'Grid Config: cat.volcopy.copies.complete',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.grid.cat.peer_bibs', 'gui', 'object',
+ oils_i18n_gettext(
+ 'eg.grid.cat.peer_bibs',
+ 'Grid Config: cat.peer_bibs',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.grid.cat.catalog.holds', 'gui', 'object',
+ oils_i18n_gettext(
+ 'eg.grid.cat.catalog.holds',
+ 'Grid Config: cat.catalog.holds',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.grid.cat.holdings', 'gui', 'object',
+ oils_i18n_gettext(
+ 'eg.grid.cat.holdings',
+ 'Grid Config: cat.holdings',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.grid.cat.z3950_results', 'gui', 'object',
+ oils_i18n_gettext(
+ 'eg.grid.cat.z3950_results',
+ 'Grid Config: cat.z3950_results',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.grid.circ.holds.shelf', 'gui', 'object',
+ oils_i18n_gettext(
+ 'eg.grid.circ.holds.shelf',
+ 'Grid Config: circ.holds.shelf',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.grid.circ.holds.pull', 'gui', 'object',
+ oils_i18n_gettext(
+ 'eg.grid.circ.holds.pull',
+ 'Grid Config: circ.holds.pull',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.grid.circ.in_house_use', 'gui', 'object',
+ oils_i18n_gettext(
+ 'eg.grid.circ.in_house_use',
+ 'Grid Config: circ.in_house_use',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.grid.circ.renew', 'gui', 'object',
+ oils_i18n_gettext(
+ 'eg.grid.circ.renew',
+ 'Grid Config: circ.renew',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.grid.circ.transits.list', 'gui', 'object',
+ oils_i18n_gettext(
+ 'eg.grid.circ.transits.list',
+ 'Grid Config: circ.transits.list',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.grid.circ.patron.holds', 'gui', 'object',
+ oils_i18n_gettext(
+ 'eg.grid.circ.patron.holds',
+ 'Grid Config: circ.patron.holds',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.grid.circ.pending_patrons.list', 'gui', 'object',
+ oils_i18n_gettext(
+ 'eg.grid.circ.pending_patrons.list',
+ 'Grid Config: circ.pending_patrons.list',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.grid.circ.patron.items_out.noncat', 'gui', 'object',
+ oils_i18n_gettext(
+ 'eg.grid.circ.patron.items_out.noncat',
+ 'Grid Config: circ.patron.items_out.noncat',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.grid.circ.patron.items_out', 'gui', 'object',
+ oils_i18n_gettext(
+ 'eg.grid.circ.patron.items_out',
+ 'Grid Config: circ.patron.items_out',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.grid.circ.patron.billhistory_payments', 'gui', 'object',
+ oils_i18n_gettext(
+ 'eg.grid.circ.patron.billhistory_payments',
+ 'Grid Config: circ.patron.billhistory_payments',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.grid.user.bucket.view', 'gui', 'object',
+ oils_i18n_gettext(
+ 'eg.grid.user.bucket.view',
+ 'Grid Config: user.bucket.view',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.grid.user.bucket.pending', 'gui', 'object',
+ oils_i18n_gettext(
+ 'eg.grid.user.bucket.pending',
+ 'Grid Config: user.bucket.pending',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.grid.circ.patron.staff_messages', 'gui', 'object',
+ oils_i18n_gettext(
+ 'eg.grid.circ.patron.staff_messages',
+ 'Grid Config: circ.patron.staff_messages',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.grid.circ.patron.archived_messages', 'gui', 'object',
+ oils_i18n_gettext(
+ 'eg.grid.circ.patron.archived_messages',
+ 'Grid Config: circ.patron.archived_messages',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.grid.circ.patron.bills', 'gui', 'object',
+ oils_i18n_gettext(
+ 'eg.grid.circ.patron.bills',
+ 'Grid Config: circ.patron.bills',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.grid.circ.patron.checkout', 'gui', 'object',
+ oils_i18n_gettext(
+ 'eg.grid.circ.patron.checkout',
+ 'Grid Config: circ.patron.checkout',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.grid.serials.mfhd_grid', 'gui', 'object',
+ oils_i18n_gettext(
+ 'eg.grid.serials.mfhd_grid',
+ 'Grid Config: serials.mfhd_grid',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.grid.serials.view_item_grid', 'gui', 'object',
+ oils_i18n_gettext(
+ 'eg.grid.serials.view_item_grid',
+ 'Grid Config: serials.view_item_grid',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.grid.serials.dist_stream_grid', 'gui', 'object',
+ oils_i18n_gettext(
+ 'eg.grid.serials.dist_stream_grid',
+ 'Grid Config: serials.dist_stream_grid',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.grid.circ.patron.search', 'gui', 'object',
+ oils_i18n_gettext(
+ 'eg.grid.circ.patron.search',
+ 'Grid Config: circ.patron.search',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.cat.record.summary.collapse', 'gui', 'bool',
+ oils_i18n_gettext(
+ 'eg.cat.record.summary.collapse',
+ 'Collapse Bib Record Summary',
+ 'cwst', 'label'
+ )
+), (
+ 'cat.marcedit.flateditor', 'gui', 'bool',
+ oils_i18n_gettext(
+ 'cat.marcedit.flateditor',
+ 'Use Flat MARC Editor',
+ 'cwst', 'label'
+ )
+), (
+ 'cat.marcedit.stack_subfields', 'gui', 'bool',
+ oils_i18n_gettext(
+ 'cat.marcedit.stack_subfields',
+ 'MARC Editor Stack Subfields',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.offline.print_receipt', 'gui', 'bool',
+ oils_i18n_gettext(
+ 'eg.offline.print_receipt',
+ 'Offline Print Receipt',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.offline.strict_barcode', 'gui', 'bool',
+ oils_i18n_gettext(
+ 'eg.offline.strict_barcode',
+ 'Offline Use Strict Barcode',
+ 'cwst', 'label'
+ )
+), (
+ 'cat.default_bib_marc_template', 'gui', 'string',
+ oils_i18n_gettext(
+ 'cat.default_bib_marc_template',
+ 'Default MARC Template',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.audio.disable', 'gui', 'bool',
+ oils_i18n_gettext(
+ 'eg.audio.disable',
+ 'Disable Staff Client Notification Audio',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.search.adv_pane', 'gui', 'string',
+ oils_i18n_gettext(
+ 'eg.search.adv_pane',
+ 'Catalog Advanced Search Default Pane',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.print.template_context.bills_current', 'gui', 'string',
+ oils_i18n_gettext(
+ 'eg.print.template_context.bills_current',
+ 'Print Template Context: bills_current',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.print.template.bills_current', 'gui', 'string',
+ oils_i18n_gettext(
+ 'eg.print.template.bills_current',
+ 'Print Template: bills_current',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.print.template_context.bills_historical', 'gui', 'string',
+ oils_i18n_gettext(
+ 'eg.print.template_context.bills_historical',
+ 'Print Template Context: bills_historical',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.print.template.bills_historical', 'gui', 'string',
+ oils_i18n_gettext(
+ 'eg.print.template.bills_historical',
+ 'Print Template: bills_historical',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.print.template_context.bill_payment', 'gui', 'string',
+ oils_i18n_gettext(
+ 'eg.print.template_context.bill_payment',
+ 'Print Template Context: bill_payment',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.print.template.bill_payment', 'gui', 'string',
+ oils_i18n_gettext(
+ 'eg.print.template.bill_payment',
+ 'Print Template: bill_payment',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.print.template_context.checkin', 'gui', 'string',
+ oils_i18n_gettext(
+ 'eg.print.template_context.checkin',
+ 'Print Template Context: checkin',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.print.template.checkin', 'gui', 'string',
+ oils_i18n_gettext(
+ 'eg.print.template.checkin',
+ 'Print Template: checkin',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.print.template_context.checkout', 'gui', 'string',
+ oils_i18n_gettext(
+ 'eg.print.template_context.checkout',
+ 'Print Template Context: checkout',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.print.template.checkout', 'gui', 'string',
+ oils_i18n_gettext(
+ 'eg.print.template.checkout',
+ 'Print Template: checkout',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.print.template_context.hold_transit_slip', 'gui', 'string',
+ oils_i18n_gettext(
+ 'eg.print.template_context.hold_transit_slip',
+ 'Print Template Context: hold_transit_slip',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.print.template.hold_transit_slip', 'gui', 'string',
+ oils_i18n_gettext(
+ 'eg.print.template.hold_transit_slip',
+ 'Print Template: hold_transit_slip',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.print.template_context.hold_shelf_slip', 'gui', 'string',
+ oils_i18n_gettext(
+ 'eg.print.template_context.hold_shelf_slip',
+ 'Print Template Context: hold_shelf_slip',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.print.template.hold_shelf_slip', 'gui', 'string',
+ oils_i18n_gettext(
+ 'eg.print.template.hold_shelf_slip',
+ 'Print Template: hold_shelf_slip',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.print.template_context.holds_for_bib', 'gui', 'string',
+ oils_i18n_gettext(
+ 'eg.print.template_context.holds_for_bib',
+ 'Print Template Context: holds_for_bib',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.print.template.holds_for_bib', 'gui', 'string',
+ oils_i18n_gettext(
+ 'eg.print.template.holds_for_bib',
+ 'Print Template: holds_for_bib',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.print.template_context.holds_for_patron', 'gui', 'string',
+ oils_i18n_gettext(
+ 'eg.print.template_context.holds_for_patron',
+ 'Print Template Context: holds_for_patron',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.print.template.holds_for_patron', 'gui', 'string',
+ oils_i18n_gettext(
+ 'eg.print.template.holds_for_patron',
+ 'Print Template: holds_for_patron',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.print.template_context.hold_pull_list', 'gui', 'string',
+ oils_i18n_gettext(
+ 'eg.print.template_context.hold_pull_list',
+ 'Print Template Context: hold_pull_list',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.print.template.hold_pull_list', 'gui', 'string',
+ oils_i18n_gettext(
+ 'eg.print.template.hold_pull_list',
+ 'Print Template: hold_pull_list',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.print.template_context.hold_shelf_list', 'gui', 'string',
+ oils_i18n_gettext(
+ 'eg.print.template_context.hold_shelf_list',
+ 'Print Template Context: hold_shelf_list',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.print.template.hold_shelf_list', 'gui', 'string',
+ oils_i18n_gettext(
+ 'eg.print.template.hold_shelf_list',
+ 'Print Template: hold_shelf_list',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.print.template_context.in_house_use_list', 'gui', 'string',
+ oils_i18n_gettext(
+ 'eg.print.template_context.in_house_use_list',
+ 'Print Template Context: in_house_use_list',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.print.template.in_house_use_list', 'gui', 'string',
+ oils_i18n_gettext(
+ 'eg.print.template.in_house_use_list',
+ 'Print Template: in_house_use_list',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.print.template_context.item_status', 'gui', 'string',
+ oils_i18n_gettext(
+ 'eg.print.template_context.item_status',
+ 'Print Template Context: item_status',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.print.template.item_status', 'gui', 'string',
+ oils_i18n_gettext(
+ 'eg.print.template.item_status',
+ 'Print Template: item_status',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.print.template_context.items_out', 'gui', 'string',
+ oils_i18n_gettext(
+ 'eg.print.template_context.items_out',
+ 'Print Template Context: items_out',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.print.template.items_out', 'gui', 'string',
+ oils_i18n_gettext(
+ 'eg.print.template.items_out',
+ 'Print Template: items_out',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.print.template_context.patron_address', 'gui', 'string',
+ oils_i18n_gettext(
+ 'eg.print.template_context.patron_address',
+ 'Print Template Context: patron_address',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.print.template.patron_address', 'gui', 'string',
+ oils_i18n_gettext(
+ 'eg.print.template.patron_address',
+ 'Print Template: patron_address',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.print.template_context.patron_data', 'gui', 'string',
+ oils_i18n_gettext(
+ 'eg.print.template_context.patron_data',
+ 'Print Template Context: patron_data',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.print.template.patron_data', 'gui', 'string',
+ oils_i18n_gettext(
+ 'eg.print.template.patron_data',
+ 'Print Template: patron_data',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.print.template_context.patron_note', 'gui', 'string',
+ oils_i18n_gettext(
+ 'eg.print.template_context.patron_note',
+ 'Print Template Context: patron_note',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.print.template.patron_note', 'gui', 'string',
+ oils_i18n_gettext(
+ 'eg.print.template.patron_note',
+ 'Print Template: patron_note',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.print.template_context.renew', 'gui', 'string',
+ oils_i18n_gettext(
+ 'eg.print.template_context.renew',
+ 'Print Template Context: renew',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.print.template.renew', 'gui', 'string',
+ oils_i18n_gettext(
+ 'eg.print.template.renew',
+ 'Print Template: renew',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.print.template_context.transit_list', 'gui', 'string',
+ oils_i18n_gettext(
+ 'eg.print.template_context.transit_list',
+ 'Print Template Context: transit_list',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.print.template.transit_list', 'gui', 'string',
+ oils_i18n_gettext(
+ 'eg.print.template.transit_list',
+ 'Print Template: transit_list',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.print.template_context.transit_slip', 'gui', 'string',
+ oils_i18n_gettext(
+ 'eg.print.template_context.transit_slip',
+ 'Print Template Context: transit_slip',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.print.template.transit_slip', 'gui', 'string',
+ oils_i18n_gettext(
+ 'eg.print.template.transit_slip',
+ 'Print Template: transit_slip',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.print.template_context.offline_checkout', 'gui', 'string',
+ oils_i18n_gettext(
+ 'eg.print.template_context.offline_checkout',
+ 'Print Template Context: offline_checkout',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.print.template.offline_checkout', 'gui', 'string',
+ oils_i18n_gettext(
+ 'eg.print.template.offline_checkout',
+ 'Print Template: offline_checkout',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.print.template_context.offline_renew', 'gui', 'string',
+ oils_i18n_gettext(
+ 'eg.print.template_context.offline_renew',
+ 'Print Template Context: offline_renew',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.print.template.offline_renew', 'gui', 'string',
+ oils_i18n_gettext(
+ 'eg.print.template.offline_renew',
+ 'Print Template: offline_renew',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.print.template_context.offline_checkin', 'gui', 'string',
+ oils_i18n_gettext(
+ 'eg.print.template_context.offline_checkin',
+ 'Print Template Context: offline_checkin',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.print.template.offline_checkin', 'gui', 'string',
+ oils_i18n_gettext(
+ 'eg.print.template.offline_checkin',
+ 'Print Template: offline_checkin',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.print.template_context.offline_in_house_use', 'gui', 'string',
+ oils_i18n_gettext(
+ 'eg.print.template_context.offline_in_house_use',
+ 'Print Template Context: offline_in_house_use',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.print.template.offline_in_house_use', 'gui', 'string',
+ oils_i18n_gettext(
+ 'eg.print.template.offline_in_house_use',
+ 'Print Template: offline_in_house_use',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.serials.stream_names', 'gui', 'array',
+ oils_i18n_gettext(
+ 'eg.serials.stream_names',
+ 'Serials Local Stream Names',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.serials.items.do_print_routing_lists', 'gui', 'bool',
+ oils_i18n_gettext(
+ 'eg.serials.items.do_print_routing_lists',
+ 'Serials Print Routing Lists',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.serials.items.receive_and_barcode', 'gui', 'bool',
+ oils_i18n_gettext(
+ 'eg.serials.items.receive_and_barcode',
+ 'Serials Barcode On Receive',
+ 'cwst', 'label'
+ )
+);
+
+
+-- More values with fm_class'es
+INSERT INTO config.workstation_setting_type (name, grp, datatype, fm_class, label)
+VALUES (
+ 'eg.search.search_lib', 'gui', 'link', 'aou',
+ oils_i18n_gettext(
+ 'eg.search.search_lib',
+ 'Staff Catalog Default Search Library',
+ 'cwst', 'label'
+ )
+), (
+ 'eg.search.pref_lib', 'gui', 'link', 'aou',
+ oils_i18n_gettext(
+ 'eg.search.pref_lib',
+ 'Staff Catalog Preferred Library',
+ 'cwst', 'label'
+ )
+);
+
+
+COMMIT;
+
+
s.PRINT_TEMPLATES_FAIL_IMPORT = "[% l('Failed to import any print template(s)') %]";
s.HATCH_SETTINGS_MIGRATION_SUCCESS = "[% l('Settings successfully migrated') %]";
s.HATCH_SETTINGS_MIGRATION_FAILURE = "[% l('Settings migration failed') %]";
+ s.HATCH_SERVER_SETTINGS_MIGRATION_CONFIRM =
+ "[% l('This will delete the local version all settings configured to live on the server. Continue?') %]";
}]);
</script>
[% END %]
egCore.hatch.removeLocalItem(key);
refreshKeys();
} else {
- egCore.hatch.removeItem(key)
+ // Honor requests to remove items from Hatch even
+ // when Hatch is configured for data storage.
+ egCore.hatch.removeRemoteItem(key)
.then(function() { refreshKeys() });
}
},
$scope.grid_persist_key = $scope.is_capture ?
'circ.checkin.capture' : 'circ.checkin.checkin';
+ // TODO: add this to the setting batch lookup below
egCore.hatch.getItem('circ.checkin.strict_barcode')
.then(function(sb){ $scope.strict_barcode = sb });
}
// set modifiers from stored preferences
- angular.forEach(modifiers, function(mod) {
- egCore.hatch.getItem('eg.circ.checkin.' + mod)
- .then(function(val) { if (val) $scope.modifiers[mod] = true });
+ var snames = modifiers.map(function(m) {return 'eg.circ.checkin.' + m;});
+ egCore.hatch.getItemBatch(snames).then(function(settings) {
+ angular.forEach(settings, function(val, key) {
+ if (val === true) {
+ var parts = key.split('.')
+ var mod = parts.pop();
+ $scope.modifiers[mod] = true;
+ }
+ })
});
// set / unset a checkin modifier
angular.module('egCoreMod')
.factory('egHatch',
- ['$q','$window','$timeout','$interpolate','$cookies',
- function($q , $window , $timeout , $interpolate , $cookies) {
+ ['$q','$window','$timeout','$interpolate','$cookies','egNet','$injector',
+ function($q , $window , $timeout , $interpolate , $cookies , egNet , $injector ) {
var service = {};
service.msgId = 1;
service.messages = {};
service.hatchAvailable = false;
+ service.auth = null; // ref to egAuth loaded on-demand to avoid circular ref.
+ service.disableServerSettings = false;
// key/value cache -- avoid unnecessary Hatch extension requests.
// Only affects *RemoteItem calls.
service.keyCache = {};
+ // Keep a local copy of all retrieved setting summaries, which indicate
+ // which setting types exist for each setting.
+ service.serverSettingSummaries = {};
+
/**
* List string prefixes for On-Call storage keys. On-Call keys
* are those that can be set/get/remove'd from localStorage when
* at a time and each maintains its own data separately.
*/
service.onCallPrefixes = ['eg.workstation'];
-
+
// Returns true if the key can be set/get in localStorage even when
// Hatch is not available.
service.keyIsOnCall = function(key) {
return oncall;
}
+ /**
+ * Settings with these prefixes will always live in the browser.
+ */
+ service.browserOnlyPrefixes = [
+ 'eg.workstation',
+ 'eg.hatch',
+ 'eg.cache',
+ 'current_tag_table_marc21_biblio',
+ 'FFPos',
+ 'FFValue'
+ ];
+
+ service.keyStoredInBrowser = function(key) {
+
+ if (service.disableServerSettings) {
+ // When server-side storage is disabled, treat every
+ // setting like it's stored locally.
+ return true;
+ }
+
+ var browserOnly = false;
+ service.browserOnlyPrefixes.forEach(function(pfx) {
+ if (key.match(new RegExp('^' + pfx)))
+ browserOnly = true;
+ });
+
+ return browserOnly;
+ }
+
// write a message to the Hatch port
service.sendToHatch = function(msg) {
var msg2 = {};
);
}
+ // TODO: once Hatch is printing-only, should probably store
+ // this preference on the server.
service.usePrinting = function() {
return service.getLocalItem('eg.hatch.enable.printing');
}
// get the value for a stored item
service.getItem = function(key) {
- if (!service.useSettings())
- return $q.when(service.getLocalItem(key));
+ if (!service.keyStoredInBrowser(key)) {
+ return service.getServerItem(key);
+ }
+
+ var deferred = $q.defer();
- if (service.hatchAvailable)
- return service.getRemoteItem(key);
+ service.getBrowserItem(key).then(
+ function(val) { deferred.resolve(val); },
- if (service.keyIsOnCall(key)) {
- console.warn("Unable to getItem from Hatch: " + key +
- ". Retrieving item from local storage instead");
+ function() { // Hatch error
+ if (service.keyIsOnCall(key)) {
+ console.warn("Unable to getItem from Hatch: " + key +
+ ". Retrieving item from local storage instead");
+ deferred.resolve(service.getLocalItem(key));
+ }
+
+ deferred.reject("Unable to getItem from Hatch: " + key);
+ }
+ );
+
+ return deferred.promise;
+ }
+
+ // Collect values in batch.
+ // For server-stored values espeically, this is more efficient
+ // than a series of one-off calls.
+ service.getItemBatch = function(keys) {
+ var browserKeys = [];
+ var serverKeys = [];
+
+ // To take full advantage of the getServerItemBatch call,
+ // we have to know in advance which keys to send to the server
+ // vs those to handle in the browser.
+ keys.forEach(function(key) {
+ if (service.keyStoredInBrowser(key)) {
+ browserKeys.push(key);
+ } else {
+ serverKeys.push(key);
+ }
+ });
+
+ var settings = {};
+
+ var serverPromise = serverKeys.length === 0 ? $q.when() :
+ service.getServerItemBatch(serverKeys).then(function(values) {
+ angular.forEach(values, function(val, key) {
+ settings[key] = val;
+ });
+ });
+
+ var browserPromises = [];
+ browserKeys.forEach(function(key) {
+ browserPromises.push(
+ service.getBrowserItem(key).then(function(val) {
+ settings[key] = val;
+ })
+ );
+ });
+
+ return $q.all(browserPromises.concat(serverPromise))
+ .then(function() {return settings});
+ }
+ service.getBrowserItem = function(key) {
+ if (service.useSettings()) {
+ if (service.hatchAvailable) {
+ return service.getRemoteItem(key);
+ }
+ } else {
return $q.when(service.getLocalItem(key));
}
-
- console.error("Unable to getItem from Hatch: " + key);
return $q.reject();
}
service.getLocalItem = function(key) {
var val = $window.localStorage.getItem(key);
- if (val == null) return;
+ if (val === null || val === undefined) return;
try {
return JSON.parse(val);
} catch(E) {
* tmp values are removed during logout or browser close.
*/
service.setItem = function(key, value) {
- if (!service.useSettings())
- return $q.when(service.setLocalItem(key, value));
- if (service.hatchAvailable)
- return service.setRemoteItem(key, value);
+ if (!service.keyStoredInBrowser(key)) {
+ return service.setServerItem(key, value);
+ }
- if (service.keyIsOnCall(key)) {
- console.warn("Unable to setItem in Hatch: " +
- key + ". Setting in local storage instead");
+ var deferred = $q.defer();
+ service.setBrowserItem(key, value).then(
+ function(val) {deferred.resolve(val);},
+
+ function() { // Hatch error
+
+ if (service.keyIsOnCall(key)) {
+ console.warn("Unable to setItem in Hatch: " +
+ key + ". Setting in local storage instead");
+
+ deferred.resolve(service.setLocalItem(key, value));
+ }
+ deferred.reject("Unable to setItem in Hatch: " + key);
+ }
+ );
+ }
+ service.setBrowserItem = function(key, value) {
+ if (service.useSettings()) {
+ if (service.hatchAvailable) {
+ return service.setRemoteItem(key, value);
+ } else {
+ return $q.reject('Unable to get item from hatch');
+ }
+ } else {
return $q.when(service.setLocalItem(key, value));
}
+ }
- console.error("Unable to setItem in Hatch: " + key);
- return $q.reject();
+ service.setServerItem = function(key, value) {
+ if (!service.auth) service.auth = $injector.get('egAuth');
+ if (!service.auth.token()) return $q.when();
+
+ // If we have already attempted to retrieve a value for this
+ // setting, then we can tell up front whether applying a value
+ // at the server will be an option. If not, store locally.
+ var summary = service.serverSettingSummaries[key];
+ if (summary && !summary.has_staff_setting) {
+
+ if (summary.has_org_setting === 't') {
+ // When no user/ws setting types exist but an org unit
+ // setting type does, it means the value cannot be
+ // applied by an individual user. Nothing left to do.
+ return $q.when();
+ }
+
+ // No setting types of any flavor exist.
+ // Fall back to local storage.
+
+ if (value === null) {
+ // a null value means clear the server setting.
+ return service.removeBrowserItem(key);
+ } else {
+ console.warn('No server setting type exists for ' + key);
+ return service.setBrowserItem(key, value);
+ }
+ }
+
+ var settings = {};
+ settings[key] = value;
+
+ return egNet.request(
+ 'open-ils.actor',
+ 'open-ils.actor.settings.apply.user_or_ws',
+ service.auth.token(), settings
+ ).then(function(appliedCount) {
+
+ if (appliedCount == 0) {
+ console.warn('No server setting type exists for ' + key);
+ // We were unable to store the setting on the server,
+ // presumably becuase no server-side setting type exists.
+ // Add to local storage instead.
+ service.setLocalItem(key, value);
+ }
+
+ service.keyCache[key] = value;
+ return appliedCount;
+ });
}
+ service.getServerItem = function(key) {
+ 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);
+
+ return egNet.request(
+ 'open-ils.actor',
+ 'open-ils.actor.settings.retrieve.atomic',
+ [key], service.auth.token()
+ ).then(function(settings) {
+ return service.handleServerItemResponse(settings[0]);
+ });
+ }
+
+ service.handleServerItemResponse = function(summary) {
+ var key = summary.name;
+ var val = summary.value;
+
+ // For our purposes, we only care if a setting can be stored
+ // as an org setting or a user-or-workstation setting.
+ summary.has_staff_setting = (
+ summary.has_user_setting === 't' ||
+ summary.has_workstation_setting === 't'
+ );
+
+ summary.value = null; // avoid duplicate value caches
+ service.serverSettingSummaries[key] = summary;
+
+ if (val !== null) {
+ // We have a server setting. Nothing left to do.
+ return $q.when(service.keyCache[key] = val);
+ }
+
+ if (!summary.has_staff_setting) {
+
+ if (summary.has_org_setting === 't') {
+ // An org unit setting type exists but no value is applied
+ // that this workstation has access to. The existence of
+ // an org unit setting type and no user/ws setting type
+ // means applying a value locally is not allowed.
+ return $q.when(service.keyCache[key] = undefined);
+ }
+
+ console.warn('No server setting type exists for '
+ + key + ', using local value.');
+
+ return service.getBrowserItem(key);
+ }
+
+ // A user/ws setting type exists, but no server value exists.
+ // Migrate the local setting to the server.
+
+ var deferred = $q.defer();
+ service.getBrowserItem(key).then(function(browserVal) {
+
+ if (browserVal === null || browserVal === undefined) {
+ // No local value to migrate.
+ return deferred.resolve(service.keyCache[key] = undefined);
+ }
+
+ // Migrate the local value to the server.
+
+ service.setServerItem(key, browserVal).then(
+ function(appliedCount) {
+ if (appliedCount == 1) {
+ console.info('setting ' + key + ' successfully ' +
+ 'migrated to a server setting');
+ service.removeBrowserItem(key); // fire & forget
+ } else {
+ console.error('error migrating setting to server,'
+ + ' falling back to local value');
+ }
+ deferred.resolve(service.keyCache[key] = browserVal);
+ }
+ );
+ });
+
+ return deferred.promise;
+ }
+
+ service.getServerItemBatch = function(keys) {
+ // no cache checking for now. assumes batch mode is only
+ // called once on page load. maybe add cache checking later.
+ if (!service.auth) service.auth = $injector.get('egAuth');
+ if (!service.auth.token()) return $q.when({});
+
+ var foundValues = {};
+ return egNet.request(
+ 'open-ils.actor',
+ 'open-ils.actor.settings.retrieve',
+ keys, service.auth.token()
+ ).then(
+ function() { return foundValues; },
+ function() {},
+ function(setting) {
+ var val = setting.value;
+ // The server returns null for undefined settings.
+ // Treat as undefined locally for backwards compat.
+ service.keyCache[setting.name] =
+ foundValues[setting.name] =
+ (val === null) ? undefined : val;
+ }
+ );
+ }
+
+
// set the value for a stored or new item
service.setRemoteItem = function(key, value) {
service.keyCache[key] = value;
// If the value is raw, pass it as 'value'. If it was
// externally JSONified, pass it via jsonified.
service.setLocalItem = function(key, value, jsonified) {
- if (jsonified === undefined )
+ if (jsonified === undefined ) {
jsonified = JSON.stringify(value);
+ } else if (value === undefined) {
+ return;
+ }
$window.localStorage.setItem(key, jsonified);
}
// remove a stored item
service.removeItem = function(key) {
- if (!service.useSettings())
- return $q.when(service.removeLocalItem(key));
- if (service.hatchAvailable)
- return service.removeRemoteItem(key);
+ if (!service.keyStoredInBrowser(key)) {
+ return service.removeServerItem(key);
+ }
- if (service.keyIsOnCall(key)) {
- console.warn("Unable to removeItem from Hatch: " + key +
- ". Removing item from local storage instead");
+ var deferred = $q.defer();
+ service.removeBrowserItem(key).then(
+ function(response) {deferred.resolve(response);},
+ function() { // Hatch error
+
+ if (service.keyIsOnCall(key)) {
+ console.warn("Unable to removeItem from Hatch: " + key +
+ ". Removing item from local storage instead");
+ deferred.resolve(service.removeLocalItem(key));
+ }
+
+ deferred.reject("Unable to removeItem from Hatch: " + key);
+ }
+ );
+
+ return deferred.promise;
+ }
+
+ service.removeBrowserItem = function(key) {
+ if (service.useSettings()) {
+ if (service.hatchAvailable) {
+ return service.removeRemoteItem(key);
+ } else {
+ return $q.reject('error talking to Hatch');
+ }
+ } else {
return $q.when(service.removeLocalItem(key));
}
+ }
- console.error("Unable to removeItem from Hatch: " + key);
- return $q.reject();
+ service.removeServerItem = function(key) {
+ return service.setServerItem(key, null);
}
service.removeRemoteItem = function(key) {
// if set, prefix limits the return set to keys starting with 'prefix'
service.getKeys = function(prefix) {
- if (service.useSettings())
- return service.getRemoteKeys(prefix);
- return $q.when(service.getLocalKeys(prefix));
+ var promise = service.getServerKeys(prefix);
+ return service.getBrowserKeys(prefix).then(function(browserKeys) {
+ return promise.then(function(serverKeys) {
+ return serverKeys.concat(browserKeys);
+ });
+ });
}
service.getRemoteKeys = function(prefix) {
});
}
+ service.getBrowserKeys = function(prefix) {
+ if (service.useSettings())
+ return service.getRemoteKeys(prefix);
+ return $q.when(service.getLocalKeys(prefix));
+ }
+
+ service.getServerKeys = function(prefix) {
+ if (!service.auth) service.auth = $injector.get('egAuth');
+ if (!service.auth.token()) return $q.when({});
+ return egNet.request(
+ 'open-ils.actor',
+ 'open-ils.actor.settings.staff.applied.names.authoritative.atomic',
+ service.auth.token(), prefix
+ );
+ }
+
service.getLocalKeys = function(prefix) {
var keys = [];
var idx = 0;