diff --git a/.prettierignore b/.prettierignore index 3859ddbc13..3f0fb7ea3c 100644 --- a/.prettierignore +++ b/.prettierignore @@ -6,3 +6,4 @@ /docs/.vitepress/dist # OpenAPI generated specs **/spec.yaml +/.nx diff --git a/apps/metadata-editor/src/app/dashboard/search-header/search-header.component.html b/apps/metadata-editor/src/app/dashboard/search-header/search-header.component.html index 2326ec526b..9b0edbaf48 100644 --- a/apps/metadata-editor/src/app/dashboard/search-header/search-header.component.html +++ b/apps/metadata-editor/src/app/dashboard/search-header/search-header.component.html @@ -20,7 +20,7 @@ diff --git a/apps/metadata-editor/src/app/dashboard/search-header/search-header.component.spec.ts b/apps/metadata-editor/src/app/dashboard/search-header/search-header.component.spec.ts index d50f0279c0..5633823269 100644 --- a/apps/metadata-editor/src/app/dashboard/search-header/search-header.component.spec.ts +++ b/apps/metadata-editor/src/app/dashboard/search-header/search-header.component.spec.ts @@ -6,7 +6,7 @@ import { import { ComponentFixture, TestBed } from '@angular/core/testing' import { SearchHeaderComponent } from './search-header.component' -import { BehaviorSubject } from 'rxjs' +import { BehaviorSubject, of } from 'rxjs' import { USER_FIXTURE } from '@geonetwork-ui/common/fixtures' import { StoreModule } from '@ngrx/store' import { EffectsModule } from '@ngrx/effects' @@ -16,8 +16,8 @@ import { PlatformServiceInterface } from '@geonetwork-ui/common/domain/platform. import { AvatarServiceInterface } from '@geonetwork-ui/api/repository/gn4' class AvatarServiceInterfaceMock { - placeholder = 'http://placeholder.com' - getProfileIcon = (hash: string) => `${hash}` + getPlaceholder = () => of('http://placeholder.com') + getProfileIcon = (hash: string) => of(`${hash}`) } const me$ = new BehaviorSubject(USER_FIXTURE()) diff --git a/apps/metadata-editor/src/app/dashboard/search-header/search-header.component.ts b/apps/metadata-editor/src/app/dashboard/search-header/search-header.component.ts index 7ce966490d..ddc5d3219f 100644 --- a/apps/metadata-editor/src/app/dashboard/search-header/search-header.component.ts +++ b/apps/metadata-editor/src/app/dashboard/search-header/search-header.component.ts @@ -22,7 +22,7 @@ import { PlatformServiceInterface } from '@geonetwork-ui/common/domain/platform. ], }) export class SearchHeaderComponent { - public placeholder = this.avatarService.placeholder + public placeholder$ = this.avatarService.getPlaceholder() constructor( public platformService: PlatformServiceInterface, diff --git a/libs/api/repository/src/lib/gn4/auth/avatar.service.interface.ts b/libs/api/repository/src/lib/gn4/auth/avatar.service.interface.ts index 3beadf4174..2ef85b8dc6 100644 --- a/libs/api/repository/src/lib/gn4/auth/avatar.service.interface.ts +++ b/libs/api/repository/src/lib/gn4/auth/avatar.service.interface.ts @@ -1,4 +1,6 @@ +import { Observable } from 'rxjs' + export abstract class AvatarServiceInterface { - public abstract placeholder: string - public abstract getProfileIcon(...args): string + public abstract getPlaceholder(): Observable + public abstract getProfileIcon(...args): Observable } diff --git a/libs/api/repository/src/lib/gn4/auth/gravatar.service.spec.ts b/libs/api/repository/src/lib/gn4/auth/gravatar.service.spec.ts index 64c2d54b05..6f31600dd7 100644 --- a/libs/api/repository/src/lib/gn4/auth/gravatar.service.spec.ts +++ b/libs/api/repository/src/lib/gn4/auth/gravatar.service.spec.ts @@ -2,7 +2,7 @@ import { TestBed } from '@angular/core/testing' import { GravatarService } from './gravatar.service' import { HttpClientTestingModule } from '@angular/common/http/testing' import { Gn4SettingsService } from '../settings/gn4-settings.service' -import { BehaviorSubject } from 'rxjs' +import { BehaviorSubject, firstValueFrom } from 'rxjs' class Gn4SettingsServiceMock { identicon$ = new BehaviorSubject('404') @@ -10,6 +10,7 @@ class Gn4SettingsServiceMock { describe('GravatarService', () => { let service: GravatarService + let settingsService: Gn4SettingsService beforeEach(() => { TestBed.configureTestingModule({ @@ -19,22 +20,31 @@ describe('GravatarService', () => { ], }) service = TestBed.inject(GravatarService) + settingsService = TestBed.inject(Gn4SettingsService) }) it('should be created', () => { expect(service).toBeTruthy() }) - it('returns correct Url without data', () => { - expect(service.getProfileIcon('')).toEqual( - 'https://www.gravatar.com/avatar/?d=404' - ) - }) - it('returns correct Url with data but without placeholder', () => { - expect(service.getProfileIcon('abc')).toEqual( - 'https://www.gravatar.com/avatar/abc?d=404' - ) + describe('#getProfileIcon', () => { + it('returns correct Url without data', async () => { + const icon = await firstValueFrom(service.getProfileIcon('')) + expect(icon).toEqual('https://www.gravatar.com/avatar/?d=404') + }) + it('returns correct Url with data but without placeholder', async () => { + const icon = await firstValueFrom(service.getProfileIcon('abc')) + expect(icon).toEqual('https://www.gravatar.com/avatar/abc?d=404') + }) }) - it('returns plaholder to be mp', () => { - expect(service.placeholder).toEqual('https://www.gravatar.com/avatar/?d=mp') + describe('#getPlaceholder', () => { + it('returns url with identicon value, without hash', async () => { + const placeholder = await firstValueFrom(service.getPlaceholder()) + expect(placeholder).toEqual('https://www.gravatar.com/avatar/?d=404') + }) + it('returns placeholder to be mp if no identicon value', async () => { + settingsService.identicon$.next('') + const placeholder = await firstValueFrom(service.getPlaceholder()) + expect(placeholder).toEqual('https://www.gravatar.com/avatar/?d=mp') + }) }) }) diff --git a/libs/api/repository/src/lib/gn4/auth/gravatar.service.ts b/libs/api/repository/src/lib/gn4/auth/gravatar.service.ts index d7839f7e3d..ce02bddb68 100644 --- a/libs/api/repository/src/lib/gn4/auth/gravatar.service.ts +++ b/libs/api/repository/src/lib/gn4/auth/gravatar.service.ts @@ -1,6 +1,8 @@ import { Injectable } from '@angular/core' import { AvatarServiceInterface } from './avatar.service.interface' import { Gn4SettingsService } from '../settings/gn4-settings.service' +import { map } from 'rxjs/operators' +import { Observable } from 'rxjs' @Injectable({ providedIn: 'root', @@ -9,16 +11,19 @@ export class GravatarService implements AvatarServiceInterface { private GRAVATAR_URL = 'https://www.gravatar.com/avatar/' private GRAVATAR_IDENTICON = 'mp' - constructor(private gn4SettingsService: Gn4SettingsService) { - this.gn4SettingsService.identicon$.subscribe( - (identicon) => - (this.GRAVATAR_IDENTICON = identicon.replace('gravatar:', '')) - ) - } + private readonly identicon$ = this.gn4SettingsService.identicon$.pipe( + map((identicon) => identicon?.replace('gravatar:', '')) + ) + constructor(private gn4SettingsService: Gn4SettingsService) {} - placeholder = this.getProfileIcon('') + getPlaceholder(): Observable { + return this.getProfileIcon('') + } - getProfileIcon(hash: string): string { - return `${this.GRAVATAR_URL}${hash}?d=${this.GRAVATAR_IDENTICON}` + getProfileIcon(hash: string): Observable { + return this.identicon$.pipe( + map((identicon) => identicon || this.GRAVATAR_IDENTICON), + map((identicon) => `${this.GRAVATAR_URL}${hash}?d=${identicon}`) + ) } } diff --git a/libs/api/repository/src/lib/gn4/platform/gn4-platform.mapper.ts b/libs/api/repository/src/lib/gn4/platform/gn4-platform.mapper.ts index bb34126673..14c73492f0 100644 --- a/libs/api/repository/src/lib/gn4/platform/gn4-platform.mapper.ts +++ b/libs/api/repository/src/lib/gn4/platform/gn4-platform.mapper.ts @@ -5,12 +5,14 @@ import { import { UserModel } from '@geonetwork-ui/common/domain/model/user/user.model' import { Injectable } from '@angular/core' import { AvatarServiceInterface } from '../auth/avatar.service.interface' +import { map } from 'rxjs/operators' +import { Observable, of } from 'rxjs' @Injectable() export class Gn4PlatformMapper { constructor(private avatarService: AvatarServiceInterface) {} - userFromMeApi(apiUser: MeResponseApiModel): UserModel { - if (!apiUser) return null + userFromMeApi(apiUser: MeResponseApiModel): Observable { + if (!apiUser) return of(null) const { hash, groupsWithRegisteredUser, @@ -20,8 +22,10 @@ export class Gn4PlatformMapper { admin, ...user } = apiUser - const icon = this.avatarService.getProfileIcon(hash) - return { ...user, profileIcon: icon } as UserModel + + return this.avatarService + .getProfileIcon(hash) + .pipe(map((profileIcon) => ({ ...user, profileIcon } as UserModel))) } userFromApi(apiUser: UserApiModel): UserModel { if (!apiUser) return null diff --git a/libs/api/repository/src/lib/gn4/platform/gn4-platform.service.spec.ts b/libs/api/repository/src/lib/gn4/platform/gn4-platform.service.spec.ts index 4d42efc935..804b7698e5 100644 --- a/libs/api/repository/src/lib/gn4/platform/gn4-platform.service.spec.ts +++ b/libs/api/repository/src/lib/gn4/platform/gn4-platform.service.spec.ts @@ -35,8 +35,8 @@ class MeApiMock { } class AvatarServiceInterfaceMock { - placeholder = 'http://placeholder.com' - getProfileIcon = jest.fn((hash: string) => `http://icon_service.com/${hash}`) + getPlaceholder = () => of('http://placeholder.com') + getProfileIcon = (hash: string) => of(`http://icon_service.com/${hash}`) } class SiteApiServiceMock { diff --git a/libs/api/repository/src/lib/gn4/platform/gn4-platform.service.ts b/libs/api/repository/src/lib/gn4/platform/gn4-platform.service.ts index 5e4807ade3..e90c04759f 100644 --- a/libs/api/repository/src/lib/gn4/platform/gn4-platform.service.ts +++ b/libs/api/repository/src/lib/gn4/platform/gn4-platform.service.ts @@ -45,7 +45,7 @@ export class Gn4PlatformService implements PlatformServiceInterface { private mapper: Gn4PlatformMapper ) { this.me$ = this.meApi.getMe().pipe( - map((apiUser) => this.mapper.userFromMeApi(apiUser)), + switchMap((apiUser) => this.mapper.userFromMeApi(apiUser)), shareReplay({ bufferSize: 1, refCount: true }) ) this.isAnonymous$ = this.me$.pipe(map((user) => !user || !('id' in user)))