diff --git a/src/app/core/auth/auth.service.spec.ts b/src/app/core/auth/auth.service.spec.ts index 3b6fae4dd1..a884eba7bb 100644 --- a/src/app/core/auth/auth.service.spec.ts +++ b/src/app/core/auth/auth.service.spec.ts @@ -230,6 +230,12 @@ describe('AuthService test', () => { expect(result).toBe(false); }); + it('should return true when authentication is loaded', () => { + authService.isAuthenticationLoaded().subscribe((status: boolean) => { + expect(status).toBe(true); + }); + }); + }); describe('', () => { diff --git a/src/app/core/auth/auth.service.ts b/src/app/core/auth/auth.service.ts index 588d9e2675..bacbfede10 100644 --- a/src/app/core/auth/auth.service.ts +++ b/src/app/core/auth/auth.service.ts @@ -21,7 +21,8 @@ import { getAuthenticationToken, getRedirectUrl, isAuthenticated, - isTokenRefreshing + isTokenRefreshing, + isAuthenticatedLoaded } from './selectors'; import { AppState, routerStateSelector } from '../../app.reducer'; import { @@ -148,6 +149,14 @@ export class AuthService { return this.store.pipe(select(isAuthenticated)); } + /** + * Determines if authentication is loaded + * @returns {Observable} + */ + public isAuthenticationLoaded(): Observable { + return this.store.pipe(select(isAuthenticatedLoaded)); + } + /** * Returns the href link to authenticated user * @returns {string} @@ -197,7 +206,7 @@ export class AuthService { return this.store.pipe( select(getAuthenticatedUserId), hasValueOperator(), - switchMap((id: string) => this.epersonService.findById(id)), + switchMap((id: string) => { console.log('ID: ', id); return this.epersonService.findById(id) }), getAllSucceededRemoteDataPayload() ) } diff --git a/src/app/core/locale/locale.service.spec.ts b/src/app/core/locale/locale.service.spec.ts index 1310653bce..67a4d61bf3 100644 --- a/src/app/core/locale/locale.service.spec.ts +++ b/src/app/core/locale/locale.service.spec.ts @@ -8,6 +8,7 @@ import { TranslateLoaderMock } from '../../shared/mocks/translate-loader.mock'; import { LANG_COOKIE, LocaleService, LANG_ORIGIN } from './locale.service'; import { AuthService } from '../auth/auth.service'; import { AuthServiceMock } from 'src/app/shared/mocks/auth.service.mock'; +import { NativeWindowRef } from '../services/window.service'; describe('LocaleService test suite', () => { let service: LocaleService; @@ -15,6 +16,7 @@ describe('LocaleService test suite', () => { let cookieService: CookieService; let translateService: TranslateService; let authService: AuthService; + let window; let spyOnGet; let spyOnSet; @@ -41,7 +43,8 @@ describe('LocaleService test suite', () => { cookieService = TestBed.get(CookieService); translateService = TestBed.get(TranslateService); authService = TestBed.get(TranslateService); - service = new LocaleService(cookieService, translateService, authService); + window = new NativeWindowRef(); + service = new LocaleService(window, cookieService, translateService, authService); serviceAsAny = service; spyOnGet = spyOn(cookieService, 'get'); spyOnSet = spyOn(cookieService, 'set'); diff --git a/src/app/core/locale/locale.service.ts b/src/app/core/locale/locale.service.ts index ee93f7d790..f4343b953a 100644 --- a/src/app/core/locale/locale.service.ts +++ b/src/app/core/locale/locale.service.ts @@ -1,12 +1,14 @@ -import { Injectable } from '@angular/core'; +import { Injectable, Inject } from '@angular/core'; import { TranslateService } from '@ngx-translate/core'; -import { isEmpty, hasValue } from '../../shared/empty.util'; +import { isEmpty, isNotEmpty } from '../../shared/empty.util'; import { CookieService } from '../services/cookie.service'; import { environment } from '../../../environments/environment'; import { AuthService } from '../auth/auth.service'; -import { BehaviorSubject, Observable } from 'rxjs'; +import { Observable, of as observableOf, combineLatest } from 'rxjs'; +import { map, take, flatMap, tap } from 'rxjs/operators'; +import { NativeWindowService, NativeWindowRef } from '../services/window.service'; export const LANG_COOKIE = 'language_cookie'; @@ -33,6 +35,7 @@ const EPERSON_LANG_METADATA = 'eperson.language'; export class LocaleService { constructor( + @Inject(NativeWindowService) protected _window: NativeWindowRef, private cookie: CookieService, private translate: TranslateService, private authService: AuthService) { @@ -58,39 +61,61 @@ export class LocaleService { return lang; } + /** + * Get the languages list of the user in Accept-Language format + * + * @returns {Observable} + */ getLanguageCodeList(): Observable { - const bs = new BehaviorSubject([]); - // check if user has set preferred language in UI - if (this.translate.currentLang) { - bs.next( - this.setQuality( - [this.translate.currentLang], - LANG_ORIGIN.UI, - false) - ); - } - // check if user is loggedIn and has language associated - this.authService.getAuthenticatedUserFromStore().subscribe( - (eperson) => { - const ePersonLang = eperson.firstMetadataValue(EPERSON_LANG_METADATA); - bs.next( - this.setQuality( - [ePersonLang], - LANG_ORIGIN.EPERSON, - !isEmpty(this.translate.currentLang)) + const obs$ = combineLatest([ + this.authService.isAuthenticated(), + this.authService.isAuthenticationLoaded() + ]); + + return obs$.pipe( + take(1), + flatMap(([isAuthenticated, isLoaded]) => { + let epersonLang$: Observable = observableOf([]); + if (isAuthenticated && isLoaded) { + epersonLang$ = this.authService.getAuthenticatedUserFromStore().pipe( + take(1), + map((eperson) => { + const languages: string[] = []; + const ePersonLang = eperson.firstMetadataValue(EPERSON_LANG_METADATA); + if (ePersonLang) { + languages.push(...this.setQuality( + [ePersonLang], + LANG_ORIGIN.EPERSON, + !isEmpty(this.translate.currentLang))); + } + return languages; + }) ); - } + } + return epersonLang$.pipe( + map((epersonLang: string[]) => { + const languages: string[] = []; + if (this.translate.currentLang) { + languages.push(...this.setQuality( + [this.translate.currentLang], + LANG_ORIGIN.UI, + false)); + } + if (isNotEmpty(epersonLang)) { + languages.push(...epersonLang); + } + if (navigator.languages) { + languages.push(...this.setQuality( + Object.assign([], navigator.languages), + LANG_ORIGIN.BROWSER, + !isEmpty(this.translate.currentLang)) + ); + } + return languages; + }) + ) + }) ); - // get the browser languages - if (navigator.languages) { - bs.next( - this.setQuality( - Object.assign([], navigator.languages), - LANG_ORIGIN.BROWSER, - !isEmpty(this.translate.currentLang)) - ); - } - return bs; } /** @@ -129,8 +154,8 @@ export class LocaleService { * Returns a new array that contains the languages list with the quality value. * The quality factor indicate the relative degree of preference for the language * @param languages the languages list - * @param origin - * @param hasOther + * @param origin origin of language list (UI, EPERSON, BROWSER) + * @param hasOther true if contains other language, false otherwise */ setQuality(languages: string[], origin: LANG_ORIGIN, hasOther: boolean): string[] { const langWithPrior = []; @@ -155,4 +180,13 @@ export class LocaleService { return langWithPrior; } + /** + * Refresh route navigated + */ + public refreshAfterChangeLanguage() { + // Hard redirect to the reload page with a unique number behind it + // so that all state is definitely lost + this._window.nativeWindow.location.href = `/reload/${new Date().getTime()}`; + } + } diff --git a/src/app/shared/lang-switch/lang-switch.component.spec.ts b/src/app/shared/lang-switch/lang-switch.component.spec.ts index c7d785a9e8..072f1bac40 100644 --- a/src/app/shared/lang-switch/lang-switch.component.spec.ts +++ b/src/app/shared/lang-switch/lang-switch.component.spec.ts @@ -34,11 +34,12 @@ class CustomLoader implements TranslateLoader { let localService: any; -describe('LangSwitchComponent', () => { +fdescribe('LangSwitchComponent', () => { function getMockLocaleService(): LocaleService { return jasmine.createSpyObj('LocaleService', { - setCurrentLanguageCode: jasmine.createSpy('setCurrentLanguageCode') + setCurrentLanguageCode: jasmine.createSpy('setCurrentLanguageCode'), + refreshAfterChangeLanguage: jasmine.createSpy('refreshAfterChangeLanguage') }) } @@ -121,6 +122,7 @@ describe('LangSwitchComponent', () => { it('should translate the app and set the client\'s language cookie', () => { expect(localService.setCurrentLanguageCode).toHaveBeenCalled(); + expect(localService.refreshAfterChangeLanguage).toHaveBeenCalled(); }); }); diff --git a/src/app/shared/lang-switch/lang-switch.component.ts b/src/app/shared/lang-switch/lang-switch.component.ts index 5a215cf42a..e28b1d4bb7 100644 --- a/src/app/shared/lang-switch/lang-switch.component.ts +++ b/src/app/shared/lang-switch/lang-switch.component.ts @@ -55,6 +55,7 @@ export class LangSwitchComponent implements OnInit { */ useLang(lang: string) { this.localeService.setCurrentLanguageCode(lang); + this.localeService.refreshAfterChangeLanguage(); } }