LP1904036 offline data retrieval
authorBill Erickson <berickxx@gmail.com>
Mon, 26 Apr 2021 16:25:21 +0000 (12:25 -0400)
committerGalen Charlton <gmc@equinoxOLI.org>
Fri, 28 Oct 2022 00:13:33 +0000 (20:13 -0400)
With this commit, offline data is fetched during every login.

Signed-off-by: Bill Erickson <berickxx@gmail.com>
Signed-off-by: Jane Sandberg <js7389@princeton.edu>
Signed-off-by: Galen Charlton <gmc@equinoxOLI.org>
Open-ILS/src/eg2/src/app/staff/common.module.ts
Open-ILS/src/eg2/src/app/staff/login.component.ts
Open-ILS/src/eg2/src/app/staff/share/offline.service.ts [new file with mode: 0644]
Open-ILS/src/perlmods/lib/OpenILS/Application/Circ.pm
Open-ILS/web/js/ui/default/staff/offline.js

index 280f92a..1381be0 100644 (file)
@@ -21,6 +21,7 @@ import {PatronBarcodeValidatorDirective} from '@eg/share/validators/patron_barco
 import {BroadcastService} from '@eg/share/util/broadcast.service';
 import {CourseService} from './share/course.service';
 import {FileExportService} from '@eg/share/util/file-export.service';
