Skip to content

Commit 53fc9e1

Browse files
committed
Merge branch 'dspace-cris-2023_02_x' into main-cris
2 parents e270018 + 6320a3d commit 53fc9e1

32 files changed

+878
-304
lines changed

bitbucket-pipelines.yml

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
options:
2-
runs-on: ubuntu-latest
2+
runs-on: self.hosted
33

44
definitions:
55
steps:
@@ -15,7 +15,7 @@ definitions:
1515
- yarn install --frozen-lockfile
1616
- yarn run lint --quiet
1717
- yarn run check-circ-deps
18-
- yarn run build:prod
18+
- yarn run build:prod:ci
1919
- yarn run test:headless
2020

2121
pipelines:

config/config.example.yml

+4
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,10 @@ item:
308308
# Rounded to the nearest size in the list of selectable sizes on the
309309
# settings menu. See pageSizeOptions in 'pagination-component-options.model.ts'.
310310
pageSize: 5
311+
# The maximum number of metadata values to add to the metatag list of the item page
312+
metatagLimit: 20
313+
# The maximum number of values for repeatable metadata to show in the full item
314+
metadataLimit: 20
311315

312316
# When the search results are retrieved, for each item type the metadata with a valid authority value are inspected.
313317
# Referenced items will be fetched with a find all by id strategy to avoid individual rest requests

package.json

+3-2
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,11 @@
1717
"build:stats": "ng build --stats-json",
1818
"build:ci": "ng config cli.cache.environment ci && yarn run build:ssr",
1919
"build:prod": "cross-env NODE_ENV=production yarn run build:ssr",
20+
"build:prod:ci": "cross-env NODE_ENV=production yarn run build:ssr:ci",
2021
"build:ssr": "npm run ng-high-memory -- build --configuration production && npm run ng-high-memory -- run dspace-angular:server:production",
22+
"build:ssr:ci": "npm run ng-mid-memory -- build --configuration production && npm run ng-mid-memory -- run dspace-angular:server:production",
2123
"ng-high-memory": "node --max-old-space-size=8192 node_modules/@angular/cli/bin/ng",
24+
"ng-mid-memory": "node --max-old-space-size=4096 node_modules/@angular/cli/bin/ng",
2225
"test": "npm run ng-high-memory -- test --source-map=true --watch=false --configuration test",
2326
"test:watch": "nodemon --exec \"npm run ng-high-memory -- test --source-map=true --watch=true --configuration test\"",
2427
"test:headless": "npm run ng-high-memory -- test --source-map=true --watch=false --configuration test --browsers=ChromeHeadless --code-coverage",
@@ -140,7 +143,6 @@
140143
"ng2-nouislider": "^2.0.0",
141144
"ngx-infinite-scroll": "^15.0.0",
142145
"ngx-pagination": "6.0.3",
143-
"ngx-sortablejs": "^11.1.0",
144146
"ngx-ui-switch": "^14.0.3",
145147
"nouislider": "^15.7.1",
146148
"pem": "1.14.7",
@@ -149,7 +151,6 @@
149151
"reflect-metadata": "^0.1.13",
150152
"rxjs": "^7.8.0",
151153
"sanitize-html": "^2.10.0",
152-
"sortablejs": "1.15.0",
153154
"uuid": "^8.3.2",
154155
"webfontloader": "1.6.28",
155156
"zone.js": "~0.11.5"

src/app/core/locale/locale.service.spec.ts

+139-103
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import { AuthService } from '../auth/auth.service';
1010
import { NativeWindowRef } from '../services/window.service';
1111
import { RouteService } from '../services/route.service';
1212
import { routeServiceStub } from '../../shared/testing/route-service.stub';
13+
import { of as observableOf } from 'rxjs';
1314

