2 * Set and get server-stored settings.
4 import {Injectable} from '@angular/core';
5 import {tap} from 'rxjs/operators';
6 import {AuthService} from './auth.service';
7 import {NetService} from './net.service';
8 import {DbStoreService} from './db-store.service';
10 // Settings summary objects returned by the API
11 interface ServerSettingSummary {
14 has_org_setting: boolean;
15 has_user_setting: boolean;
16 has_workstation_setting: boolean;
19 @Injectable({providedIn: 'root'})
20 export class ServerStoreService {
22 cache: {[key: string]: any};
25 private db: DbStoreService,
26 private net: NetService,
27 private auth: AuthService) {
31 setItem(key: string, value: any): Promise<any> {
33 if (!this.auth.token()) {
34 return Promise.reject('Auth required to apply settings');
37 const setting: any = {};
40 return this.net.request(
42 'open-ils.actor.settings.apply.user_or_ws',
43 this.auth.token(), setting)
45 .toPromise().then(appliedCount => {
47 if (Number(appliedCount) <= 0) { // no value applied
48 return Promise.reject(
49 `No user or workstation setting type exists for: "${key}".\n` +
50 'Create a ws/user setting type or use setLocalItem() to ' +
51 'store the value locally.'
55 return this.addSettingsToDb(setting);
59 // Returns a single setting value
60 getItem(key: string): Promise<any> {
61 return this.getItemBatch([key]).then(
62 settings => settings[key]
66 // Sync call for items known to be cached locally.
67 getItemCached(key: string): any {
68 return this.cache[key];
71 // Sync batch call for items known to be cached locally
72 getItemBatchCached(keys: string[]): {[key: string]: any} {
73 const values: any = {};
75 if (key in this.cache) {
76 values[key] = this.cache[key];
82 // Returns a set of key/value pairs for the requested settings
83 getItemBatch(keys: string[]): Promise<{[key: string]: any}> {
87 if (key in this.cache) {
88 values[key] = this.cache[key];
92 if (keys.length === Object.keys(values).length) {
93 // All values are cached already
94 return Promise.resolve(values);
97 if (!this.auth.token()) {
98 // Authtokens require for fetching server settings, but
99 // calls to retrieve settings could potentially occur
100 // before auth completes -- Ideally not, but just to be safe.
101 return Promise.resolve({});
104 // IndexedDB call required.
107 keys.forEach(key => {
108 if (!Object.keys(values).includes(key)) {
113 return this.getSettingsFromDb(dbKeys) // Also appends to local cache.
114 .then(dbValues => values = Object.assign(values, dbValues))
117 const serverKeys = [];
118 keys.forEach(key => {
119 if (!Object.keys(values).includes(key)) {
120 serverKeys.push(key);
124 if (serverKeys.length === 0) { return values; }
126 return this.net.request(
128 'open-ils.actor.settings.retrieve',
129 serverKeys, this.auth.token()
131 ).pipe(tap((summary: ServerSettingSummary) => {
132 this.cache[summary.name] =
133 values[summary.name] = summary.value;
135 })).toPromise().then(__ => {
137 const dbSets: any = {};
138 serverKeys.forEach(sKey => dbSets[sKey] = values[sKey]);
140 return this.addSettingsToDb(dbSets);
146 removeItem(key: string): Promise<any> {
147 return this.setItem(key, null);
150 private addSettingsToDb(values: {[key: string]: any}): Promise<{[key: string]: any}> {
153 Object.keys(values).forEach(name => {
154 // Anything added to the db should also be cached locally.
155 this.cache[name] = values[name];
156 rows.push({name: name, value: JSON.stringify(values[name])});
159 if (rows.length === 0) { return Promise.resolve(values); }
161 return this.db.request({
164 action: 'insertOrReplace',
166 }).then(_ => values).catch(_ => values);
169 getSettingsFromDb(names: string[]): Promise<{[key: string]: any}> {
170 if (names.length === 0) { return Promise.resolve({}); }
172 const values: any = {};
174 return this.db.request({
177 action: 'selectWhereIn',
180 }).then(settings => {
182 // array of key => JSON-string objects
183 settings.forEach(setting => {
184 const value = JSON.parse(setting.value);
185 // propagate to local cache as well
186 values[setting.name] = this.cache[setting.name] = value;
190 }).catch(_ => values);