mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-07 10:04:11 +00:00
Merge remote-tracking branch 'upstream/main' into w2p-98211_advanced-workflow-actions-main
# Conflicts: # src/app/shared/shared.module.ts
This commit is contained in:
@@ -30,8 +30,9 @@
|
|||||||
"clean:log": "rimraf *.log*",
|
"clean:log": "rimraf *.log*",
|
||||||
"clean:json": "rimraf *.records.json",
|
"clean:json": "rimraf *.records.json",
|
||||||
"clean:node": "rimraf node_modules",
|
"clean:node": "rimraf node_modules",
|
||||||
|
"clean:cli": "rimraf .angular/cache",
|
||||||
"clean:prod": "yarn run clean:dist && yarn run clean:log && yarn run clean:doc && yarn run clean:coverage && yarn run clean:json",
|
"clean:prod": "yarn run clean:dist && yarn run clean:log && yarn run clean:doc && yarn run clean:coverage && yarn run clean:json",
|
||||||
"clean": "yarn run clean:prod && yarn run clean:dev:config && yarn run clean:node",
|
"clean": "yarn run clean:prod && yarn run clean:dev:config && yarn run clean:cli && yarn run clean:node",
|
||||||
"sync-i18n": "ts-node --project ./tsconfig.ts-node.json scripts/sync-i18n-files.ts",
|
"sync-i18n": "ts-node --project ./tsconfig.ts-node.json scripts/sync-i18n-files.ts",
|
||||||
"build:mirador": "webpack --config webpack/webpack.mirador.config.ts",
|
"build:mirador": "webpack --config webpack/webpack.mirador.config.ts",
|
||||||
"merge-i18n": "ts-node --project ./tsconfig.ts-node.json scripts/merge-i18n-files.ts",
|
"merge-i18n": "ts-node --project ./tsconfig.ts-node.json scripts/merge-i18n-files.ts",
|
||||||
|
@@ -196,7 +196,24 @@ export class AuthInterceptor implements HttpInterceptor {
|
|||||||
authStatus.token = new AuthTokenInfo(accessToken);
|
authStatus.token = new AuthTokenInfo(accessToken);
|
||||||
} else {
|
} else {
|
||||||
authStatus.authenticated = false;
|
authStatus.authenticated = false;
|
||||||
authStatus.error = isNotEmpty(error) ? ((typeof error === 'string') ? JSON.parse(error) : error) : null;
|
if (isNotEmpty(error)) {
|
||||||
|
if (typeof error === 'string') {
|
||||||
|
try {
|
||||||
|
authStatus.error = JSON.parse(error);
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Unknown auth error "', error, '" caused ', e);
|
||||||
|
authStatus.error = {
|
||||||
|
error: 'Unknown',
|
||||||
|
message: 'Unknown auth error',
|
||||||
|
status: 500,
|
||||||
|
timestamp: Date.now(),
|
||||||
|
path: ''
|
||||||
|
};
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
authStatus.error = error;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return authStatus;
|
return authStatus;
|
||||||
}
|
}
|
||||||
|
@@ -2,6 +2,7 @@ import { Injectable } from '@angular/core';
|
|||||||
import { hasValue, isEmpty } from '../../shared/empty.util';
|
import { hasValue, isEmpty } from '../../shared/empty.util';
|
||||||
import { DSpaceObject } from '../shared/dspace-object.model';
|
import { DSpaceObject } from '../shared/dspace-object.model';
|
||||||
import { TranslateService } from '@ngx-translate/core';
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
|
import { Metadata } from '../shared/metadata.utils';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a name for a {@link DSpaceObject} based
|
* Returns a name for a {@link DSpaceObject} based
|
||||||
@@ -67,4 +68,45 @@ export class DSONameService {
|
|||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the Hit highlight
|
||||||
|
*
|
||||||
|
* @param object
|
||||||
|
* @param dso
|
||||||
|
*
|
||||||
|
* @returns {string} html embedded hit highlight.
|
||||||
|
*/
|
||||||
|
getHitHighlights(object: any, dso: DSpaceObject): string {
|
||||||
|
const types = dso.getRenderTypes();
|
||||||
|
const entityType = types
|
||||||
|
.filter((type) => typeof type === 'string')
|
||||||
|
.find((type: string) => (['Person', 'OrgUnit']).includes(type)) as string;
|
||||||
|
if (entityType === 'Person') {
|
||||||
|
const familyName = this.firstMetadataValue(object, dso, 'person.familyName');
|
||||||
|
const givenName = this.firstMetadataValue(object, dso, 'person.givenName');
|
||||||
|
if (isEmpty(familyName) && isEmpty(givenName)) {
|
||||||
|
return this.firstMetadataValue(object, dso, 'dc.title') || dso.name;
|
||||||
|
} else if (isEmpty(familyName) || isEmpty(givenName)) {
|
||||||
|
return familyName || givenName;
|
||||||
|
}
|
||||||
|
return `${familyName}, ${givenName}`;
|
||||||
|
} else if (entityType === 'OrgUnit') {
|
||||||
|
return this.firstMetadataValue(object, dso, 'organization.legalName');
|
||||||
|
}
|
||||||
|
return this.firstMetadataValue(object, dso, 'dc.title') || dso.name || this.translateService.instant('dso.name.untitled');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the first matching metadata string value from hitHighlights or dso metadata, preferring hitHighlights.
|
||||||
|
*
|
||||||
|
* @param object
|
||||||
|
* @param dso
|
||||||
|
* @param {string|string[]} keyOrKeys The metadata key(s) in scope. Wildcards are supported; see [[Metadata]].
|
||||||
|
*
|
||||||
|
* @returns {string} the first matching string value, or `undefined`.
|
||||||
|
*/
|
||||||
|
firstMetadataValue(object: any, dso: DSpaceObject, keyOrKeys: string | string[]): string {
|
||||||
|
return Metadata.firstValue([object.hitHighlights, dso.metadata], keyOrKeys);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -61,7 +61,7 @@ export class OrgUnitSearchResultListSubmissionElementComponent extends SearchRes
|
|||||||
this.useNameVariants = this.context === Context.EntitySearchModalWithNameVariants;
|
this.useNameVariants = this.context === Context.EntitySearchModalWithNameVariants;
|
||||||
|
|
||||||
if (this.useNameVariants) {
|
if (this.useNameVariants) {
|
||||||
const defaultValue = this.dsoTitle;
|
const defaultValue = this.dso ? this.dsoNameService.getName(this.dso) : undefined;
|
||||||
const alternatives = this.allMetadataValues(this.alternativeField);
|
const alternatives = this.allMetadataValues(this.alternativeField);
|
||||||
this.allSuggestions = [defaultValue, ...alternatives];
|
this.allSuggestions = [defaultValue, ...alternatives];
|
||||||
|
|
||||||
|
@@ -55,7 +55,7 @@ export class PersonSearchResultListSubmissionElementComponent extends SearchResu
|
|||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
super.ngOnInit();
|
super.ngOnInit();
|
||||||
const defaultValue = this.dsoTitle;
|
const defaultValue = this.dso ? this.dsoNameService.getName(this.dso) : undefined;
|
||||||
const alternatives = this.allMetadataValues(this.alternativeField);
|
const alternatives = this.allMetadataValues(this.alternativeField);
|
||||||
this.allSuggestions = [defaultValue, ...alternatives];
|
this.allSuggestions = [defaultValue, ...alternatives];
|
||||||
|
|
||||||
|
@@ -0,0 +1,3 @@
|
|||||||
|
<button class="btn btn-lg btn-primary btn-block mt-2 text-white" (click)="redirectToExternalProvider()">
|
||||||
|
<i class="fas fa-sign-in-alt"></i> {{getButtonLabel() | translate}}
|
||||||
|
</button>
|
@@ -14,18 +14,17 @@ import { AuthServiceStub } from '../../../testing/auth-service.stub';
|
|||||||
import { storeModuleConfig } from '../../../../app.reducer';
|
import { storeModuleConfig } from '../../../../app.reducer';
|
||||||
import { AuthMethod } from '../../../../core/auth/models/auth.method';
|
import { AuthMethod } from '../../../../core/auth/models/auth.method';
|
||||||
import { AuthMethodType } from '../../../../core/auth/models/auth.method-type';
|
import { AuthMethodType } from '../../../../core/auth/models/auth.method-type';
|
||||||
import { LogInOrcidComponent } from './log-in-orcid.component';
|
import { LogInExternalProviderComponent } from './log-in-external-provider.component';
|
||||||
import { NativeWindowService } from '../../../../core/services/window.service';
|
import { NativeWindowService } from '../../../../core/services/window.service';
|
||||||
import { RouterStub } from '../../../testing/router.stub';
|
import { RouterStub } from '../../../testing/router.stub';
|
||||||
import { ActivatedRouteStub } from '../../../testing/active-router.stub';
|
import { ActivatedRouteStub } from '../../../testing/active-router.stub';
|
||||||
import { NativeWindowMockFactory } from '../../../mocks/mock-native-window-ref';
|
import { NativeWindowMockFactory } from '../../../mocks/mock-native-window-ref';
|
||||||
import { HardRedirectService } from '../../../../core/services/hard-redirect.service';
|
import { HardRedirectService } from '../../../../core/services/hard-redirect.service';
|
||||||
|
|
||||||
|
describe('LogInExternalProviderComponent', () => {
|
||||||
|
|
||||||
describe('LogInOrcidComponent', () => {
|
let component: LogInExternalProviderComponent;
|
||||||
|
let fixture: ComponentFixture<LogInExternalProviderComponent>;
|
||||||
let component: LogInOrcidComponent;
|
|
||||||
let fixture: ComponentFixture<LogInOrcidComponent>;
|
|
||||||
let page: Page;
|
let page: Page;
|
||||||
let user: EPerson;
|
let user: EPerson;
|
||||||
let componentAsAny: any;
|
let componentAsAny: any;
|
||||||
@@ -66,7 +65,7 @@ describe('LogInOrcidComponent', () => {
|
|||||||
TranslateModule.forRoot()
|
TranslateModule.forRoot()
|
||||||
],
|
],
|
||||||
declarations: [
|
declarations: [
|
||||||
LogInOrcidComponent
|
LogInExternalProviderComponent
|
||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
{ provide: AuthService, useClass: AuthServiceStub },
|
{ provide: AuthService, useClass: AuthServiceStub },
|
||||||
@@ -88,7 +87,7 @@ describe('LogInOrcidComponent', () => {
|
|||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
// create component and test fixture
|
// create component and test fixture
|
||||||
fixture = TestBed.createComponent(LogInOrcidComponent);
|
fixture = TestBed.createComponent(LogInExternalProviderComponent);
|
||||||
|
|
||||||
// get test component from the fixture
|
// get test component from the fixture
|
||||||
component = fixture.componentInstance;
|
component = fixture.componentInstance;
|
||||||
@@ -109,7 +108,7 @@ describe('LogInOrcidComponent', () => {
|
|||||||
expect(componentAsAny.injectedAuthMethodModel.location).toBe(location);
|
expect(componentAsAny.injectedAuthMethodModel.location).toBe(location);
|
||||||
expect(componentAsAny._window.nativeWindow.location.href).toBe(currentUrl);
|
expect(componentAsAny._window.nativeWindow.location.href).toBe(currentUrl);
|
||||||
|
|
||||||
component.redirectToOrcid();
|
component.redirectToExternalProvider();
|
||||||
|
|
||||||
expect(setHrefSpy).toHaveBeenCalledWith(currentUrl);
|
expect(setHrefSpy).toHaveBeenCalledWith(currentUrl);
|
||||||
|
|
||||||
@@ -124,7 +123,7 @@ describe('LogInOrcidComponent', () => {
|
|||||||
expect(componentAsAny.injectedAuthMethodModel.location).toBe(location);
|
expect(componentAsAny.injectedAuthMethodModel.location).toBe(location);
|
||||||
expect(componentAsAny._window.nativeWindow.location.href).toBe(currentUrl);
|
expect(componentAsAny._window.nativeWindow.location.href).toBe(currentUrl);
|
||||||
|
|
||||||
component.redirectToOrcid();
|
component.redirectToExternalProvider();
|
||||||
|
|
||||||
expect(setHrefSpy).toHaveBeenCalledWith(currentUrl);
|
expect(setHrefSpy).toHaveBeenCalledWith(currentUrl);
|
||||||
|
|
||||||
@@ -143,7 +142,7 @@ class Page {
|
|||||||
public navigateSpy: jasmine.Spy;
|
public navigateSpy: jasmine.Spy;
|
||||||
public passwordInput: HTMLInputElement;
|
public passwordInput: HTMLInputElement;
|
||||||
|
|
||||||
constructor(private component: LogInOrcidComponent, private fixture: ComponentFixture<LogInOrcidComponent>) {
|
constructor(private component: LogInExternalProviderComponent, private fixture: ComponentFixture<LogInExternalProviderComponent>) {
|
||||||
// use injector to get services
|
// use injector to get services
|
||||||
const injector = fixture.debugElement.injector;
|
const injector = fixture.debugElement.injector;
|
||||||
const store = injector.get(Store);
|
const store = injector.get(Store);
|
@@ -4,22 +4,27 @@ import { Observable } from 'rxjs';
|
|||||||
import { take } from 'rxjs/operators';
|
import { take } from 'rxjs/operators';
|
||||||
import { select, Store } from '@ngrx/store';
|
import { select, Store } from '@ngrx/store';
|
||||||
|
|
||||||
import { AuthMethod } from '../../../core/auth/models/auth.method';
|
import { AuthMethod } from '../../../../core/auth/models/auth.method';
|
||||||
|
|
||||||
import { isAuthenticated, isAuthenticationLoading } from '../../../core/auth/selectors';
|
import { isAuthenticated, isAuthenticationLoading } from '../../../../core/auth/selectors';
|
||||||
import { NativeWindowRef, NativeWindowService } from '../../../core/services/window.service';
|
import { NativeWindowRef, NativeWindowService } from '../../../../core/services/window.service';
|
||||||
import { isEmpty, isNotNull } from '../../empty.util';
|
import { isEmpty, isNotNull } from '../../../empty.util';
|
||||||
import { AuthService } from '../../../core/auth/auth.service';
|
import { AuthService } from '../../../../core/auth/auth.service';
|
||||||
import { HardRedirectService } from '../../../core/services/hard-redirect.service';
|
import { HardRedirectService } from '../../../../core/services/hard-redirect.service';
|
||||||
import { URLCombiner } from '../../../core/url-combiner/url-combiner';
|
import { URLCombiner } from '../../../../core/url-combiner/url-combiner';
|
||||||
import { CoreState } from '../../../core/core-state.model';
|
import { CoreState } from '../../../../core/core-state.model';
|
||||||
|
import { renderAuthMethodFor } from '../log-in.methods-decorator';
|
||||||
|
import { AuthMethodType } from '../../../../core/auth/models/auth.method-type';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'ds-log-in-external-provider',
|
selector: 'ds-log-in-external-provider',
|
||||||
template: ''
|
templateUrl: './log-in-external-provider.component.html',
|
||||||
|
styleUrls: ['./log-in-external-provider.component.scss']
|
||||||
})
|
})
|
||||||
export abstract class LogInExternalProviderComponent implements OnInit {
|
@renderAuthMethodFor(AuthMethodType.Oidc)
|
||||||
|
@renderAuthMethodFor(AuthMethodType.Shibboleth)
|
||||||
|
@renderAuthMethodFor(AuthMethodType.Orcid)
|
||||||
|
export class LogInExternalProviderComponent implements OnInit {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The authentication method data.
|
* The authentication method data.
|
||||||
@@ -107,4 +112,7 @@ export abstract class LogInExternalProviderComponent implements OnInit {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getButtonLabel() {
|
||||||
|
return `login.form.${this.authMethod.authMethodType}`;
|
||||||
|
}
|
||||||
}
|
}
|
@@ -1,3 +0,0 @@
|
|||||||
<button class="btn btn-lg btn-primary btn-block mt-2 text-white" (click)="redirectToOidc()">
|
|
||||||
<i class="fas fa-sign-in-alt"></i> {{"login.form.oidc" | translate}}
|
|
||||||
</button>
|
|
@@ -1,155 +0,0 @@
|
|||||||
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
|
|
||||||
import { ActivatedRoute, Router } from '@angular/router';
|
|
||||||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
|
||||||
|
|
||||||
import { provideMockStore } from '@ngrx/store/testing';
|
|
||||||
import { Store, StoreModule } from '@ngrx/store';
|
|
||||||
import { TranslateModule } from '@ngx-translate/core';
|
|
||||||
|
|
||||||
import { EPerson } from '../../../../core/eperson/models/eperson.model';
|
|
||||||
import { EPersonMock } from '../../../testing/eperson.mock';
|
|
||||||
import { authReducer } from '../../../../core/auth/auth.reducer';
|
|
||||||
import { AuthService } from '../../../../core/auth/auth.service';
|
|
||||||
import { AuthServiceStub } from '../../../testing/auth-service.stub';
|
|
||||||
import { storeModuleConfig } from '../../../../app.reducer';
|
|
||||||
import { AuthMethod } from '../../../../core/auth/models/auth.method';
|
|
||||||
import { AuthMethodType } from '../../../../core/auth/models/auth.method-type';
|
|
||||||
import { LogInOidcComponent } from './log-in-oidc.component';
|
|
||||||
import { NativeWindowService } from '../../../../core/services/window.service';
|
|
||||||
import { RouterStub } from '../../../testing/router.stub';
|
|
||||||
import { ActivatedRouteStub } from '../../../testing/active-router.stub';
|
|
||||||
import { NativeWindowMockFactory } from '../../../mocks/mock-native-window-ref';
|
|
||||||
import { HardRedirectService } from '../../../../core/services/hard-redirect.service';
|
|
||||||
|
|
||||||
|
|
||||||
describe('LogInOidcComponent', () => {
|
|
||||||
|
|
||||||
let component: LogInOidcComponent;
|
|
||||||
let fixture: ComponentFixture<LogInOidcComponent>;
|
|
||||||
let page: Page;
|
|
||||||
let user: EPerson;
|
|
||||||
let componentAsAny: any;
|
|
||||||
let setHrefSpy;
|
|
||||||
let oidcBaseUrl;
|
|
||||||
let location;
|
|
||||||
let initialState: any;
|
|
||||||
let hardRedirectService: HardRedirectService;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
user = EPersonMock;
|
|
||||||
oidcBaseUrl = 'dspace-rest.test/oidc?redirectUrl=';
|
|
||||||
location = oidcBaseUrl + 'http://dspace-angular.test/home';
|
|
||||||
|
|
||||||
hardRedirectService = jasmine.createSpyObj('hardRedirectService', {
|
|
||||||
getCurrentRoute: {},
|
|
||||||
redirect: {}
|
|
||||||
});
|
|
||||||
|
|
||||||
initialState = {
|
|
||||||
core: {
|
|
||||||
auth: {
|
|
||||||
authenticated: false,
|
|
||||||
loaded: false,
|
|
||||||
blocking: false,
|
|
||||||
loading: false,
|
|
||||||
authMethods: []
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
beforeEach(waitForAsync(() => {
|
|
||||||
// refine the test module by declaring the test component
|
|
||||||
TestBed.configureTestingModule({
|
|
||||||
imports: [
|
|
||||||
StoreModule.forRoot({ auth: authReducer }, storeModuleConfig),
|
|
||||||
TranslateModule.forRoot()
|
|
||||||
],
|
|
||||||
declarations: [
|
|
||||||
LogInOidcComponent
|
|
||||||
],
|
|
||||||
providers: [
|
|
||||||
{ provide: AuthService, useClass: AuthServiceStub },
|
|
||||||
{ provide: 'authMethodProvider', useValue: new AuthMethod(AuthMethodType.Oidc, location) },
|
|
||||||
{ provide: 'isStandalonePage', useValue: true },
|
|
||||||
{ provide: NativeWindowService, useFactory: NativeWindowMockFactory },
|
|
||||||
{ provide: Router, useValue: new RouterStub() },
|
|
||||||
{ provide: ActivatedRoute, useValue: new ActivatedRouteStub() },
|
|
||||||
{ provide: HardRedirectService, useValue: hardRedirectService },
|
|
||||||
provideMockStore({ initialState }),
|
|
||||||
],
|
|
||||||
schemas: [
|
|
||||||
CUSTOM_ELEMENTS_SCHEMA
|
|
||||||
]
|
|
||||||
})
|
|
||||||
.compileComponents();
|
|
||||||
|
|
||||||
}));
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
// create component and test fixture
|
|
||||||
fixture = TestBed.createComponent(LogInOidcComponent);
|
|
||||||
|
|
||||||
// get test component from the fixture
|
|
||||||
component = fixture.componentInstance;
|
|
||||||
componentAsAny = component;
|
|
||||||
|
|
||||||
// create page
|
|
||||||
page = new Page(component, fixture);
|
|
||||||
setHrefSpy = spyOnProperty(componentAsAny._window.nativeWindow.location, 'href', 'set').and.callThrough();
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should set the properly a new redirectUrl', () => {
|
|
||||||
const currentUrl = 'http://dspace-angular.test/collections/12345';
|
|
||||||
componentAsAny._window.nativeWindow.location.href = currentUrl;
|
|
||||||
|
|
||||||
fixture.detectChanges();
|
|
||||||
|
|
||||||
expect(componentAsAny.injectedAuthMethodModel.location).toBe(location);
|
|
||||||
expect(componentAsAny._window.nativeWindow.location.href).toBe(currentUrl);
|
|
||||||
|
|
||||||
component.redirectToOidc();
|
|
||||||
|
|
||||||
expect(setHrefSpy).toHaveBeenCalledWith(currentUrl);
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should not set a new redirectUrl', () => {
|
|
||||||
const currentUrl = 'http://dspace-angular.test/home';
|
|
||||||
componentAsAny._window.nativeWindow.location.href = currentUrl;
|
|
||||||
|
|
||||||
fixture.detectChanges();
|
|
||||||
|
|
||||||
expect(componentAsAny.injectedAuthMethodModel.location).toBe(location);
|
|
||||||
expect(componentAsAny._window.nativeWindow.location.href).toBe(currentUrl);
|
|
||||||
|
|
||||||
component.redirectToOidc();
|
|
||||||
|
|
||||||
expect(setHrefSpy).toHaveBeenCalledWith(currentUrl);
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* I represent the DOM elements and attach spies.
|
|
||||||
*
|
|
||||||
* @class Page
|
|
||||||
*/
|
|
||||||
class Page {
|
|
||||||
|
|
||||||
public emailInput: HTMLInputElement;
|
|
||||||
public navigateSpy: jasmine.Spy;
|
|
||||||
public passwordInput: HTMLInputElement;
|
|
||||||
|
|
||||||
constructor(private component: LogInOidcComponent, private fixture: ComponentFixture<LogInOidcComponent>) {
|
|
||||||
// use injector to get services
|
|
||||||
const injector = fixture.debugElement.injector;
|
|
||||||
const store = injector.get(Store);
|
|
||||||
|
|
||||||
// add spies
|
|
||||||
this.navigateSpy = spyOn(store, 'dispatch');
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@@ -1,21 +0,0 @@
|
|||||||
import { Component, } from '@angular/core';
|
|
||||||
|
|
||||||
import { renderAuthMethodFor } from '../log-in.methods-decorator';
|
|
||||||
import { AuthMethodType } from '../../../../core/auth/models/auth.method-type';
|
|
||||||
import { LogInExternalProviderComponent } from '../log-in-external-provider.component';
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'ds-log-in-oidc',
|
|
||||||
templateUrl: './log-in-oidc.component.html',
|
|
||||||
})
|
|
||||||
@renderAuthMethodFor(AuthMethodType.Oidc)
|
|
||||||
export class LogInOidcComponent extends LogInExternalProviderComponent {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Redirect to orcid authentication url
|
|
||||||
*/
|
|
||||||
redirectToOidc() {
|
|
||||||
this.redirectToExternalProvider();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@@ -1,3 +0,0 @@
|
|||||||
<button class="btn btn-lg btn-primary btn-block mt-2 text-white" (click)="redirectToOrcid()">
|
|
||||||
<i class="fas fa-sign-in-alt"></i> {{"login.form.orcid" | translate}}
|
|
||||||
</button>
|
|
@@ -1,21 +0,0 @@
|
|||||||
import { Component, } from '@angular/core';
|
|
||||||
|
|
||||||
import { renderAuthMethodFor } from '../log-in.methods-decorator';
|
|
||||||
import { AuthMethodType } from '../../../../core/auth/models/auth.method-type';
|
|
||||||
import { LogInExternalProviderComponent } from '../log-in-external-provider.component';
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'ds-log-in-orcid',
|
|
||||||
templateUrl: './log-in-orcid.component.html',
|
|
||||||
})
|
|
||||||
@renderAuthMethodFor(AuthMethodType.Orcid)
|
|
||||||
export class LogInOrcidComponent extends LogInExternalProviderComponent {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Redirect to orcid authentication url
|
|
||||||
*/
|
|
||||||
redirectToOrcid() {
|
|
||||||
this.redirectToExternalProvider();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@@ -1,3 +0,0 @@
|
|||||||
<button class="btn btn-lg btn-primary btn-block mt-2 text-white" (click)="redirectToShibboleth()">
|
|
||||||
<i class="fas fa-sign-in-alt"></i> {{"login.form.shibboleth" | translate}}
|
|
||||||
</button>
|
|
@@ -1,155 +0,0 @@
|
|||||||
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
|
|
||||||
import { ActivatedRoute, Router } from '@angular/router';
|
|
||||||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
|
||||||
|
|
||||||
import { provideMockStore } from '@ngrx/store/testing';
|
|
||||||
import { Store, StoreModule } from '@ngrx/store';
|
|
||||||
import { TranslateModule } from '@ngx-translate/core';
|
|
||||||
|
|
||||||
import { EPerson } from '../../../../core/eperson/models/eperson.model';
|
|
||||||
import { EPersonMock } from '../../../testing/eperson.mock';
|
|
||||||
import { authReducer } from '../../../../core/auth/auth.reducer';
|
|
||||||
import { AuthService } from '../../../../core/auth/auth.service';
|
|
||||||
import { AuthServiceStub } from '../../../testing/auth-service.stub';
|
|
||||||
import { storeModuleConfig } from '../../../../app.reducer';
|
|
||||||
import { AuthMethod } from '../../../../core/auth/models/auth.method';
|
|
||||||
import { AuthMethodType } from '../../../../core/auth/models/auth.method-type';
|
|
||||||
import { LogInShibbolethComponent } from './log-in-shibboleth.component';
|
|
||||||
import { NativeWindowService } from '../../../../core/services/window.service';
|
|
||||||
import { RouterStub } from '../../../testing/router.stub';
|
|
||||||
import { ActivatedRouteStub } from '../../../testing/active-router.stub';
|
|
||||||
import { NativeWindowMockFactory } from '../../../mocks/mock-native-window-ref';
|
|
||||||
import { HardRedirectService } from '../../../../core/services/hard-redirect.service';
|
|
||||||
|
|
||||||
|
|
||||||
describe('LogInShibbolethComponent', () => {
|
|
||||||
|
|
||||||
let component: LogInShibbolethComponent;
|
|
||||||
let fixture: ComponentFixture<LogInShibbolethComponent>;
|
|
||||||
let page: Page;
|
|
||||||
let user: EPerson;
|
|
||||||
let componentAsAny: any;
|
|
||||||
let setHrefSpy;
|
|
||||||
let shibbolethBaseUrl;
|
|
||||||
let location;
|
|
||||||
let initialState: any;
|
|
||||||
let hardRedirectService: HardRedirectService;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
user = EPersonMock;
|
|
||||||
shibbolethBaseUrl = 'dspace-rest.test/shibboleth?redirectUrl=';
|
|
||||||
location = shibbolethBaseUrl + 'http://dspace-angular.test/home';
|
|
||||||
|
|
||||||
hardRedirectService = jasmine.createSpyObj('hardRedirectService', {
|
|
||||||
getCurrentRoute: {},
|
|
||||||
redirect: {}
|
|
||||||
});
|
|
||||||
|
|
||||||
initialState = {
|
|
||||||
core: {
|
|
||||||
auth: {
|
|
||||||
authenticated: false,
|
|
||||||
loaded: false,
|
|
||||||
blocking: false,
|
|
||||||
loading: false,
|
|
||||||
authMethods: []
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
beforeEach(waitForAsync(() => {
|
|
||||||
// refine the test module by declaring the test component
|
|
||||||
TestBed.configureTestingModule({
|
|
||||||
imports: [
|
|
||||||
StoreModule.forRoot({ auth: authReducer }, storeModuleConfig),
|
|
||||||
TranslateModule.forRoot()
|
|
||||||
],
|
|
||||||
declarations: [
|
|
||||||
LogInShibbolethComponent
|
|
||||||
],
|
|
||||||
providers: [
|
|
||||||
{ provide: AuthService, useClass: AuthServiceStub },
|
|
||||||
{ provide: 'authMethodProvider', useValue: new AuthMethod(AuthMethodType.Shibboleth, location) },
|
|
||||||
{ provide: 'isStandalonePage', useValue: true },
|
|
||||||
{ provide: NativeWindowService, useFactory: NativeWindowMockFactory },
|
|
||||||
{ provide: Router, useValue: new RouterStub() },
|
|
||||||
{ provide: ActivatedRoute, useValue: new ActivatedRouteStub() },
|
|
||||||
{ provide: HardRedirectService, useValue: hardRedirectService },
|
|
||||||
provideMockStore({ initialState }),
|
|
||||||
],
|
|
||||||
schemas: [
|
|
||||||
CUSTOM_ELEMENTS_SCHEMA
|
|
||||||
]
|
|
||||||
})
|
|
||||||
.compileComponents();
|
|
||||||
|
|
||||||
}));
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
// create component and test fixture
|
|
||||||
fixture = TestBed.createComponent(LogInShibbolethComponent);
|
|
||||||
|
|
||||||
// get test component from the fixture
|
|
||||||
component = fixture.componentInstance;
|
|
||||||
componentAsAny = component;
|
|
||||||
|
|
||||||
// create page
|
|
||||||
page = new Page(component, fixture);
|
|
||||||
setHrefSpy = spyOnProperty(componentAsAny._window.nativeWindow.location, 'href', 'set').and.callThrough();
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should set the properly a new redirectUrl', () => {
|
|
||||||
const currentUrl = 'http://dspace-angular.test/collections/12345';
|
|
||||||
componentAsAny._window.nativeWindow.location.href = currentUrl;
|
|
||||||
|
|
||||||
fixture.detectChanges();
|
|
||||||
|
|
||||||
expect(componentAsAny.injectedAuthMethodModel.location).toBe(location);
|
|
||||||
expect(componentAsAny._window.nativeWindow.location.href).toBe(currentUrl);
|
|
||||||
|
|
||||||
component.redirectToShibboleth();
|
|
||||||
|
|
||||||
expect(setHrefSpy).toHaveBeenCalledWith(currentUrl);
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should not set a new redirectUrl', () => {
|
|
||||||
const currentUrl = 'http://dspace-angular.test/home';
|
|
||||||
componentAsAny._window.nativeWindow.location.href = currentUrl;
|
|
||||||
|
|
||||||
fixture.detectChanges();
|
|
||||||
|
|
||||||
expect(componentAsAny.injectedAuthMethodModel.location).toBe(location);
|
|
||||||
expect(componentAsAny._window.nativeWindow.location.href).toBe(currentUrl);
|
|
||||||
|
|
||||||
component.redirectToShibboleth();
|
|
||||||
|
|
||||||
expect(setHrefSpy).toHaveBeenCalledWith(currentUrl);
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* I represent the DOM elements and attach spies.
|
|
||||||
*
|
|
||||||
* @class Page
|
|
||||||
*/
|
|
||||||
class Page {
|
|
||||||
|
|
||||||
public emailInput: HTMLInputElement;
|
|
||||||
public navigateSpy: jasmine.Spy;
|
|
||||||
public passwordInput: HTMLInputElement;
|
|
||||||
|
|
||||||
constructor(private component: LogInShibbolethComponent, private fixture: ComponentFixture<LogInShibbolethComponent>) {
|
|
||||||
// use injector to get services
|
|
||||||
const injector = fixture.debugElement.injector;
|
|
||||||
const store = injector.get(Store);
|
|
||||||
|
|
||||||
// add spies
|
|
||||||
this.navigateSpy = spyOn(store, 'dispatch');
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@@ -1,23 +0,0 @@
|
|||||||
import { Component, } from '@angular/core';
|
|
||||||
|
|
||||||
import { renderAuthMethodFor } from '../log-in.methods-decorator';
|
|
||||||
import { AuthMethodType } from '../../../../core/auth/models/auth.method-type';
|
|
||||||
import { LogInExternalProviderComponent } from '../log-in-external-provider.component';
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'ds-log-in-shibboleth',
|
|
||||||
templateUrl: './log-in-shibboleth.component.html',
|
|
||||||
styleUrls: ['./log-in-shibboleth.component.scss'],
|
|
||||||
|
|
||||||
})
|
|
||||||
@renderAuthMethodFor(AuthMethodType.Shibboleth)
|
|
||||||
export class LogInShibbolethComponent extends LogInExternalProviderComponent {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Redirect to shibboleth authentication url
|
|
||||||
*/
|
|
||||||
redirectToShibboleth() {
|
|
||||||
this.redirectToExternalProvider();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@@ -6,4 +6,23 @@ export class DSONameServiceMock {
|
|||||||
public getName(dso: DSpaceObject) {
|
public getName(dso: DSpaceObject) {
|
||||||
return UNDEFINED_NAME;
|
return UNDEFINED_NAME;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public getHitHighlights(object: any, dso: DSpaceObject) {
|
||||||
|
if (object.hitHighlights && object.hitHighlights['dc.title']) {
|
||||||
|
return object.hitHighlights['dc.title'][0].value;
|
||||||
|
} else if (object.hitHighlights && object.hitHighlights['organization.legalName']) {
|
||||||
|
return object.hitHighlights['organization.legalName'][0].value;
|
||||||
|
} else if (object.hitHighlights && (object.hitHighlights['person.familyName'] || object.hitHighlights['person.givenName'])) {
|
||||||
|
if (object.hitHighlights['person.familyName'] && object.hitHighlights['person.givenName']) {
|
||||||
|
return `${object.hitHighlights['person.familyName'][0].value}, ${object.hitHighlights['person.givenName'][0].value}`;
|
||||||
|
}
|
||||||
|
if (object.hitHighlights['person.familyName']) {
|
||||||
|
return `${object.hitHighlights['person.familyName'][0].value}`;
|
||||||
|
}
|
||||||
|
if (object.hitHighlights['person.givenName']) {
|
||||||
|
return `${object.hitHighlights['person.givenName'][0].value}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return UNDEFINED_NAME;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -28,13 +28,19 @@ import { ItemSearchResultGridElementComponent } from './item-search-result-grid-
|
|||||||
|
|
||||||
const mockItemWithMetadata: ItemSearchResult = new ItemSearchResult();
|
const mockItemWithMetadata: ItemSearchResult = new ItemSearchResult();
|
||||||
mockItemWithMetadata.hitHighlights = {};
|
mockItemWithMetadata.hitHighlights = {};
|
||||||
|
const dcTitle = 'This is just another <em>title</em>';
|
||||||
mockItemWithMetadata.indexableObject = Object.assign(new Item(), {
|
mockItemWithMetadata.indexableObject = Object.assign(new Item(), {
|
||||||
|
hitHighlights: {
|
||||||
|
'dc.title': [{
|
||||||
|
value: dcTitle
|
||||||
|
}],
|
||||||
|
},
|
||||||
bundles: createSuccessfulRemoteDataObject$(buildPaginatedList(new PageInfo(), [])),
|
bundles: createSuccessfulRemoteDataObject$(buildPaginatedList(new PageInfo(), [])),
|
||||||
metadata: {
|
metadata: {
|
||||||
'dc.title': [
|
'dc.title': [
|
||||||
{
|
{
|
||||||
language: 'en_US',
|
language: 'en_US',
|
||||||
value: 'This is just another title'
|
value: dcTitle
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
'dc.contributor.author': [
|
'dc.contributor.author': [
|
||||||
@@ -57,6 +63,114 @@ mockItemWithMetadata.indexableObject = Object.assign(new Item(), {
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
const mockPerson: ItemSearchResult = Object.assign(new ItemSearchResult(), {
|
||||||
|
hitHighlights: {
|
||||||
|
'person.familyName': [{
|
||||||
|
value: '<em>Michel</em>'
|
||||||
|
}],
|
||||||
|
},
|
||||||
|
indexableObject:
|
||||||
|
Object.assign(new Item(), {
|
||||||
|
bundles: createSuccessfulRemoteDataObject$(buildPaginatedList(new PageInfo(), [])),
|
||||||
|
entityType: 'Person',
|
||||||
|
metadata: {
|
||||||
|
'dc.title': [
|
||||||
|
{
|
||||||
|
language: 'en_US',
|
||||||
|
value: 'This is just another title'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
'dc.contributor.author': [
|
||||||
|
{
|
||||||
|
language: 'en_US',
|
||||||
|
value: 'Smith, Donald'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
'dc.publisher': [
|
||||||
|
{
|
||||||
|
language: 'en_US',
|
||||||
|
value: 'a publisher'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
'dc.date.issued': [
|
||||||
|
{
|
||||||
|
language: 'en_US',
|
||||||
|
value: '2015-06-26'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
'dc.description.abstract': [
|
||||||
|
{
|
||||||
|
language: 'en_US',
|
||||||
|
value: 'This is the abstract'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
'dspace.entity.type': [
|
||||||
|
{
|
||||||
|
value: 'Person'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
'person.familyName': [
|
||||||
|
{
|
||||||
|
value: 'Michel'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
})
|
||||||
|
});
|
||||||
|
const mockOrgUnit: ItemSearchResult = Object.assign(new ItemSearchResult(), {
|
||||||
|
hitHighlights: {
|
||||||
|
'organization.legalName': [{
|
||||||
|
value: '<em>Science</em>'
|
||||||
|
}],
|
||||||
|
},
|
||||||
|
indexableObject:
|
||||||
|
Object.assign(new Item(), {
|
||||||
|
bundles: createSuccessfulRemoteDataObject$(buildPaginatedList(new PageInfo(), [])),
|
||||||
|
entityType: 'OrgUnit',
|
||||||
|
metadata: {
|
||||||
|
'dc.title': [
|
||||||
|
{
|
||||||
|
language: 'en_US',
|
||||||
|
value: 'This is just another title'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
'dc.contributor.author': [
|
||||||
|
{
|
||||||
|
language: 'en_US',
|
||||||
|
value: 'Smith, Donald'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
'dc.publisher': [
|
||||||
|
{
|
||||||
|
language: 'en_US',
|
||||||
|
value: 'a publisher'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
'dc.date.issued': [
|
||||||
|
{
|
||||||
|
language: 'en_US',
|
||||||
|
value: '2015-06-26'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
'dc.description.abstract': [
|
||||||
|
{
|
||||||
|
language: 'en_US',
|
||||||
|
value: 'This is the abstract'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
'organization.legalName': [
|
||||||
|
{
|
||||||
|
value: 'Science'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
'dspace.entity.type': [
|
||||||
|
{
|
||||||
|
value: 'OrgUnit'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
const mockItemWithoutMetadata: ItemSearchResult = new ItemSearchResult();
|
const mockItemWithoutMetadata: ItemSearchResult = new ItemSearchResult();
|
||||||
mockItemWithoutMetadata.hitHighlights = {};
|
mockItemWithoutMetadata.hitHighlights = {};
|
||||||
@@ -154,6 +268,41 @@ export function getEntityGridElementTestComponent(component, searchResultWithMet
|
|||||||
expect(itemAuthorField).toBeNull();
|
expect(itemAuthorField).toBeNull();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('When the item has title', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
comp.object = mockItemWithMetadata;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
it('should show highlighted title', () => {
|
||||||
|
const titleField = fixture.debugElement.query(By.css('.card-title'));
|
||||||
|
expect(titleField.nativeNode.innerHTML).toEqual(dcTitle);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('When the item is Person and has title', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
comp.object = mockPerson;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should show highlighted title', () => {
|
||||||
|
const titleField = fixture.debugElement.query(By.css('.card-title'));
|
||||||
|
expect(titleField.nativeNode.innerHTML).toEqual('<em>Michel</em>');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('When the item is orgUnit and has title', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
comp.object = mockOrgUnit;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should show highlighted title', () => {
|
||||||
|
const titleField = fixture.debugElement.query(By.css('.card-title'));
|
||||||
|
expect(titleField.nativeNode.innerHTML).toEqual('<em>Science</em>');
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@@ -42,6 +42,6 @@ export class ItemSearchResultGridElementComponent extends SearchResultGridElemen
|
|||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
super.ngOnInit();
|
super.ngOnInit();
|
||||||
this.itemPageRoute = getItemPageRoute(this.dso);
|
this.itemPageRoute = getItemPageRoute(this.dso);
|
||||||
this.dsoTitle = this.dsoNameService.getName(this.dso);
|
this.dsoTitle = this.dsoNameService.getHitHighlights(this.object, this.dso);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -55,7 +55,7 @@ export class ItemListPreviewComponent implements OnInit {
|
|||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.showThumbnails = this.appConfig.browseBy.showThumbnails;
|
this.showThumbnails = this.appConfig.browseBy.showThumbnails;
|
||||||
this.dsoTitle = this.dsoNameService.getName(this.item);
|
this.dsoTitle = this.dsoNameService.getHitHighlights(this.object, this.item);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@@ -13,8 +13,13 @@ import { APP_CONFIG } from '../../../../../../../config/app-config.interface';
|
|||||||
|
|
||||||
let publicationListElementComponent: ItemSearchResultListElementComponent;
|
let publicationListElementComponent: ItemSearchResultListElementComponent;
|
||||||
let fixture: ComponentFixture<ItemSearchResultListElementComponent>;
|
let fixture: ComponentFixture<ItemSearchResultListElementComponent>;
|
||||||
|
const dcTitle = 'This is just another <em>title</em>';
|
||||||
const mockItemWithMetadata: ItemSearchResult = Object.assign(new ItemSearchResult(), {
|
const mockItemWithMetadata: ItemSearchResult = Object.assign(new ItemSearchResult(), {
|
||||||
|
hitHighlights: {
|
||||||
|
'dc.title': [{
|
||||||
|
value: dcTitle
|
||||||
|
}],
|
||||||
|
},
|
||||||
indexableObject:
|
indexableObject:
|
||||||
Object.assign(new Item(), {
|
Object.assign(new Item(), {
|
||||||
bundles: observableOf({}),
|
bundles: observableOf({}),
|
||||||
@@ -22,7 +27,7 @@ const mockItemWithMetadata: ItemSearchResult = Object.assign(new ItemSearchResul
|
|||||||
'dc.title': [
|
'dc.title': [
|
||||||
{
|
{
|
||||||
language: 'en_US',
|
language: 'en_US',
|
||||||
value: 'This is just another title'
|
value: dcTitle
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
'dc.contributor.author': [
|
'dc.contributor.author': [
|
||||||
@@ -59,7 +64,114 @@ const mockItemWithoutMetadata: ItemSearchResult = Object.assign(new ItemSearchRe
|
|||||||
metadata: {}
|
metadata: {}
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
const mockPerson: ItemSearchResult = Object.assign(new ItemSearchResult(), {
|
||||||
|
hitHighlights: {
|
||||||
|
'person.familyName': [{
|
||||||
|
value: '<em>Michel</em>'
|
||||||
|
}],
|
||||||
|
},
|
||||||
|
indexableObject:
|
||||||
|
Object.assign(new Item(), {
|
||||||
|
bundles: observableOf({}),
|
||||||
|
entityType: 'Person',
|
||||||
|
metadata: {
|
||||||
|
'dc.title': [
|
||||||
|
{
|
||||||
|
language: 'en_US',
|
||||||
|
value: 'This is just another title'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
'dc.contributor.author': [
|
||||||
|
{
|
||||||
|
language: 'en_US',
|
||||||
|
value: 'Smith, Donald'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
'dc.publisher': [
|
||||||
|
{
|
||||||
|
language: 'en_US',
|
||||||
|
value: 'a publisher'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
'dc.date.issued': [
|
||||||
|
{
|
||||||
|
language: 'en_US',
|
||||||
|
value: '2015-06-26'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
'dc.description.abstract': [
|
||||||
|
{
|
||||||
|
language: 'en_US',
|
||||||
|
value: 'This is the abstract'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
'person.familyName': [
|
||||||
|
{
|
||||||
|
value: 'Michel'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
'dspace.entity.type': [
|
||||||
|
{
|
||||||
|
value: 'Person'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
})
|
||||||
|
});
|
||||||
|
const mockOrgUnit: ItemSearchResult = Object.assign(new ItemSearchResult(), {
|
||||||
|
hitHighlights: {
|
||||||
|
'organization.legalName': [{
|
||||||
|
value: '<em>Science</em>'
|
||||||
|
}],
|
||||||
|
},
|
||||||
|
indexableObject:
|
||||||
|
Object.assign(new Item(), {
|
||||||
|
bundles: observableOf({}),
|
||||||
|
entityType: 'OrgUnit',
|
||||||
|
metadata: {
|
||||||
|
'dc.title': [
|
||||||
|
{
|
||||||
|
language: 'en_US',
|
||||||
|
value: 'This is just another title'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
'dc.contributor.author': [
|
||||||
|
{
|
||||||
|
language: 'en_US',
|
||||||
|
value: 'Smith, Donald'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
'dc.publisher': [
|
||||||
|
{
|
||||||
|
language: 'en_US',
|
||||||
|
value: 'a publisher'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
'dc.date.issued': [
|
||||||
|
{
|
||||||
|
language: 'en_US',
|
||||||
|
value: '2015-06-26'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
'dc.description.abstract': [
|
||||||
|
{
|
||||||
|
language: 'en_US',
|
||||||
|
value: 'This is the abstract'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
'organization.legalName': [
|
||||||
|
{
|
||||||
|
value: 'Science'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
'dspace.entity.type': [
|
||||||
|
{
|
||||||
|
value: 'OrgUnit'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
})
|
||||||
|
});
|
||||||
const environmentUseThumbs = {
|
const environmentUseThumbs = {
|
||||||
browseBy: {
|
browseBy: {
|
||||||
showThumbnails: true
|
showThumbnails: true
|
||||||
@@ -205,6 +317,42 @@ describe('ItemSearchResultListElementComponent', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('When the item has title', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
publicationListElementComponent.object = mockItemWithMetadata;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should show highlighted title', () => {
|
||||||
|
const titleField = fixture.debugElement.query(By.css('.item-list-title'));
|
||||||
|
expect(titleField.nativeNode.innerHTML).toEqual(dcTitle);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('When the item is Person and has title', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
publicationListElementComponent.object = mockPerson;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should show highlighted title', () => {
|
||||||
|
const titleField = fixture.debugElement.query(By.css('.item-list-title'));
|
||||||
|
expect(titleField.nativeNode.innerHTML).toEqual('<em>Michel</em>');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('When the item is orgUnit and has title', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
publicationListElementComponent.object = mockOrgUnit;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should show highlighted title', () => {
|
||||||
|
const titleField = fixture.debugElement.query(By.css('.item-list-title'));
|
||||||
|
expect(titleField.nativeNode.innerHTML).toEqual('<em>Science</em>');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('When the item has no title', () => {
|
describe('When the item has no title', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
publicationListElementComponent.object = mockItemWithoutMetadata;
|
publicationListElementComponent.object = mockItemWithoutMetadata;
|
||||||
|
@@ -33,7 +33,7 @@ export class SearchResultListElementComponent<T extends SearchResult<K>, K exten
|
|||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
if (hasValue(this.object)) {
|
if (hasValue(this.object)) {
|
||||||
this.dso = this.object.indexableObject;
|
this.dso = this.object.indexableObject;
|
||||||
this.dsoTitle = this.dsoNameService.getName(this.dso);
|
this.dsoTitle = this.dsoNameService.getHitHighlights(this.object, this.dso);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -186,7 +186,6 @@ import {
|
|||||||
ImportableListItemControlComponent
|
ImportableListItemControlComponent
|
||||||
} from './object-collection/shared/importable-list-item-control/importable-list-item-control.component';
|
} from './object-collection/shared/importable-list-item-control/importable-list-item-control.component';
|
||||||
import { LogInContainerComponent } from './log-in/container/log-in-container.component';
|
import { LogInContainerComponent } from './log-in/container/log-in-container.component';
|
||||||
import { LogInShibbolethComponent } from './log-in/methods/shibboleth/log-in-shibboleth.component';
|
|
||||||
import { LogInPasswordComponent } from './log-in/methods/password/log-in-password.component';
|
import { LogInPasswordComponent } from './log-in/methods/password/log-in-password.component';
|
||||||
import { LogInComponent } from './log-in/log-in.component';
|
import { LogInComponent } from './log-in/log-in.component';
|
||||||
import { MissingTranslationHelper } from './translate/missing-translation.helper';
|
import { MissingTranslationHelper } from './translate/missing-translation.helper';
|
||||||
@@ -229,9 +228,7 @@ import { SearchNavbarComponent } from '../search-navbar/search-navbar.component'
|
|||||||
import { ThemedSearchNavbarComponent } from '../search-navbar/themed-search-navbar.component';
|
import { ThemedSearchNavbarComponent } from '../search-navbar/themed-search-navbar.component';
|
||||||
import { ScopeSelectorModalComponent } from './search-form/scope-selector-modal/scope-selector-modal.component';
|
import { ScopeSelectorModalComponent } from './search-form/scope-selector-modal/scope-selector-modal.component';
|
||||||
import { DsSelectComponent } from './ds-select/ds-select.component';
|
import { DsSelectComponent } from './ds-select/ds-select.component';
|
||||||
import { LogInOidcComponent } from './log-in/methods/oidc/log-in-oidc.component';
|
|
||||||
import { RSSComponent } from './rss-feed/rss.component';
|
import { RSSComponent } from './rss-feed/rss.component';
|
||||||
import { LogInOrcidComponent } from './log-in/methods/orcid/log-in-orcid.component';
|
|
||||||
import { BrowserOnlyPipe } from './utils/browser-only.pipe';
|
import { BrowserOnlyPipe } from './utils/browser-only.pipe';
|
||||||
import { ThemedLoadingComponent } from './loading/themed-loading.component';
|
import { ThemedLoadingComponent } from './loading/themed-loading.component';
|
||||||
import { SearchExportCsvComponent } from './search/search-export-csv/search-export-csv.component';
|
import { SearchExportCsvComponent } from './search/search-export-csv/search-export-csv.component';
|
||||||
@@ -246,6 +243,7 @@ import {
|
|||||||
} from './object-list/listable-notification-object/listable-notification-object.component';
|
} from './object-list/listable-notification-object/listable-notification-object.component';
|
||||||
import { ThemedCollectionDropdownComponent } from './collection-dropdown/themed-collection-dropdown.component';
|
import { ThemedCollectionDropdownComponent } from './collection-dropdown/themed-collection-dropdown.component';
|
||||||
import { MetadataFieldWrapperComponent } from './metadata-field-wrapper/metadata-field-wrapper.component';
|
import { MetadataFieldWrapperComponent } from './metadata-field-wrapper/metadata-field-wrapper.component';
|
||||||
|
import { LogInExternalProviderComponent } from './log-in/methods/log-in-external-provider/log-in-external-provider.component';
|
||||||
import { AdvancedClaimedTaskActionSelectReviewerComponent } from './mydspace-actions/claimed-task/select-reviewer/advanced-claimed-task-action-select-reviewer.component';
|
import { AdvancedClaimedTaskActionSelectReviewerComponent } from './mydspace-actions/claimed-task/select-reviewer/advanced-claimed-task-action-select-reviewer.component';
|
||||||
import {
|
import {
|
||||||
AdvancedClaimedTaskActionRatingComponent
|
AdvancedClaimedTaskActionRatingComponent
|
||||||
@@ -352,8 +350,6 @@ const COMPONENTS = [
|
|||||||
ListableNotificationObjectComponent,
|
ListableNotificationObjectComponent,
|
||||||
DsoPageEditButtonComponent,
|
DsoPageEditButtonComponent,
|
||||||
MetadataFieldWrapperComponent,
|
MetadataFieldWrapperComponent,
|
||||||
AdvancedClaimedTaskActionSelectReviewerComponent,
|
|
||||||
AdvancedClaimedTaskActionRatingComponent,
|
|
||||||
];
|
];
|
||||||
|
|
||||||
const ENTRY_COMPONENTS = [
|
const ENTRY_COMPONENTS = [
|
||||||
@@ -393,9 +389,7 @@ const ENTRY_COMPONENTS = [
|
|||||||
MetadataRepresentationListElementComponent,
|
MetadataRepresentationListElementComponent,
|
||||||
ItemMetadataRepresentationListElementComponent,
|
ItemMetadataRepresentationListElementComponent,
|
||||||
LogInPasswordComponent,
|
LogInPasswordComponent,
|
||||||
LogInShibbolethComponent,
|
LogInExternalProviderComponent,
|
||||||
LogInOidcComponent,
|
|
||||||
LogInOrcidComponent,
|
|
||||||
ClaimedTaskActionsDeclineTaskComponent,
|
ClaimedTaskActionsDeclineTaskComponent,
|
||||||
CollectionDropdownComponent,
|
CollectionDropdownComponent,
|
||||||
ThemedCollectionDropdownComponent,
|
ThemedCollectionDropdownComponent,
|
||||||
|
@@ -3903,6 +3903,8 @@
|
|||||||
|
|
||||||
"submission.import-external.source.crossref": "CrossRef",
|
"submission.import-external.source.crossref": "CrossRef",
|
||||||
|
|
||||||
|
"submission.import-external.source.datacite": "DataCite",
|
||||||
|
|
||||||
"submission.import-external.source.scielo": "SciELO",
|
"submission.import-external.source.scielo": "SciELO",
|
||||||
|
|
||||||
"submission.import-external.source.scopus": "Scopus",
|
"submission.import-external.source.scopus": "Scopus",
|
||||||
|
Reference in New Issue
Block a user