diff --git a/deploy/auth/index.js b/deploy/auth/index.js index d3ce8cef15b8c2ea6f667babbcd9030694f3f605..732c522b16ac31ad55a74deee9c65ccc90961a65 100644 --- a/deploy/auth/index.js +++ b/deploy/auth/index.js @@ -9,15 +9,20 @@ let isReady = false const ready = async () => isReady const configureAuth = async (app) => { + console.log('configure Auth') const hbpOidc = require('./hbp-oidc') const hbpOidc2 = require('./hbp-oidc-v2') - const obj = await require('./util')() - const { initPassportJs, objStoreDb } = obj + const { initPassportJs, objStoreDb } = require('./util') + initPassportJs(app) - await retry(() => hbpOidc(app), { timeout: 1000, retries: 3 }) - await retry(() => hbpOidc2(app), { timeout: 1000, retries: 3 }) + await retry(async () => { + await hbpOidc(app) + }, { timeout: 1000, retries: 3 }) + await retry(async () => { + await hbpOidc2(app) + }, { timeout: 1000, retries: 3 }) isReady = true app.get('/logout', (req, res) => { diff --git a/deploy/auth/index.spec.js b/deploy/auth/index.spec.js index be692b0eacdb16cb5d3972fb7736203367bb3dfc..6773ad36bd7fcc46a8af447e3eea77555e6299d9 100644 --- a/deploy/auth/index.spec.js +++ b/deploy/auth/index.spec.js @@ -1,8 +1,6 @@ const sinon = require('sinon') const { assert, expect } = require('chai') const initPassportJsStub = sinon.stub() -const utilStub = sinon.stub() -utilStub.returns(new Promise(rs => rs({ initPassportJs: initPassportJsStub }))) const hbpOidcStub = sinon.stub() const hbpOidcV2Stub = sinon.stub() @@ -12,7 +10,7 @@ const appGetStub = sinon.stub() describe('auth/index.js', () => { before(() => { require.cache[require.resolve('./util')] = { - exports: utilStub + exports: { initPassportJs: initPassportJsStub } } require.cache[require.resolve('./hbp-oidc')] = { exports: hbpOidcStub diff --git a/deploy/auth/util.js b/deploy/auth/util.js index 9b5bbaadbfad423b530af5ebf360d369845371cb..4733f5070d9ef981d3ca4c9f6720834ae229f12b 100644 --- a/deploy/auth/util.js +++ b/deploy/auth/util.js @@ -31,9 +31,27 @@ const refreshToken = async () => { return true } +const getClient = async () => { + const { client } = await configureAuth({ + clientId, + clientSecret, + discoveryUrl, + redirectUri, + clientConfig: { + redirect_uris: [ redirectUri ], + response_types: [ 'code' ] + } + }) + + __client = client +} + +getClient() + const getPublicAccessToken = async () => { - if (!__client) - throw new Error(CLIENT_NOT_INIT) + if (!__client) { + await getClient() + } if (!__publicAccessToken) { await refreshToken() @@ -70,31 +88,8 @@ const initPassportJs = app => { }) } -module.exports = async () => { - - /** - * this configuration is required to acquire valid - * access tokens using refresh token - * - * This is so that datasets can be retrieved when user - * is not authenticated - */ - const { client } = await configureAuth({ - clientId, - clientSecret, - discoveryUrl, - redirectUri, - clientConfig: { - redirect_uris: [ redirectUri ], - response_types: [ 'code' ] - } - }) - - __client = client - - return { - initPassportJs, - objStoreDb, - getPublicAccessToken: async () => await getPublicAccessToken() - } -} \ No newline at end of file +module.exports = { + initPassportJs, + objStoreDb, + getPublicAccessToken: async () => await getPublicAccessToken(), +} diff --git a/deploy/auth/util.spec.js b/deploy/auth/util.spec.js index d81a177536bd14b966b95c1afa55348e4aaf37b2..1d8a33ae229aa4540d80edb1fba201e80cdd9d97 100644 --- a/deploy/auth/util.spec.js +++ b/deploy/auth/util.spec.js @@ -114,8 +114,7 @@ describe('util.js', async () => { }) it('> configureAuth and refresh called with correct param', async () => { - const util = require('./util') - const { getPublicAccessToken } = await util() + const { getPublicAccessToken } = require('./util') const token = await getPublicAccessToken() const { @@ -130,7 +129,10 @@ describe('util.js', async () => { const { HBP_CLIENTID, HBP_CLIENTSECRET, HOSTNAME, HOST_PATHNAME, REFRESH_TOKEN } = env // configuAuthStub - assert(configureAuthStub.calledOnce) + assert( + configureAuthStub.called, + 'expect configureAuthStub to have been called once' + ) const { args } = configureAuthStub.firstCall const arg = args[0] expect(arg).to.include({ @@ -183,8 +185,7 @@ describe('util.js', async () => { }) it('> refresh getPublicAccessToken will reject', async () => { - const util = require('./util') - const { getPublicAccessToken } = await util() + const { getPublicAccessToken } = require('./util') try { await getPublicAccessToken() diff --git a/deploy/datasets/index.js b/deploy/datasets/index.js index b5aa755c55717af63100e2f21ae079e7c0c766fe..886369d89d8e947464be6d8d2e1fc66b15f01a53 100644 --- a/deploy/datasets/index.js +++ b/deploy/datasets/index.js @@ -16,15 +16,12 @@ datasetsRouter.use(bodyParser.urlencoded({ extended: false })) datasetsRouter.use(bodyParser.json()) let readyFlag = false -init() - .then(() => { - console.log(`dataset init success`) - readyFlag = true - }) - .catch(e => { - console.warn(`dataset init failed`, e) - retry(() => init()) - }) + +retry(async () => { + await init() + console.log(`data init success`) + readyFlag = true +}, { timeout: 1000, retries: 5 }) const ready = async () => readyFlag diff --git a/deploy/datasets/util.js b/deploy/datasets/util.js index f394dad852746c26996d4fea857a98795cf492b7..a0bf8f2b1e12a1a54e5199980ab8c0e408296c76 100644 --- a/deploy/datasets/util.js +++ b/deploy/datasets/util.js @@ -1,4 +1,4 @@ -const kgQueryUtil = require('./../auth/util') +const { getPublicAccessToken: getPublic } = require('./../auth/util') const { getCommonSenseDsFilter } = require('./supplements/commonSense') const { hasPreview } = require('./supplements/previewFile') const path = require('path') @@ -378,7 +378,6 @@ const init = async () => { else console.warn(`ACCESS_TOKEN environmental variable is set! All queries will be made made with ACCESS_TOKEN!`) } if (getPublicAccessToken) return - const { getPublicAccessToken: getPublic } = await kgQueryUtil() getPublicAccessToken = getPublic } diff --git a/src/main.module.ts b/src/main.module.ts index 2ad478a6ac13ac3cd2f214e4bdd1f3ef2a4ef1b2..06c2a92305d7213bf957698a7c9710827caa905e 100644 --- a/src/main.module.ts +++ b/src/main.module.ts @@ -243,23 +243,6 @@ export function debug(reducer: ActionReducer<any>): ActionReducer<any> { deps: [ ClickInterceptorService ] - }, - { - provide: OVERWRITE_SHOW_DATASET_DIALOG_TOKEN, - useFactory: (store: Store<any>) => { - return function overwriteShowDatasetDialog( arg: { fullId?: string, name: string, description: string } ){ - if (arg.fullId) { - store.dispatch( - uiActionShowDatasetWtihId({ - id: arg.fullId - }) - ) - } - } as TOverwriteShowDatasetDialog - }, - deps: [ - Store - ] } ], bootstrap : [ diff --git a/src/ui/databrowserModule/databrowser.service.ts b/src/ui/databrowserModule/databrowser.service.ts index 7c8ccc1dfc1d9b1de747ded340616cf1bc3cae5f..67ea743005e076fb9028bc676f193ac44058b6d5 100644 --- a/src/ui/databrowserModule/databrowser.service.ts +++ b/src/ui/databrowserModule/databrowser.service.ts @@ -1,8 +1,8 @@ import { HttpClient } from "@angular/common/http"; import {ComponentRef, Injectable, OnDestroy} from "@angular/core"; import { select, Store } from "@ngrx/store"; -import { BehaviorSubject, combineLatest, forkJoin, from, fromEvent, Observable, of, Subscription } from "rxjs"; -import { catchError, debounceTime, distinctUntilChanged, filter, map, shareReplay, switchMap, tap, withLatestFrom } from "rxjs/operators"; +import { BehaviorSubject, forkJoin, from, fromEvent, Observable, of, Subscription } from "rxjs"; +import { catchError, debounceTime, distinctUntilChanged, filter, map, shareReplay, switchMap, withLatestFrom } from "rxjs/operators"; import { AtlasViewerConstantsServices } from "src/atlasViewer/atlasViewer.constantService.service"; import { AtlasWorkerService } from "src/atlasViewer/atlasViewer.workerService.service"; @@ -18,7 +18,7 @@ import { FilterDataEntriesByRegion } from "./util/filterDataEntriesByRegion.pipe import { datastateActionToggleFav, datastateActionUnfavDataset, datastateActionFavDataset } from "src/services/state/dataState/actions"; import { getStringIdsFromRegion } from 'common/util' -import { viewerStateSelectorNavigation } from "src/services/state/viewerState/selectors"; +import { viewerStateSelectedTemplateSelector, viewerStateSelectorNavigation } from "src/services/state/viewerState/selectors"; const noMethodDisplayName = 'No methods described' @@ -87,7 +87,6 @@ export class DatabrowserService implements OnDestroy { private dataentries: IDataEntry[] = [] private subscriptions: Subscription[] = [] - public fetchDataObservable$: Observable<any> public manualFetchDataset$: BehaviorSubject<null> = new BehaviorSubject(null) public spatialDatasets$: Observable<any> @@ -146,8 +145,7 @@ export class DatabrowserService implements OnDestroy { this.spatialDatasets$ = this.viewportBoundingBox$.pipe( withLatestFrom(this.store.pipe( - select('viewerState'), - select('templateSelected'), + select(viewerStateSelectedTemplateSelector), distinctUntilChanged(), filter(v => !!v), )), @@ -165,23 +163,6 @@ export class DatabrowserService implements OnDestroy { }), ) - this.fetchDataObservable$ = combineLatest( - this.store.pipe( - select('viewerState'), - safeFilter('templateSelected'), - tap(({templateSelected}) => this.darktheme = templateSelected.useTheme === 'dark'), - map(({templateSelected}) => (templateSelected.name)), - distinctUntilChanged(), - ), - this.store.pipe( - select('viewerState'), - safeFilter('parcellationSelected'), - map(({parcellationSelected}) => (parcellationSelected.name)), - distinctUntilChanged(), - ), - this.manualFetchDataset$, - ) - this.subscriptions.push( this.spatialDatasets$.subscribe(arr => { this.store.dispatch({ @@ -191,12 +172,6 @@ export class DatabrowserService implements OnDestroy { }), ) - this.subscriptions.push( - this.fetchDataObservable$.pipe( - debounceTime(16), - ).subscribe((param: [string, string, null] ) => this.fetchData(param[0], param[1])), - ) - this.subscriptions.push( fromEvent(this.workerService.worker, 'message').pipe( filter((message: MessageEvent) => message && message.data && message.data.type === 'RETURN_REBUILT_REGION_SELECTION_TREE'), diff --git a/src/ui/databrowserModule/databrowser/databrowser.component.ts b/src/ui/databrowserModule/databrowser/databrowser.component.ts index fb951325407d19176d77763b231409265adcc9c2..ad18ebb36bdb592456a671de321ae68e74ea4f2a 100644 --- a/src/ui/databrowserModule/databrowser/databrowser.component.ts +++ b/src/ui/databrowserModule/databrowser/databrowser.component.ts @@ -1,5 +1,5 @@ -import { ChangeDetectionStrategy, ChangeDetectorRef, Component, EventEmitter, Input, OnChanges, OnDestroy, OnInit, Output, ViewChild } from "@angular/core"; -import { merge, Observable, Subscription } from "rxjs"; +import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnDestroy, OnInit, ViewChild } from "@angular/core"; +import { Subscription } from "rxjs"; import { LoggingService } from "src/logging"; import { IDataEntry } from "src/services/state/dataStore.store"; import { CountedDataModality, DatabrowserService } from "../databrowser.service"; @@ -7,6 +7,9 @@ import { ModalityPicker } from "../modalityPicker/modalityPicker.component"; import { ARIA_LABELS } from 'common/constants.js' import { DatabrowserBase } from "./databrowser.base"; import { debounceTime } from "rxjs/operators"; +import { OVERWRITE_SHOW_DATASET_DIALOG_TOKEN, TOverwriteShowDatasetDialog } from "src/util/interfaces"; +import { Store } from "@ngrx/store"; +import { uiActionShowDatasetWtihId } from "src/services/state/uiState/actions"; const { MODALITY_FILTER, LIST_OF_DATASETS } = ARIA_LABELS @@ -18,6 +21,27 @@ const { MODALITY_FILTER, LIST_OF_DATASETS } = ARIA_LABELS ], exportAs: 'dataBrowser', changeDetection: ChangeDetectionStrategy.OnPush, + providers: [ + + { + provide: OVERWRITE_SHOW_DATASET_DIALOG_TOKEN, + useFactory: (store: Store<any>) => { + return function overwriteShowDatasetDialog( arg: { fullId?: string, name: string, description: string } ){ + if (arg.fullId) { + store.dispatch( + uiActionShowDatasetWtihId({ + id: arg.fullId + }) + ) + } + } as TOverwriteShowDatasetDialog + }, + deps: [ + Store + ] + } + ] + }) export class DataBrowser extends DatabrowserBase implements OnDestroy, OnInit { @@ -74,18 +98,6 @@ export class DataBrowser extends DatabrowserBase implements OnDestroy, OnInit { * TODO gets init'ed everytime when appends to ngtemplateoutlet */ this.dataService.dbComponentInit(this) - this.subscriptions.push( - merge( - // this.dataService.selectedRegions$, - this.dataService.fetchDataObservable$, - ).subscribe(() => { - /** - * Only reset modality picker - * resetting all creates infinite loop - */ - this.clearAll() - }), - ) /** * TODO fix diff --git a/src/ui/databrowserModule/kgSingleDatasetService.service.ts b/src/ui/databrowserModule/kgSingleDatasetService.service.ts index 4f00a6f0ce282c6a78d95bb0ac01c787ce64b9d9..d182542fa3fe6593809aabb14f2b0872036014a7 100644 --- a/src/ui/databrowserModule/kgSingleDatasetService.service.ts +++ b/src/ui/databrowserModule/kgSingleDatasetService.service.ts @@ -1,8 +1,8 @@ import { HttpClient } from "@angular/common/http"; import { Injectable, OnDestroy, TemplateRef } from "@angular/core"; import { select, Store } from "@ngrx/store"; -import { Subscription } from "rxjs"; -import { filter } from "rxjs/operators"; +import { Observable, Subscription } from "rxjs"; +import { filter, shareReplay } from "rxjs/operators"; import { IDataEntry, ViewerPreviewFile, DATASETS_ACTIONS_TYPES } from "src/services/state/dataStore.store"; import { IavRootStoreInterface } from "src/services/stateStore.service"; import { BACKENDURL } from "src/util/constants"; @@ -36,12 +36,20 @@ export class KgSingleDatasetService implements OnDestroy { } } + private memoizedDatasetFromKg: Map<string, Observable<any>> = new Map() + public getInfoFromKg({ kgId, kgSchema = 'minds/core/dataset/v1.0.0' }: Partial<KgQueryInterface>) { + const key = `${kgSchema}/${kgId}` + if (this.memoizedDatasetFromKg.has(key)) return this.memoizedDatasetFromKg.get(key) const _url = new URL(`${BACKENDURL.replace(/\/$/, '')}/datasets/kgInfo`) const searchParam = _url.searchParams searchParam.set('kgSchema', kgSchema) searchParam.set('kgId', kgId) - return this.http.get<any>(_url.toString(), { responseType: 'json' }) + const query$ = this.http.get<any>(_url.toString(), { responseType: 'json' }).pipe( + shareReplay(1) + ) + this.memoizedDatasetFromKg.set(key, query$) + return query$ } public getDownloadZipFromKgHref({ kgSchema = 'minds/core/dataset/v1.0.0', kgId }) {