+import {OfflineService} from '@eg/staff/share/offline.service';
 
 /**
  * Imports the EG common modules and adds modules common to all staff UI's.
@@ -78,7 +79,8 @@ export class StaffCommonModule {
                 AudioService,
                 BroadcastService,
                 CourseService,
-                FileExportService
+                FileExportService,
+                OfflineService
             ]
         };
     }
index f78991f..7846285 100644 (file)
@@ -4,6 +4,7 @@ import {Router, ActivatedRoute} from '@angular/router';
 import {AuthService, AuthWsState} from '@eg/core/auth.service';
 import {StoreService} from '@eg/core/store.service';
 import {OrgService} from '@eg/core/org.service';
+import {OfflineService} from '@eg/staff/share/offline.service';
 
 // Direct users to the AngJS splash page when no routeTo is provided.
 const SPLASH_PAGE_PATH = '/eg/staff/splash';
@@ -31,7 +32,8 @@ export class StaffLoginComponent implements OnInit {
       private renderer: Renderer2,
       private auth: AuthService,
       private org: OrgService,
-      private store: StoreService
+      private store: StoreService,
+      private offline: OfflineService
     ) {}
 
     ngOnInit() {
@@ -98,9 +100,10 @@ export class StaffLoginComponent implements OnInit {
 
                 } else {
 
-                    // Initial login clears cached org unit setting values
-                    // and user/workstation setting values
-                    this.org.clearCachedSettings().then(_ => {
+                    this.offline.fetchOfflineData()
+                    // Initial login clears cached org unit settings.
+                    .then(_ => this.org.clearCachedSettings())
+                    .then(_ => {
 
                         // Force reload of the app after a successful login.
                         // This allows the route resolver to re-run with a
diff --git a/Open-ILS/src/eg2/src/app/staff/share/offline.service.ts b/Open-ILS/src/eg2/src/app/staff/share/offline.service.ts
new file mode 100644 (file)
index 0000000..bc2a1d3
--- /dev/null
@@ -0,0 +1,108 @@
+import {Observable} from 'rxjs';
+import {from} from 'rxjs';
+import {tap, concatMap} from 'rxjs/operators';
+import {Injectable} from '@angular/core';
+import {AuthService} from '@eg/core/auth.service';
+import {EventService} from '@eg/core/event.service';
+import {IdlObject, IdlService} from '@eg/core/idl.service';
+import {NetService} from '@eg/core/net.service';
+import {OrgService} from '@eg/core/org.service';
+import {PcrudService} from '@eg/core/pcrud.service';
+import {DbStoreService} from '@eg/core/db-store.service';
+
+/** Service for storing and fetching data related to offline services/interfaces */
+
+@Injectable()
+export class OfflineService {
+
+    isOffline = false;
+
+    constructor(
+        private auth: AuthService,
+        private evt: EventService,
+        private idl: IdlService,
+        private net: NetService,
+        private org: OrgService,
+        private pcrud: PcrudService,
+        private db: DbStoreService
+    ) {}
+
+    clearOfflineCache(): Promise<any> {
+        return this.db.request(
+            {schema: 'cache', table: 'Object', action: 'deleteAll'})
+
+        .then(_ => this.db.request(
+            {schema: 'cache', table: 'StatCat', action: 'deleteAll'})
+        );
+    }
+
+    fetchOfflineData(): Promise<any> {
+
+        // TODO check cache date first or just always grab it?
+        // TODO add setting that let's users opt-out of loading offline data.
+
+        return this.clearOfflineCache()
+
+        .then(_ => {
+
+            // Start with the org unit list which is already loaded.
+            this.addListToCache('aou', this.org.list());
+
+            return this.net.request(
+                'open-ils.circ',
+                'open-ils.circ.offline.data.retrieve',
+                this.auth.token()
+            )
+            .pipe(concatMap(data => {
+                if (data.idl_class === 'actsc') {
+                    return from(this.addStatCatsToCache(data.data));
+                } else {
+                    return from(this.addListToCache(data.idl_class, data.data));
+                }
+            }))
+            .toPromise();
+        });
+    }
+
+    addListToCache(idlClass: string, list: IdlObject[]): Promise<any> {
+
+        const pkey = this.idl.classes[idlClass].pkey;
+        const rows = list.map(item => {
+            return {
+                type: idlClass,
+                id: '' + item[pkey](),
+                object: this.idl.toHash(item)
+            };
+        });
+
+        return this.db.request({
+            schema: 'cache',
+            table: 'Object',
+            action: 'insert',
+            rows: rows
+        }).then(resp => {
+            return this.db.request({
+                schema: 'cache',
+                table: 'CacheDate',
+                action: 'insertOrReplace',
+                rows: [{type: idlClass, cachedate: new Date()}]
+            });
+        });
+    }
+
+    addStatCatsToCache(statcats: IdlObject[]): Promise<any> {
+        if (!statcats || statcats.length === 0) {
+            return Promise.resolve();
+        }
+
+        var rows = statcats.map(cat => {
+            return {id: cat.id(), value: this.idl.toHash(cat)}});
+
+        return this.db.request({
+            schema: 'cache',
+            table: 'StatCat',
+            action: 'insert',
+            rows: rows
+        });
+    }
+}
index c14cc4f..b8aba47 100644 (file)
@@ -2198,12 +2198,8 @@ sub get_offline_data {
     $client->respond({idl_class => 'fdoc', 
         data => $e->retrieve_all_config_idl_field_doc});
 
-    my $perm_groups = $e->search_permission_grp_tree([
-        {parent => undef},
-        {flesh => 99, flesh_fields => {pgt => ['children']}}
-    ]);
-
-    $client->respond({idl_class => 'pgt', data => $perm_groups});
+    $client->respond({idl_class => 'pgt', 
+        data => $e->retrieve_all_permission_grp_tree});
     
     my $stat_cats = $U->simplereq(
         'open-ils.circ', 
@@ -2233,7 +2229,7 @@ sub get_offline_data {
         }]
     });
 
-    $client->respond($settings);
+    $client->respond({idl_class => 'cust', data => $settings});
 
     return undef;
 }
index 099c1e1..f31cc63 100644 (file)
@@ -983,8 +983,8 @@ function($routeProvider , $locationProvider , $compileProvider) {
                     service.opt_in_setting_types[stype.name()] = stype;
                 }
                 if (stype.reg_default() != undefined) {
-                    service.user_settings[setting.name()] = 
-                        setting.reg_default();
+                    service.user_settings[stype.name()] = 
+                        stype.reg_default();
                 }
             });
             return $q.when();