Skip to content

Commit

Permalink
Merge branch 'dspace-cris-2023_02_x' into main-cris
Browse files Browse the repository at this point in the history
  • Loading branch information
atarix83 committed Mar 29, 2024
2 parents e270018 + 6320a3d commit 53fc9e1
Show file tree
Hide file tree
Showing 32 changed files with 878 additions and 304 deletions.
4 changes: 2 additions & 2 deletions bitbucket-pipelines.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
options:
runs-on: ubuntu-latest
runs-on: self.hosted

definitions:
steps:
Expand All @@ -15,7 +15,7 @@ definitions:
- yarn install --frozen-lockfile
- yarn run lint --quiet
- yarn run check-circ-deps
- yarn run build:prod
- yarn run build:prod:ci
- yarn run test:headless

pipelines:
Expand Down
4 changes: 4 additions & 0 deletions config/config.example.yml
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,10 @@ item:
# Rounded to the nearest size in the list of selectable sizes on the
# settings menu. See pageSizeOptions in 'pagination-component-options.model.ts'.
pageSize: 5
# The maximum number of metadata values to add to the metatag list of the item page
metatagLimit: 20
# The maximum number of values for repeatable metadata to show in the full item
metadataLimit: 20

# When the search results are retrieved, for each item type the metadata with a valid authority value are inspected.
# Referenced items will be fetched with a find all by id strategy to avoid individual rest requests
Expand Down
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,11 @@
"build:stats": "ng build --stats-json",
"build:ci": "ng config cli.cache.environment ci && yarn run build:ssr",
"build:prod": "cross-env NODE_ENV=production yarn run build:ssr",
"build:prod:ci": "cross-env NODE_ENV=production yarn run build:ssr:ci",
"build:ssr": "npm run ng-high-memory -- build --configuration production && npm run ng-high-memory -- run dspace-angular:server:production",
"build:ssr:ci": "npm run ng-mid-memory -- build --configuration production && npm run ng-mid-memory -- run dspace-angular:server:production",
"ng-high-memory": "node --max-old-space-size=8192 node_modules/@angular/cli/bin/ng",
"ng-mid-memory": "node --max-old-space-size=4096 node_modules/@angular/cli/bin/ng",
"test": "npm run ng-high-memory -- test --source-map=true --watch=false --configuration test",
"test:watch": "nodemon --exec \"npm run ng-high-memory -- test --source-map=true --watch=true --configuration test\"",
"test:headless": "npm run ng-high-memory -- test --source-map=true --watch=false --configuration test --browsers=ChromeHeadless --code-coverage",
Expand Down Expand Up @@ -140,7 +143,6 @@
"ng2-nouislider": "^2.0.0",
"ngx-infinite-scroll": "^15.0.0",
"ngx-pagination": "6.0.3",
"ngx-sortablejs": "^11.1.0",
"ngx-ui-switch": "^14.0.3",
"nouislider": "^15.7.1",
"pem": "1.14.7",
Expand All @@ -149,7 +151,6 @@
"reflect-metadata": "^0.1.13",
"rxjs": "^7.8.0",
"sanitize-html": "^2.10.0",
"sortablejs": "1.15.0",
"uuid": "^8.3.2",
"webfontloader": "1.6.28",
"zone.js": "~0.11.5"
Expand Down
242 changes: 139 additions & 103 deletions src/app/core/locale/locale.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { AuthService } from '../auth/auth.service';
import { NativeWindowRef } from '../services/window.service';
import { RouteService } from '../services/route.service';
import { routeServiceStub } from '../../shared/testing/route-service.stub';
import { of as observableOf } from 'rxjs';

