Skip to content

Commit e052799

Browse files
Mattia VianelliAndrea Barbasso
authored andcommitted
Merged in task/dspace-cris-2024_02_x/DSC-2458 (pull request DSpace#3990)
Task/dspace cris 2024 02 x/DSC-2458 Approved-by: Andrea Barbasso
2 parents e35afb1 + 253e78a commit e052799

10 files changed

Lines changed: 443 additions & 88 deletions
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<div class="container">
2+
3+
<h2 *ngIf="(headLabel$ | async) as headLabel">{{ headLabel | translate }}</h2>
4+
5+
<ng-container *ngIf="metadataLoaded$ | async">
6+
<ng-container *ngIf="(cmsMetadataValue$ | async) as value; else missingMetadata">
7+
<ds-markdown-viewer [value]="value"></ds-markdown-viewer>
8+
</ng-container>
9+
</ng-container>
10+
11+
<ng-template #missingMetadata>
12+
<div>{{ 'info.empty-cms-metadata-error' | translate }}</div>
13+
</ng-template>
14+
</div>

src/app/info/cms-info/cms-info.component.scss

Whitespace-only changes.
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
import {
2+
ComponentFixture,
3+
TestBed,
4+
} from '@angular/core/testing';
5+
import { ActivatedRoute } from '@angular/router';
6+
import { Store } from '@ngrx/store';
7+
import { TranslateModule } from '@ngx-translate/core';
8+
import { MockComponent } from 'ng-mocks';
9+
import {
10+
Observable,
11+
of as observableOf,
12+
of,
13+
} from 'rxjs';
14+
import { AuthService } from 'src/app/core/auth/auth.service';
15+
import { AuthTokenInfo } from 'src/app/core/auth/models/auth-token-info.model';
16+
import { ObjectCacheService } from 'src/app/core/cache/object-cache.service';
17+
import { SiteDataService } from 'src/app/core/data/site-data.service';
18+
import { LocaleService } from 'src/app/core/locale/locale.service';
19+
import { CookieService } from 'src/app/core/services/cookie.service';
20+
import {
21+
NativeWindowRef,
22+
NativeWindowService,
23+
} from 'src/app/core/services/window.service';
24+
import { Site } from 'src/app/core/shared/site.model';
25+
import { CookieServiceMock } from 'src/app/shared/mocks/cookie.service.mock';
26+
27+
import { MarkdownViewerComponent } from '../../shared/markdown-viewer/markdown-viewer.component';
28+
import { CmsInfoComponent } from './cms-info.component';
29+
30+
describe('CmsInfoComponent', () => {
31+
let component: CmsInfoComponent;
32+
let fixture: ComponentFixture<CmsInfoComponent>;
33+
let authService: AuthService;
34+
let token: AuthTokenInfo;
35+
let store;
36+
let redirectUrl: string;
37+
let activatedRouteStub: any;
38+
let siteServiceStub: any;
39+
40+
const site: Site = Object.assign(new Site(), {
41+
metadata: {
42+
'dc.rights' : [{
43+
value: 'English text',
44+
language: 'en',
45+
},
46+
{
47+
value: 'German text',
48+
language: 'de',
49+
}],
50+
},
51+
});
52+
53+
beforeEach(async () => {
54+
redirectUrl = 'redirect/url';
55+
token = new AuthTokenInfo('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9');
56+
authService = jasmine.createSpyObj('authService', {
57+
isAuthenticated: observableOf(true),
58+
getToken: token,
59+
});
60+
store = jasmine.createSpyObj('store', ['dispatch']);
61+
activatedRouteStub = {
62+
data: observableOf({ schema: 'cris', qualifier: 'testQualifier' }),
63+
queryParamMap: observableOf({}),
64+
};
65+
siteServiceStub = {
66+
find(): Observable<Site> {
67+
return of(site);
68+
},
69+
};
70+
await TestBed.configureTestingModule({
71+
imports: [
72+
TranslateModule.forRoot(),
73+
CmsInfoComponent,
74+
MockComponent(MarkdownViewerComponent),
75+
],
76+
providers: [
77+
LocaleService,
78+
ObjectCacheService,
79+
{ provide: SiteDataService, useValue: siteServiceStub },
80+
{ provide: Store, useValue: store },
81+
{ provide: AuthService, useValue: authService },
82+
{ provide: CookieService, useValue: new CookieServiceMock },
83+
{ provide: NativeWindowService, useValue: new NativeWindowRef() },
84+
{ provide: ActivatedRoute, useValue: activatedRouteStub },
85+
],
86+
})
87+
.compileComponents();
88+
89+
fixture = TestBed.createComponent(CmsInfoComponent);
90+
component = fixture.componentInstance;
91+
fixture.detectChanges();
92+
});
93+
94+
it('should create', () => {
95+
expect(component).toBeTruthy();
96+
});
97+
98+
it('should set headLabel$ when data is successfully retrieved', () => {
99+
const headLabelSpy = spyOn(component.headLabel$, 'next');
100+
101+
component.ngOnInit();
102+
103+
expect(headLabelSpy).toHaveBeenCalledOnceWith('info.testQualifier.head');
104+
});
105+
106+
it('should log a warning to console if metadata content is missing', () => {
107+
spyOn(console, 'warn');
108+
site.metadata['cris.cms.testQualifier'] = undefined;
109+
110+
component.ngOnInit();
111+
112+
expect(console.warn).toHaveBeenCalledWith('Metadata cris.cms.testQualifier has no content');
113+
});
114+
});
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
import {
2+
AsyncPipe,
3+
NgIf,
4+
} from '@angular/common';
5+
import {
6+
Component,
7+
OnInit,
8+
} from '@angular/core';
9+
import { ActivatedRoute } from '@angular/router';
10+
import { TranslateModule } from '@ngx-translate/core';
11+
import {
12+
BehaviorSubject,
13+
combineLatest,
14+
} from 'rxjs';
15+
import { take } from 'rxjs/operators';
16+
17+
import { SiteDataService } from '../../core/data/site-data.service';
18+
import { LocaleService } from '../../core/locale/locale.service';
19+
import { hasValue } from '../../shared/empty.util';
20+
import { MarkdownViewerComponent } from '../../shared/markdown-viewer/markdown-viewer.component';
21+
22+
@Component({
23+
selector: 'ds-cms-info',
24+
templateUrl: './cms-info.component.html',
25+
styleUrls: ['./cms-info.component.scss'],
26+
standalone: true,
27+
imports: [
28+
NgIf,
29+
AsyncPipe,
30+
TranslateModule,
31+
MarkdownViewerComponent,
32+
],
33+
})
34+
export class CmsInfoComponent implements OnInit {
35+
36+
/**
37+
* The i18n label for the page title
38+
*/
39+
headLabel$ = new BehaviorSubject<string>('');
40+
41+
/**
42+
* The content of the CMS metadata
43+
*/
44+
cmsMetadataValue$ = new BehaviorSubject<string>('');
45+
46+
/**
47+
* True if the metadata content is being loaded
48+
*/
49+
metadataLoaded$ = new BehaviorSubject<boolean>(false);
50+
51+
constructor(
52+
private siteService: SiteDataService,
53+
private locale: LocaleService,
54+
private route: ActivatedRoute,
55+
) {
56+
}
57+
58+
ngOnInit() {
59+
60+
const data$ = this.route.data.pipe(
61+
take(1),
62+
);
63+
64+
const site$ = this.siteService.find().pipe(take(1));
65+
66+
combineLatest([data$, site$]).subscribe(([data, site]) => {
67+
this.headLabel$.next(`info.${data.qualifier}.head`);
68+
const mdValue = site?.firstMetadataValue(`${data.schema}.cms.${data.qualifier}`, { language: this.locale.getCurrentLanguageCode() });
69+
if (hasValue(mdValue)) {
70+
this.cmsMetadataValue$.next(mdValue);
71+
} else {
72+
console.warn(`Metadata ${data.schema}.cms.${data.qualifier} has no content`);
73+
}
74+
this.metadataLoaded$.next(true);
75+
});
76+
77+
}
78+
79+
}

src/app/info/info-routes.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { notifyInfoGuard } from '../core/coar-notify/notify-info/notify-info.gua
99
import { feedbackGuard } from '../core/feedback/feedback.guard';
1010
import { hasValue } from '../shared/empty.util';
1111
import { AccessibilitySettingsComponent } from './accessibility-settings/accessibility-settings.component';
12+
import { CmsInfoComponent } from './cms-info/cms-info.component';
1213
import { ThemedEndUserAgreementComponent } from './end-user-agreement/themed-end-user-agreement.component';
1314
import { ThemedFeedbackComponent } from './feedback/themed-feedback.component';
1415
import {
@@ -21,6 +22,19 @@ import {
2122
import { NotifyInfoComponent } from './notify-info/notify-info.component';
2223
import { ThemedPrivacyComponent } from './privacy/themed-privacy.component';
2324

25+
function cmsInfoRoute(qualifier: string, schema: string): Route {
26+
return {
27+
path: qualifier,
28+
component: CmsInfoComponent,
29+
resolve: { breadcrumb: i18nBreadcrumbResolver },
30+
data: {
31+
title: `info.${qualifier}.title`,
32+
breadcrumbKey: `info.${qualifier}`,
33+
schema: schema,
34+
qualifier: qualifier,
35+
},
36+
};
37+
}
2438

2539
export const ROUTES: Routes = [
2640
{
@@ -60,4 +74,5 @@ export const ROUTES: Routes = [
6074
breadcrumbKey: 'info.coar-notify-support',
6175
},
6276
} : undefined,
77+
cmsInfoRoute(PRIVACY_PATH, 'cris'),
6378
].filter((route: Route) => hasValue(route));

0 commit comments

Comments
 (0)