1415
describe('LocaleService test suite', () => {
1516
let service: LocaleService;
@@ -22,129 +23,164 @@ describe('LocaleService test suite', () => {
2223
let authService;
2324
let routeService;
2425
let document;
26+
let spyOnGetLanguage;
27+
28+
29+
const translateServiceStub: any = {
30+
getLangs: () => {
31+
return langList;
32+
},
33+
getBrowserLang: () => {
34+
return langList;
35+
},
36+
// eslint-disable-next-line @typescript-eslint/no-empty-function
37+
use: (param: string) => {
38+
}
39+
};
2540

2641
authService = jasmine.createSpyObj('AuthService', {
2742
isAuthenticated: jasmine.createSpy('isAuthenticated'),
2843
isAuthenticationLoaded: jasmine.createSpy('isAuthenticationLoaded')
2944
});
30-
3145
const langList = ['en', 'xx', 'de'];
3246

33-
beforeEach(waitForAsync(() => {
34-
return TestBed.configureTestingModule({
35-
imports: [
36-
TranslateModule.forRoot({
37-
loader: {
38-
provide: TranslateLoader,
39-
useClass: TranslateLoaderMock
40-
}
41-
}),
42-
],
43-
providers: [
44-
{ provide: CookieService, useValue: new CookieServiceMock() },
45-
{ provide: AuthService, userValue: authService },
46-
{ provide: RouteService, useValue: routeServiceStub },
47-
{ provide: Document, useValue: document },
48-
]
49-
});
50-
}));
51-
52-
beforeEach(() => {
53-
cookieService = TestBed.inject(CookieService);
54-
translateService = TestBed.inject(TranslateService);
55-
routeService = TestBed.inject(RouteService);
56-
window = new NativeWindowRef();
57-
document = { documentElement: { lang: 'en' } };
58-
service = new LocaleService(window, cookieService, translateService, authService, routeService, document);
59-
serviceAsAny = service;
60-
spyOnGet = spyOn(cookieService, 'get');
61-
spyOnSet = spyOn(cookieService, 'set');
62-
});
47+
describe('with valid language', () => {
48+
49+
beforeEach(waitForAsync(() => {
50+
return TestBed.configureTestingModule({
51+
imports: [
52+
TranslateModule.forRoot({
53+
loader: {
54+
provide: TranslateLoader,
55+
useClass: TranslateLoaderMock
56+
}
57+
}),
58+
],
59+
providers: [
60+
{ provide: CookieService, useValue: new CookieServiceMock() },
61+
{ provide: AuthService, userValue: authService },
62+
{ provide: RouteService, useValue: routeServiceStub },
63+
{ provide: TranslateService, useValue: translateServiceStub },
64+
{ provide: Document, useValue: document },
65+
]
66+
});
67+
}));
6368

64-
describe('getCurrentLanguageCode', () => {
6569
beforeEach(() => {
66-
spyOn(translateService, 'getLangs').and.returnValue(langList);
67-
});
68-
69-
it('should return the language saved on cookie if it\'s a valid & active language', () => {
70-
spyOnGet.and.returnValue('de');
71-
expect(service.getCurrentLanguageCode()).toBe('de');
72-
});
73-
74-
it('should return the default language if the cookie language is disabled', () => {
75-
spyOnGet.and.returnValue('disabled');
76-
expect(service.getCurrentLanguageCode()).toBe('en');
77-
});
78-
79-
it('should return the default language if the cookie language does not exist', () => {
80-
spyOnGet.and.returnValue('does-not-exist');
81-
expect(service.getCurrentLanguageCode()).toBe('en');
82-
});
83-
84-
it('should return language from browser setting', () => {
85-
spyOn(translateService, 'getBrowserLang').and.returnValue('xx');
86-
expect(service.getCurrentLanguageCode()).toBe('xx');
70+
cookieService = TestBed.inject(CookieService);
71+
translateService = TestBed.inject(TranslateService);
72+
routeService = TestBed.inject(RouteService);
73+
window = new NativeWindowRef();
74+
document = { documentElement: { lang: 'en' } };
75+
service = new LocaleService(window, cookieService, translateService, authService, routeService, document);
76+
serviceAsAny = service;
77+
spyOnGet = spyOn(cookieService, 'get');
78+
spyOnSet = spyOn(cookieService, 'set');
79+
spyOnGetLanguage = spyOn(routeService, 'getQueryParameterValue').withArgs('lang');
8780
});
8881

89-
it('should return default language from config', () => {
90-
spyOn(translateService, 'getBrowserLang').and.returnValue('fr');
91-
expect(service.getCurrentLanguageCode()).toBe('en');
92-
});
93-
});
94-
95-
describe('getLanguageCodeFromCookie', () => {
96-
it('should return language from cookie', () => {
97-
spyOnGet.and.returnValue('de');
98-
expect(service.getLanguageCodeFromCookie()).toBe('de');
82+
describe('getCurrentLanguageCode', () => {
83+
it('should return language saved on cookie', () => {
84+
spyOnGet.and.returnValue('de');
85+
expect(service.getCurrentLanguageCode()).toBe('de');
86+
});
87+
88+
describe('', () => {
89+
beforeEach(() => {
90+
spyOn(translateService, 'getLangs').and.returnValue(langList);
91+
});
92+
93+
it('should return language from browser setting', () => {
94+
spyOn(translateService, 'getBrowserLang').and.returnValue('xx');
95+
expect(service.getCurrentLanguageCode()).toBe('xx');
96+
});
97+
98+
it('should return default language from config', () => {
99+
spyOn(translateService, 'getBrowserLang').and.returnValue('fr');
100+
expect(service.getCurrentLanguageCode()).toBe('en');
101+
});
102+
});
99103
});
100104

101-
});
105+
describe('getLanguageCodeFromCookie', () => {
106+
it('should return language from cookie', () => {
107+
spyOnGet.and.returnValue('de');
108+
expect(service.getLanguageCodeFromCookie()).toBe('de');
109+
});
102110

103-
describe('saveLanguageCodeToCookie', () => {
104-
it('should save language to cookie', () => {
105-
service.saveLanguageCodeToCookie('en');
106-
expect(spyOnSet).toHaveBeenCalledWith(LANG_COOKIE, 'en');
107111
});
108-
});
109112

110-
describe('setCurrentLanguageCode', () => {
111-
beforeEach(() => {
112-
spyOn(service, 'saveLanguageCodeToCookie');
113-
spyOn(translateService, 'use');
113+
describe('saveLanguageCodeToCookie', () => {
114+
it('should save language to cookie', () => {
115+
service.saveLanguageCodeToCookie('en');
116+
expect(spyOnSet).toHaveBeenCalledWith(LANG_COOKIE, 'en');
117+
});
114118
});
115119

116-
it('should set the given language', () => {
117-
service.setCurrentLanguageCode('xx');
118-
expect(translateService.use).toHaveBeenCalledWith('xx');
119-
expect(service.saveLanguageCodeToCookie).toHaveBeenCalledWith('xx');
120-
});
121-
122-
it('should set the current language', () => {
123-
spyOn(service, 'getCurrentLanguageCode').and.returnValue('es');
124-
service.setCurrentLanguageCode();
125-
expect(translateService.use).toHaveBeenCalledWith('es');
126-
expect(service.saveLanguageCodeToCookie).toHaveBeenCalledWith('es');
127-
});
128-
129-
it('should set the current language on the html tag', () => {
130-
spyOn(service, 'getCurrentLanguageCode').and.returnValue('es');
131-
service.setCurrentLanguageCode();
132-
expect((service as any).document.documentElement.lang).toEqual('es');
133-
});
134-
});
135-
136-
describe('', () => {
137-
it('should set quality to current language list', () => {
138-
const langListWithQuality = ['en;q=1', 'xx;q=0.9', 'de;q=0.8'];
139-
spyOn(service, 'setQuality').and.returnValue(langListWithQuality);
140-
service.setQuality(langList, LANG_ORIGIN.BROWSER, false);
141-
expect(service.setQuality).toHaveBeenCalledWith(langList, LANG_ORIGIN.BROWSER, false);
120+
describe('setCurrentLanguageCode', () => {
121+
beforeEach(() => {
122+
spyOn(service, 'saveLanguageCodeToCookie');
123+
spyOn(translateService, 'use');
124+
});
125+
126+
it('should set the given language', () => {
127+
service.setCurrentLanguageCode('it');
128+
expect(translateService.use).toHaveBeenCalledWith('it');
129+
expect(service.saveLanguageCodeToCookie).toHaveBeenCalledWith('it');
130+
});
131+
132+
it('should set the current language', () => {
133+
spyOn(service, 'getCurrentLanguageCode').and.returnValue('es');
134+
service.setCurrentLanguageCode();
135+
expect(translateService.use).toHaveBeenCalledWith('es');
136+
expect(service.saveLanguageCodeToCookie).toHaveBeenCalledWith('es');
137+
});
138+
139+
it('should set the current language on the html tag', () => {
140+
spyOn(service, 'getCurrentLanguageCode').and.returnValue('es');
141+
service.setCurrentLanguageCode();
142+
expect((service as any).document.documentElement.lang).toEqual('es');
143+
});
144+
145+
describe('should set language on init', () => {
146+
beforeEach(() => {
147+
spyOn(translateService, 'getLangs').and.returnValue(langList);
148+
spyOn(service, 'setCurrentLanguageCode');
149+
});
150+
describe('whith correct lang query param ', () => {
151+
beforeEach(() => {
152+
spyOnGetLanguage.and.returnValue(observableOf('en'));
153+
service.initDefaults();
154+
});
155+
it('should set correct lang', () => {
156+
expect(service.setCurrentLanguageCode).toHaveBeenCalledWith('en');
157+
});
158+
});
159+
describe('whith wrong lang query param ', () => {
160+
beforeEach(() => {
161+
spyOnGetLanguage.and.returnValue(observableOf('abcd'));
162+
service.initDefaults();
163+
});
164+
it('should not set lang', () => {
165+
expect(service.setCurrentLanguageCode).not.toHaveBeenCalled();
166+
});
167+
});
168+
});
142169
});
143170

144-
it('should return the list of language with quality factor', () => {
145-
spyOn(service, 'getLanguageCodeList');
146-
service.getLanguageCodeList();
147-
expect(service.getLanguageCodeList).toHaveBeenCalled();
171+
describe('', () => {
172+
it('should set quality to current language list', () => {
173+
const langListWithQuality = ['en;q=1', 'it;q=0.9', 'de;q=0.8'];
174+
spyOn(service, 'setQuality').and.returnValue(langListWithQuality);
175+
service.setQuality(langList, LANG_ORIGIN.BROWSER, false);
176+
expect(service.setQuality).toHaveBeenCalledWith(langList, LANG_ORIGIN.BROWSER, false);
177+
});
178+
179+
it('should return the list of language with quality factor', () => {
180+
spyOn(service, 'getLanguageCodeList');
181+
service.getLanguageCodeList();
182+
expect(service.getLanguageCodeList).toHaveBeenCalled();
183+
});
148184
});
149185
});
150186
});

src/app/core/locale/locale.service.ts

+12
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,18 @@ export class LocaleService {
4343
protected routeService: RouteService,
4444
@Inject(DOCUMENT) protected document: any
4545
) {
46+
this.initDefaults();
47+
}
48+
49+
/**
50+
* Initialize the language from query params
51+
*/
52+
initDefaults() {
53+
this.routeService.getQueryParameterValue('lang').subscribe(lang => {
54+
if (lang && this.translate.getLangs().includes(lang)) {
55+
this.setCurrentLanguageCode(lang);
56+
}
57+
});
4658
}
4759

4860
/**

src/app/core/metadata/metadata.service.ts

+8-9
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,12 @@ import { TranslateService } from '@ngx-translate/core';
88
import {
99
BehaviorSubject,
1010
combineLatest,
11-
Observable,
12-
of as observableOf,
1311
concat as observableConcat,
14-
EMPTY
12+
EMPTY,
13+
Observable,
14+
of as observableOf
1515
} from 'rxjs';
16-
import { filter, map, switchMap, take, mergeMap } from 'rxjs/operators';
16+
import { filter, map, mergeMap, switchMap, take } from 'rxjs/operators';
1717

1818
import { hasNoValue, hasValue, isNotEmpty } from '../../shared/empty.util';
1919
import { DSONameService } from '../breadcrumbs/dso-name.service';
@@ -25,10 +25,7 @@ import { BitstreamFormat } from '../shared/bitstream-format.model';
2525
import { Bitstream } from '../shared/bitstream.model';
2626
import { DSpaceObject } from '../shared/dspace-object.model';
2727
import { Item } from '../shared/item.model';
28-
import {
29-
getFirstCompletedRemoteData,
30-
getFirstSucceededRemoteDataPayload
31-
} from '../shared/operators';
28+
import { getFirstCompletedRemoteData, getFirstSucceededRemoteDataPayload } from '../shared/operators';
3229
import { RootDataService } from '../data/root-data.service';
3330
import { getBitstreamDownloadRoute } from '../../app-routing-paths';
3431
import { BundleDataService } from '../data/bundle-data.service';
@@ -245,7 +242,9 @@ export class MetadataService {
245242
* Add <meta name="citation_author" ... > to the <head>
246243
*/
247244
private setCitationAuthorTags(): void {
248-
const values: string[] = this.getMetaTagValues(['dc.author', 'dc.contributor.author', 'dc.creator']);
245+
// limit author to first 20 entries to avoid issue with item page rendering
246+
const values: string[] = this.getMetaTagValues(['dc.author', 'dc.contributor.author', 'dc.creator'])
247+
.slice(0, this.appConfig.item.metatagLimit);
249248
this.addMetaTags('citation_author', values);
250249
}
251250

0 commit comments

Comments
 (0)