describe('LocaleService test suite', () => {
let service: LocaleService;
Expand All @@ -22,129 +23,164 @@ describe('LocaleService test suite', () => {
let authService;
let routeService;
let document;
let spyOnGetLanguage;


const translateServiceStub: any = {
getLangs: () => {
return langList;
},
getBrowserLang: () => {
return langList;
},
// eslint-disable-next-line @typescript-eslint/no-empty-function
use: (param: string) => {
}
};

authService = jasmine.createSpyObj('AuthService', {
isAuthenticated: jasmine.createSpy('isAuthenticated'),
isAuthenticationLoaded: jasmine.createSpy('isAuthenticationLoaded')
});

const langList = ['en', 'xx', 'de'];

beforeEach(waitForAsync(() => {
return TestBed.configureTestingModule({
imports: [
TranslateModule.forRoot({
loader: {
provide: TranslateLoader,
useClass: TranslateLoaderMock
}
}),
],
providers: [
{ provide: CookieService, useValue: new CookieServiceMock() },
{ provide: AuthService, userValue: authService },
{ provide: RouteService, useValue: routeServiceStub },
{ provide: Document, useValue: document },
]
});
}));

beforeEach(() => {
cookieService = TestBed.inject(CookieService);
translateService = TestBed.inject(TranslateService);
routeService = TestBed.inject(RouteService);
window = new NativeWindowRef();
document = { documentElement: { lang: 'en' } };
service = new LocaleService(window, cookieService, translateService, authService, routeService, document);
serviceAsAny = service;
spyOnGet = spyOn(cookieService, 'get');
spyOnSet = spyOn(cookieService, 'set');
});
describe('with valid language', () => {

beforeEach(waitForAsync(() => {
return TestBed.configureTestingModule({
imports: [
TranslateModule.forRoot({
loader: {
provide: TranslateLoader,
useClass: TranslateLoaderMock
}
}),
],
providers: [
{ provide: CookieService, useValue: new CookieServiceMock() },
{ provide: AuthService, userValue: authService },
{ provide: RouteService, useValue: routeServiceStub },
{ provide: TranslateService, useValue: translateServiceStub },
{ provide: Document, useValue: document },
]
});
}));

describe('getCurrentLanguageCode', () => {
beforeEach(() => {
spyOn(translateService, 'getLangs').and.returnValue(langList);
});

it('should return the language saved on cookie if it\'s a valid & active language', () => {
spyOnGet.and.returnValue('de');
expect(service.getCurrentLanguageCode()).toBe('de');
});

it('should return the default language if the cookie language is disabled', () => {
spyOnGet.and.returnValue('disabled');
expect(service.getCurrentLanguageCode()).toBe('en');
});

it('should return the default language if the cookie language does not exist', () => {
spyOnGet.and.returnValue('does-not-exist');
expect(service.getCurrentLanguageCode()).toBe('en');
});

it('should return language from browser setting', () => {
spyOn(translateService, 'getBrowserLang').and.returnValue('xx');
expect(service.getCurrentLanguageCode()).toBe('xx');
cookieService = TestBed.inject(CookieService);
translateService = TestBed.inject(TranslateService);
routeService = TestBed.inject(RouteService);
window = new NativeWindowRef();
document = { documentElement: { lang: 'en' } };
service = new LocaleService(window, cookieService, translateService, authService, routeService, document);
serviceAsAny = service;
spyOnGet = spyOn(cookieService, 'get');
spyOnSet = spyOn(cookieService, 'set');
spyOnGetLanguage = spyOn(routeService, 'getQueryParameterValue').withArgs('lang');
});

it('should return default language from config', () => {
spyOn(translateService, 'getBrowserLang').and.returnValue('fr');
expect(service.getCurrentLanguageCode()).toBe('en');
});
});

describe('getLanguageCodeFromCookie', () => {
it('should return language from cookie', () => {
spyOnGet.and.returnValue('de');
expect(service.getLanguageCodeFromCookie()).toBe('de');
describe('getCurrentLanguageCode', () => {
it('should return language saved on cookie', () => {
spyOnGet.and.returnValue('de');
expect(service.getCurrentLanguageCode()).toBe('de');
});

describe('', () => {
beforeEach(() => {
spyOn(translateService, 'getLangs').and.returnValue(langList);
});

it('should return language from browser setting', () => {
spyOn(translateService, 'getBrowserLang').and.returnValue('xx');
expect(service.getCurrentLanguageCode()).toBe('xx');
});

it('should return default language from config', () => {
spyOn(translateService, 'getBrowserLang').and.returnValue('fr');
expect(service.getCurrentLanguageCode()).toBe('en');
});
});
});

});
describe('getLanguageCodeFromCookie', () => {
it('should return language from cookie', () => {
spyOnGet.and.returnValue('de');
expect(service.getLanguageCodeFromCookie()).toBe('de');
});

describe('saveLanguageCodeToCookie', () => {
it('should save language to cookie', () => {
service.saveLanguageCodeToCookie('en');
expect(spyOnSet).toHaveBeenCalledWith(LANG_COOKIE, 'en');
});
});

describe('setCurrentLanguageCode', () => {
beforeEach(() => {
spyOn(service, 'saveLanguageCodeToCookie');
spyOn(translateService, 'use');
describe('saveLanguageCodeToCookie', () => {
it('should save language to cookie', () => {
service.saveLanguageCodeToCookie('en');
expect(spyOnSet).toHaveBeenCalledWith(LANG_COOKIE, 'en');
});
});

it('should set the given language', () => {
service.setCurrentLanguageCode('xx');
expect(translateService.use).toHaveBeenCalledWith('xx');
expect(service.saveLanguageCodeToCookie).toHaveBeenCalledWith('xx');
});

it('should set the current language', () => {
spyOn(service, 'getCurrentLanguageCode').and.returnValue('es');
service.setCurrentLanguageCode();
expect(translateService.use).toHaveBeenCalledWith('es');
expect(service.saveLanguageCodeToCookie).toHaveBeenCalledWith('es');
});

it('should set the current language on the html tag', () => {
spyOn(service, 'getCurrentLanguageCode').and.returnValue('es');
service.setCurrentLanguageCode();
expect((service as any).document.documentElement.lang).toEqual('es');
});
});

describe('', () => {
it('should set quality to current language list', () => {
const langListWithQuality = ['en;q=1', 'xx;q=0.9', 'de;q=0.8'];
spyOn(service, 'setQuality').and.returnValue(langListWithQuality);
service.setQuality(langList, LANG_ORIGIN.BROWSER, false);
expect(service.setQuality).toHaveBeenCalledWith(langList, LANG_ORIGIN.BROWSER, false);
describe('setCurrentLanguageCode', () => {
beforeEach(() => {
spyOn(service, 'saveLanguageCodeToCookie');
spyOn(translateService, 'use');
});

it('should set the given language', () => {
service.setCurrentLanguageCode('it');
expect(translateService.use).toHaveBeenCalledWith('it');
expect(service.saveLanguageCodeToCookie).toHaveBeenCalledWith('it');
});

it('should set the current language', () => {
spyOn(service, 'getCurrentLanguageCode').and.returnValue('es');
service.setCurrentLanguageCode();
expect(translateService.use).toHaveBeenCalledWith('es');
expect(service.saveLanguageCodeToCookie).toHaveBeenCalledWith('es');
});

it('should set the current language on the html tag', () => {
spyOn(service, 'getCurrentLanguageCode').and.returnValue('es');
service.setCurrentLanguageCode();
expect((service as any).document.documentElement.lang).toEqual('es');
});

describe('should set language on init', () => {
beforeEach(() => {
spyOn(translateService, 'getLangs').and.returnValue(langList);
spyOn(service, 'setCurrentLanguageCode');
});
describe('whith correct lang query param ', () => {
beforeEach(() => {
spyOnGetLanguage.and.returnValue(observableOf('en'));
service.initDefaults();
});
it('should set correct lang', () => {
expect(service.setCurrentLanguageCode).toHaveBeenCalledWith('en');
});
});
describe('whith wrong lang query param ', () => {
beforeEach(() => {
spyOnGetLanguage.and.returnValue(observableOf('abcd'));
service.initDefaults();
});
it('should not set lang', () => {
expect(service.setCurrentLanguageCode).not.toHaveBeenCalled();
});
});
});
});

it('should return the list of language with quality factor', () => {
spyOn(service, 'getLanguageCodeList');
service.getLanguageCodeList();
expect(service.getLanguageCodeList).toHaveBeenCalled();
describe('', () => {
it('should set quality to current language list', () => {
const langListWithQuality = ['en;q=1', 'it;q=0.9', 'de;q=0.8'];
spyOn(service, 'setQuality').and.returnValue(langListWithQuality);
service.setQuality(langList, LANG_ORIGIN.BROWSER, false);
expect(service.setQuality).toHaveBeenCalledWith(langList, LANG_ORIGIN.BROWSER, false);
});

it('should return the list of language with quality factor', () => {
spyOn(service, 'getLanguageCodeList');
service.getLanguageCodeList();
expect(service.getLanguageCodeList).toHaveBeenCalled();
});
});
});
});
12 changes: 12 additions & 0 deletions src/app/core/locale/locale.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,18 @@ export class LocaleService {
protected routeService: RouteService,
@Inject(DOCUMENT) protected document: any
) {
this.initDefaults();
}

/**
* Initialize the language from query params
*/
initDefaults() {
this.routeService.getQueryParameterValue('lang').subscribe(lang => {
if (lang && this.translate.getLangs().includes(lang)) {
this.setCurrentLanguageCode(lang);
}
});
}

/**
Expand Down
17 changes: 8 additions & 9 deletions src/app/core/metadata/metadata.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@ import { TranslateService } from '@ngx-translate/core';
import {
BehaviorSubject,
combineLatest,
Observable,
of as observableOf,
concat as observableConcat,
EMPTY
EMPTY,
Observable,
of as observableOf
} from 'rxjs';
import { filter, map, switchMap, take, mergeMap } from 'rxjs/operators';
import { filter, map, mergeMap, switchMap, take } from 'rxjs/operators';

import { hasNoValue, hasValue, isNotEmpty } from '../../shared/empty.util';
import { DSONameService } from '../breadcrumbs/dso-name.service';
Expand All @@ -25,10 +25,7 @@ import { BitstreamFormat } from '../shared/bitstream-format.model';
import { Bitstream } from '../shared/bitstream.model';
import { DSpaceObject } from '../shared/dspace-object.model';
import { Item } from '../shared/item.model';
import {
getFirstCompletedRemoteData,
getFirstSucceededRemoteDataPayload
} from '../shared/operators';
import { getFirstCompletedRemoteData, getFirstSucceededRemoteDataPayload } from '../shared/operators';
import { RootDataService } from '../data/root-data.service';
import { getBitstreamDownloadRoute } from '../../app-routing-paths';
import { BundleDataService } from '../data/bundle-data.service';
Expand Down Expand Up @@ -245,7 +242,9 @@ export class MetadataService {
* Add <meta name="citation_author" ... > to the <head>
*/
private setCitationAuthorTags(): void {
const values: string[] = this.getMetaTagValues(['dc.author', 'dc.contributor.author', 'dc.creator']);
// limit author to first 20 entries to avoid issue with item page rendering
const values: string[] = this.getMetaTagValues(['dc.author', 'dc.contributor.author', 'dc.creator'])
.slice(0, this.appConfig.item.metatagLimit);
this.addMetaTags('citation_author', values);
}

Expand Down
Loading

0 comments on commit 53fc9e1

Please sign in to comment.