1 import {Injectable} from '@angular/core';
2 import {Observable} from 'rxjs/Observable';
3 import {tap} from 'rxjs/operators/tap';
4 import {map} from 'rxjs/operators/map';
5 import {HttpClient} from '@angular/common/http';
6 import {saveAs} from 'file-saver/FileSaver';
7 import {IdlService, IdlObject} from '@eg/core/idl.service';
8 import {OrgService} from '@eg/core/org.service';
9 import {NetService} from '@eg/core/net.service';
10 import {AuthService} from '@eg/core/auth.service';
11 import {PcrudService} from '@eg/core/pcrud.service';
12 import {PermService} from '@eg/core/perm.service';
13 import {EventService} from '@eg/core/event.service';
14 import {ProgressDialogComponent} from '@eg/share/dialog/progress.component';
16 export const VANDELAY_EXPORT_PATH = '/exporter';
17 export const VANDELAY_UPLOAD_PATH = '/vandelay-upload';
19 export class VandelayImportSelection {
22 importQueue: boolean; // import the whole queue
23 overlayMap: {[qrId: number]: /* breId */ number};
32 export class VandelayService {
34 allQueues: {[qtype: string]: IdlObject[]};
35 attrDefs: {[atype: string]: IdlObject[]};
36 bibSources: IdlObject[];
37 bibBuckets: IdlObject[];
38 copyStatuses: IdlObject[];
39 matchSets: {[stype: string]: IdlObject[]};
40 importItemAttrDefs: IdlObject[];
41 bibTrashGroups: IdlObject[];
42 mergeProfiles: IdlObject[];
44 // Used for tracking records between the queue page and
45 // the import page. Fields managed externally.
46 importSelection: VandelayImportSelection;
48 // Track the last grid offset in the queue page so we
49 // can return the user to the same page of data after
50 // going to the matches page.
51 queuePageOffset: number;
54 private http: HttpClient,
55 private idl: IdlService,
56 private org: OrgService,
57 private evt: EventService,
58 private net: NetService,
59 private auth: AuthService,
60 private pcrud: PcrudService,
61 private perm: PermService
66 this.importSelection = null;
67 this.queuePageOffset = 0;
70 getAttrDefs(dtype: string): Promise<IdlObject[]> {
71 if (this.attrDefs[dtype]) {
72 return Promise.resolve(this.attrDefs[dtype]);
74 const cls = (dtype === 'bib') ? 'vqbrad' : 'vqarad';
77 return this.pcrud.retrieveAll(cls,
78 {order_by: orderBy}, {atomic: true}).toPromise()
80 this.attrDefs[dtype] = list;
85 getMergeProfiles(): Promise<IdlObject[]> {
86 if (this.mergeProfiles) {
87 return Promise.resolve(this.mergeProfiles);
90 const owners = this.org.ancestors(this.auth.user().ws_ou(), true);
91 return this.pcrud.search('vmp',
92 {owner: owners}, {order_by: {vmp: ['name']}}, {atomic: true})
93 .toPromise().then(profiles => {
94 this.mergeProfiles = profiles;
99 // Returns a promise resolved with the list of queues.
100 getAllQueues(qtype: string): Promise<IdlObject[]> {
101 if (this.allQueues[qtype]) {
102 return Promise.resolve(this.allQueues[qtype]);
104 this.allQueues[qtype] = [];
107 // could be a big list, invoke in streaming mode
108 return this.net.request(
110 `open-ils.vandelay.${qtype}_queue.owner.retrieve`,
113 queue => this.allQueues[qtype].push(queue)
114 )).toPromise().then(() => this.allQueues[qtype]);
117 getBibSources(): Promise<IdlObject[]> {
118 if (this.bibSources) {
119 return Promise.resolve(this.bibSources);
122 return this.pcrud.retrieveAll('cbs',
123 {order_by: {cbs: 'id'}},
125 ).toPromise().then(sources => {
126 this.bibSources = sources;
131 getItemImportDefs(): Promise<IdlObject[]> {
132 if (this.importItemAttrDefs) {
133 return Promise.resolve(this.importItemAttrDefs);
136 const owners = this.org.ancestors(this.auth.user().ws_ou(), true);
137 return this.pcrud.search('viiad', {owner: owners}, {}, {atomic: true})
138 .toPromise().then(defs => {
139 this.importItemAttrDefs = defs;
144 // todo: differentiate between biblio and authority a la queue api
145 getMatchSets(mtype: string): Promise<IdlObject[]> {
147 const mstype = mtype.match(/bib/) ? 'biblio' : 'authority';
149 if (this.matchSets[mtype]) {
150 return Promise.resolve(this.matchSets[mtype]);
152 this.matchSets[mtype] = [];
155 const owners = this.org.ancestors(this.auth.user().ws_ou(), true);
157 return this.pcrud.search('vms',
158 {owner: owners, mtype: mstype}, {}, {atomic: true})
159 .toPromise().then(sets => {
160 this.matchSets[mtype] = sets;
165 getBibBuckets(): Promise<IdlObject[]> {
166 if (this.bibBuckets) {
167 return Promise.resolve(this.bibBuckets);
171 return this.net.request(
173 'open-ils.actor.container.retrieve_by_class',
174 this.auth.token(), this.auth.user().id(), 'biblio', 'staff_client'
175 //).pipe(tap(bkt => bkts.push(bkt))).toPromise().then(() => bkts);
176 ).toPromise().then(bkts => {
177 this.bibBuckets = bkts;
182 getCopyStatuses(): Promise<any> {
183 if (this.copyStatuses) {
184 return Promise.resolve(this.copyStatuses);
186 return this.pcrud.retrieveAll('ccs', {}, {atomic: true})
187 .toPromise().then(stats => {
188 this.copyStatuses = stats;
193 getBibTrashGroups(): Promise<any> {
194 if (this.bibTrashGroups) {
195 return Promise.resolve(this.bibTrashGroups);
198 const owners = this.org.ancestors(this.auth.user().ws_ou(), true);
200 return this.pcrud.search('vibtg',
201 {always_apply : 'f', owner: owners},
204 ).toPromise().then(groups => {
205 this.bibTrashGroups = groups;
211 // Create a queue and return the ID of the new queue via promise.
217 matchBucket: number): Promise<number> {
219 const method = `open-ils.vandelay.${recordType}_queue.create`;
221 let qType = recordType;
222 if (recordType.match(/bib_acq/)) {
226 return new Promise((resolve, reject) => {
228 'open-ils.vandelay', method,
229 this.auth.token(), queueName, null, qType,
230 matchSet, importDefId, matchBucket
231 ).subscribe(queue => {
232 const e = this.evt.parse(queue);
236 // createQueue is always called after queues have
237 // been fetched and cached.
238 this.allQueues[qType].push(queue);
245 getQueuedRecords(queueId: number, queueType: string,
246 options?: any, limitToMatches?: boolean): Observable<any> {
248 const qtype = queueType.match(/bib/) ? 'bib' : 'auth';
251 `open-ils.vandelay.${qtype}_queue.records.retrieve`;
253 if (limitToMatches) {
255 `open-ils.vandelay.${qtype}_queue.records.matches.retrieve`;
258 return this.net.request('open-ils.vandelay',
259 method, this.auth.token(), queueId, options);
262 // Download a queue as a MARC file.
263 exportQueue(queue: IdlObject, nonImported?: boolean) {
265 const etype = queue.queue_type().match(/auth/) ? 'auth' : 'bib';
268 `${VANDELAY_EXPORT_PATH}?type=${etype}&queueid=${queue.id()}`
270 let saveName = queue.name();
273 url += '&nonimported=1';
274 saveName += '_nonimported';
279 this.http.get(url, {responseType: 'text'}).subscribe(
282 new Blob([data], {type: 'application/octet-stream'}),
292 // Poll every 2 seconds for session tracker updates so long
293 // as the session tracker is active.
294 // Returns an Observable of tracker objects.
295 pollSessionTracker(id: number): Observable<IdlObject> {
296 return new Observable(observer => {
297 this.getNextSessionTracker(id, observer);
301 getNextSessionTracker(id: number, observer: any) {
303 // No need for this to be an authoritative call.
304 // It will complete eventually regardless.
305 this.pcrud.retrieve('vst', id).subscribe(
307 if (tracker && tracker.state() === 'active') {
308 observer.next(tracker);
310 this.getNextSessionTracker(id, observer), 2000);
313 `Vandelay session tracker ${id} is ${tracker.state()}`);