diff --git a/package.json b/package.json
index b946f490b1..38dde038d0 100644
--- a/package.json
+++ b/package.json
@@ -30,8 +30,9 @@
"clean:log": "rimraf *.log*",
"clean:json": "rimraf *.records.json",
"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": "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",
"build:mirador": "webpack --config webpack/webpack.mirador.config.ts",
"merge-i18n": "ts-node --project ./tsconfig.ts-node.json scripts/merge-i18n-files.ts",
diff --git a/src/app/core/auth/auth.interceptor.ts b/src/app/core/auth/auth.interceptor.ts
index e55d0c0ff9..672879f436 100644
--- a/src/app/core/auth/auth.interceptor.ts
+++ b/src/app/core/auth/auth.interceptor.ts
@@ -196,7 +196,24 @@ export class AuthInterceptor implements HttpInterceptor {
authStatus.token = new AuthTokenInfo(accessToken);
} else {
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;
}
diff --git a/src/app/core/breadcrumbs/dso-name.service.ts b/src/app/core/breadcrumbs/dso-name.service.ts
index d56f4a00eb..64f37baa65 100644
--- a/src/app/core/breadcrumbs/dso-name.service.ts
+++ b/src/app/core/breadcrumbs/dso-name.service.ts
@@ -2,6 +2,7 @@ import { Injectable } from '@angular/core';
import { hasValue, isEmpty } from '../../shared/empty.util';
import { DSpaceObject } from '../shared/dspace-object.model';
import { TranslateService } from '@ngx-translate/core';
+import { Metadata } from '../shared/metadata.utils';
/**
* Returns a name for a {@link DSpaceObject} based
@@ -67,4 +68,45 @@ export class DSONameService {
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);
+ }
+
}
diff --git a/src/app/entity-groups/research-entities/submission/item-list-elements/org-unit/org-unit-search-result-list-submission-element.component.ts b/src/app/entity-groups/research-entities/submission/item-list-elements/org-unit/org-unit-search-result-list-submission-element.component.ts
index 7a38a02cf4..954f7bc591 100644
--- a/src/app/entity-groups/research-entities/submission/item-list-elements/org-unit/org-unit-search-result-list-submission-element.component.ts
+++ b/src/app/entity-groups/research-entities/submission/item-list-elements/org-unit/org-unit-search-result-list-submission-element.component.ts
@@ -61,7 +61,7 @@ export class OrgUnitSearchResultListSubmissionElementComponent extends SearchRes
this.useNameVariants = this.context === Context.EntitySearchModalWithNameVariants;
if (this.useNameVariants) {
- const defaultValue = this.dsoTitle;
+ const defaultValue = this.dso ? this.dsoNameService.getName(this.dso) : undefined;
const alternatives = this.allMetadataValues(this.alternativeField);
this.allSuggestions = [defaultValue, ...alternatives];
diff --git a/src/app/entity-groups/research-entities/submission/item-list-elements/person/person-search-result-list-submission-element.component.ts b/src/app/entity-groups/research-entities/submission/item-list-elements/person/person-search-result-list-submission-element.component.ts
index 7d761c42dd..305407f8d2 100644
--- a/src/app/entity-groups/research-entities/submission/item-list-elements/person/person-search-result-list-submission-element.component.ts
+++ b/src/app/entity-groups/research-entities/submission/item-list-elements/person/person-search-result-list-submission-element.component.ts
@@ -55,7 +55,7 @@ export class PersonSearchResultListSubmissionElementComponent extends SearchResu
ngOnInit() {
super.ngOnInit();
- const defaultValue = this.dsoTitle;
+ const defaultValue = this.dso ? this.dsoNameService.getName(this.dso) : undefined;
const alternatives = this.allMetadataValues(this.alternativeField);
this.allSuggestions = [defaultValue, ...alternatives];
diff --git a/src/app/shared/log-in/methods/log-in-external-provider/log-in-external-provider.component.html b/src/app/shared/log-in/methods/log-in-external-provider/log-in-external-provider.component.html
new file mode 100644
index 0000000000..6046aec725
--- /dev/null
+++ b/src/app/shared/log-in/methods/log-in-external-provider/log-in-external-provider.component.html
@@ -0,0 +1,3 @@
+
diff --git a/src/app/shared/log-in/methods/shibboleth/log-in-shibboleth.component.scss b/src/app/shared/log-in/methods/log-in-external-provider/log-in-external-provider.component.scss
similarity index 100%
rename from src/app/shared/log-in/methods/shibboleth/log-in-shibboleth.component.scss
rename to src/app/shared/log-in/methods/log-in-external-provider/log-in-external-provider.component.scss
diff --git a/src/app/shared/log-in/methods/orcid/log-in-orcid.component.spec.ts b/src/app/shared/log-in/methods/log-in-external-provider/log-in-external-provider.component.spec.ts
similarity index 88%
rename from src/app/shared/log-in/methods/orcid/log-in-orcid.component.spec.ts
rename to src/app/shared/log-in/methods/log-in-external-provider/log-in-external-provider.component.spec.ts
index 001f0a4959..de4f62eb9e 100644
--- a/src/app/shared/log-in/methods/orcid/log-in-orcid.component.spec.ts
+++ b/src/app/shared/log-in/methods/log-in-external-provider/log-in-external-provider.component.spec.ts
@@ -14,18 +14,17 @@ 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 { LogInOrcidComponent } from './log-in-orcid.component';
+import { LogInExternalProviderComponent } from './log-in-external-provider.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('LogInExternalProviderComponent', () => {
-describe('LogInOrcidComponent', () => {
-
- let component: LogInOrcidComponent;
- let fixture: ComponentFixture;
+ let component: LogInExternalProviderComponent;
+ let fixture: ComponentFixture;
let page: Page;
let user: EPerson;
let componentAsAny: any;
@@ -66,7 +65,7 @@ describe('LogInOrcidComponent', () => {
TranslateModule.forRoot()
],
declarations: [
- LogInOrcidComponent
+ LogInExternalProviderComponent
],
providers: [
{ provide: AuthService, useClass: AuthServiceStub },
@@ -88,7 +87,7 @@ describe('LogInOrcidComponent', () => {
beforeEach(() => {
// create component and test fixture
- fixture = TestBed.createComponent(LogInOrcidComponent);
+ fixture = TestBed.createComponent(LogInExternalProviderComponent);
// get test component from the fixture
component = fixture.componentInstance;
@@ -109,7 +108,7 @@ describe('LogInOrcidComponent', () => {
expect(componentAsAny.injectedAuthMethodModel.location).toBe(location);
expect(componentAsAny._window.nativeWindow.location.href).toBe(currentUrl);
- component.redirectToOrcid();
+ component.redirectToExternalProvider();
expect(setHrefSpy).toHaveBeenCalledWith(currentUrl);
@@ -124,7 +123,7 @@ describe('LogInOrcidComponent', () => {
expect(componentAsAny.injectedAuthMethodModel.location).toBe(location);
expect(componentAsAny._window.nativeWindow.location.href).toBe(currentUrl);
- component.redirectToOrcid();
+ component.redirectToExternalProvider();
expect(setHrefSpy).toHaveBeenCalledWith(currentUrl);
@@ -143,7 +142,7 @@ class Page {
public navigateSpy: jasmine.Spy;
public passwordInput: HTMLInputElement;
- constructor(private component: LogInOrcidComponent, private fixture: ComponentFixture) {
+ constructor(private component: LogInExternalProviderComponent, private fixture: ComponentFixture) {
// use injector to get services
const injector = fixture.debugElement.injector;
const store = injector.get(Store);
diff --git a/src/app/shared/log-in/methods/log-in-external-provider.component.ts b/src/app/shared/log-in/methods/log-in-external-provider/log-in-external-provider.component.ts
similarity index 73%
rename from src/app/shared/log-in/methods/log-in-external-provider.component.ts
rename to src/app/shared/log-in/methods/log-in-external-provider/log-in-external-provider.component.ts
index 037fc40e90..f182968457 100644
--- a/src/app/shared/log-in/methods/log-in-external-provider.component.ts
+++ b/src/app/shared/log-in/methods/log-in-external-provider/log-in-external-provider.component.ts
@@ -4,22 +4,27 @@ import { Observable } from 'rxjs';
import { take } from 'rxjs/operators';
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 { NativeWindowRef, NativeWindowService } from '../../../core/services/window.service';
-import { isEmpty, isNotNull } from '../../empty.util';
-import { AuthService } from '../../../core/auth/auth.service';
-import { HardRedirectService } from '../../../core/services/hard-redirect.service';
-import { URLCombiner } from '../../../core/url-combiner/url-combiner';
-import { CoreState } from '../../../core/core-state.model';
+import { isAuthenticated, isAuthenticationLoading } from '../../../../core/auth/selectors';
+import { NativeWindowRef, NativeWindowService } from '../../../../core/services/window.service';
+import { isEmpty, isNotNull } from '../../../empty.util';
+import { AuthService } from '../../../../core/auth/auth.service';
+import { HardRedirectService } from '../../../../core/services/hard-redirect.service';
+import { URLCombiner } from '../../../../core/url-combiner/url-combiner';
+import { CoreState } from '../../../../core/core-state.model';
+import { renderAuthMethodFor } from '../log-in.methods-decorator';
+import { AuthMethodType } from '../../../../core/auth/models/auth.method-type';
@Component({
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.
@@ -107,4 +112,7 @@ export abstract class LogInExternalProviderComponent implements OnInit {
}
+ getButtonLabel() {
+ return `login.form.${this.authMethod.authMethodType}`;
+ }
}
diff --git a/src/app/shared/log-in/methods/oidc/log-in-oidc.component.html b/src/app/shared/log-in/methods/oidc/log-in-oidc.component.html
deleted file mode 100644
index 7e78834305..0000000000
--- a/src/app/shared/log-in/methods/oidc/log-in-oidc.component.html
+++ /dev/null
@@ -1,3 +0,0 @@
-
\ No newline at end of file
diff --git a/src/app/shared/log-in/methods/oidc/log-in-oidc.component.spec.ts b/src/app/shared/log-in/methods/oidc/log-in-oidc.component.spec.ts
deleted file mode 100644
index 078a58dd5a..0000000000
--- a/src/app/shared/log-in/methods/oidc/log-in-oidc.component.spec.ts
+++ /dev/null
@@ -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;
- 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) {
- // use injector to get services
- const injector = fixture.debugElement.injector;
- const store = injector.get(Store);
-
- // add spies
- this.navigateSpy = spyOn(store, 'dispatch');
- }
-
-}
diff --git a/src/app/shared/log-in/methods/oidc/log-in-oidc.component.ts b/src/app/shared/log-in/methods/oidc/log-in-oidc.component.ts
deleted file mode 100644
index 882996b207..0000000000
--- a/src/app/shared/log-in/methods/oidc/log-in-oidc.component.ts
+++ /dev/null
@@ -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();
- }
-
-}
diff --git a/src/app/shared/log-in/methods/orcid/log-in-orcid.component.html b/src/app/shared/log-in/methods/orcid/log-in-orcid.component.html
deleted file mode 100644
index 6f5453fd60..0000000000
--- a/src/app/shared/log-in/methods/orcid/log-in-orcid.component.html
+++ /dev/null
@@ -1,3 +0,0 @@
-
\ No newline at end of file
diff --git a/src/app/shared/log-in/methods/orcid/log-in-orcid.component.ts b/src/app/shared/log-in/methods/orcid/log-in-orcid.component.ts
deleted file mode 100644
index e0b1da3db5..0000000000
--- a/src/app/shared/log-in/methods/orcid/log-in-orcid.component.ts
+++ /dev/null
@@ -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();
- }
-
-}
diff --git a/src/app/shared/log-in/methods/shibboleth/log-in-shibboleth.component.html b/src/app/shared/log-in/methods/shibboleth/log-in-shibboleth.component.html
deleted file mode 100644
index 3a3b935cfa..0000000000
--- a/src/app/shared/log-in/methods/shibboleth/log-in-shibboleth.component.html
+++ /dev/null
@@ -1,3 +0,0 @@
-
diff --git a/src/app/shared/log-in/methods/shibboleth/log-in-shibboleth.component.spec.ts b/src/app/shared/log-in/methods/shibboleth/log-in-shibboleth.component.spec.ts
deleted file mode 100644
index 075d33d98e..0000000000
--- a/src/app/shared/log-in/methods/shibboleth/log-in-shibboleth.component.spec.ts
+++ /dev/null
@@ -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;
- 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) {
- // use injector to get services
- const injector = fixture.debugElement.injector;
- const store = injector.get(Store);
-
- // add spies
- this.navigateSpy = spyOn(store, 'dispatch');
- }
-
-}
diff --git a/src/app/shared/log-in/methods/shibboleth/log-in-shibboleth.component.ts b/src/app/shared/log-in/methods/shibboleth/log-in-shibboleth.component.ts
deleted file mode 100644
index dcfb3ccfc3..0000000000
--- a/src/app/shared/log-in/methods/shibboleth/log-in-shibboleth.component.ts
+++ /dev/null
@@ -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();
- }
-
-}
diff --git a/src/app/shared/mocks/dso-name.service.mock.ts b/src/app/shared/mocks/dso-name.service.mock.ts
index f4947cc860..cf3cf5466b 100644
--- a/src/app/shared/mocks/dso-name.service.mock.ts
+++ b/src/app/shared/mocks/dso-name.service.mock.ts
@@ -6,4 +6,23 @@ export class DSONameServiceMock {
public getName(dso: DSpaceObject) {
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;
+ }
}
diff --git a/src/app/shared/object-grid/search-result-grid-element/item-search-result/item/item-search-result-grid-element.component.spec.ts b/src/app/shared/object-grid/search-result-grid-element/item-search-result/item/item-search-result-grid-element.component.spec.ts
index 57b863a1b1..dc42b033d8 100644
--- a/src/app/shared/object-grid/search-result-grid-element/item-search-result/item/item-search-result-grid-element.component.spec.ts
+++ b/src/app/shared/object-grid/search-result-grid-element/item-search-result/item/item-search-result-grid-element.component.spec.ts
@@ -28,13 +28,19 @@ import { ItemSearchResultGridElementComponent } from './item-search-result-grid-
const mockItemWithMetadata: ItemSearchResult = new ItemSearchResult();
mockItemWithMetadata.hitHighlights = {};
+const dcTitle = 'This is just another title';
mockItemWithMetadata.indexableObject = Object.assign(new Item(), {
+ hitHighlights: {
+ 'dc.title': [{
+ value: dcTitle
+ }],
+ },
bundles: createSuccessfulRemoteDataObject$(buildPaginatedList(new PageInfo(), [])),
metadata: {
'dc.title': [
{
language: 'en_US',
- value: 'This is just another title'
+ value: dcTitle
}
],
'dc.contributor.author': [
@@ -57,6 +63,114 @@ mockItemWithMetadata.indexableObject = Object.assign(new Item(), {
]
}
});
+const mockPerson: ItemSearchResult = Object.assign(new ItemSearchResult(), {
+ hitHighlights: {
+ 'person.familyName': [{
+ value: 'Michel'
+ }],
+ },
+ 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: 'Science'
+ }],
+ },
+ 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();
mockItemWithoutMetadata.hitHighlights = {};
@@ -154,6 +268,41 @@ export function getEntityGridElementTestComponent(component, searchResultWithMet
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('Michel');
+ });
+ });
+
+ 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('Science');
+ });
+ });
});
};
}
diff --git a/src/app/shared/object-grid/search-result-grid-element/item-search-result/item/item-search-result-grid-element.component.ts b/src/app/shared/object-grid/search-result-grid-element/item-search-result/item/item-search-result-grid-element.component.ts
index b5f9c016e4..303e4681a2 100644
--- a/src/app/shared/object-grid/search-result-grid-element/item-search-result/item/item-search-result-grid-element.component.ts
+++ b/src/app/shared/object-grid/search-result-grid-element/item-search-result/item/item-search-result-grid-element.component.ts
@@ -42,6 +42,6 @@ export class ItemSearchResultGridElementComponent extends SearchResultGridElemen
ngOnInit(): void {
super.ngOnInit();
this.itemPageRoute = getItemPageRoute(this.dso);
- this.dsoTitle = this.dsoNameService.getName(this.dso);
+ this.dsoTitle = this.dsoNameService.getHitHighlights(this.object, this.dso);
}
}
diff --git a/src/app/shared/object-list/my-dspace-result-list-element/item-list-preview/item-list-preview.component.ts b/src/app/shared/object-list/my-dspace-result-list-element/item-list-preview/item-list-preview.component.ts
index 04f1e24d7b..6b40678ded 100644
--- a/src/app/shared/object-list/my-dspace-result-list-element/item-list-preview/item-list-preview.component.ts
+++ b/src/app/shared/object-list/my-dspace-result-list-element/item-list-preview/item-list-preview.component.ts
@@ -55,7 +55,7 @@ export class ItemListPreviewComponent implements OnInit {
ngOnInit(): void {
this.showThumbnails = this.appConfig.browseBy.showThumbnails;
- this.dsoTitle = this.dsoNameService.getName(this.item);
+ this.dsoTitle = this.dsoNameService.getHitHighlights(this.object, this.item);
}
diff --git a/src/app/shared/object-list/search-result-list-element/item-search-result/item-types/item/item-search-result-list-element.component.spec.ts b/src/app/shared/object-list/search-result-list-element/item-search-result/item-types/item/item-search-result-list-element.component.spec.ts
index d1e6c27ba4..7665b7d64e 100644
--- a/src/app/shared/object-list/search-result-list-element/item-search-result/item-types/item/item-search-result-list-element.component.spec.ts
+++ b/src/app/shared/object-list/search-result-list-element/item-search-result/item-types/item/item-search-result-list-element.component.spec.ts
@@ -13,8 +13,13 @@ import { APP_CONFIG } from '../../../../../../../config/app-config.interface';
let publicationListElementComponent: ItemSearchResultListElementComponent;
let fixture: ComponentFixture;
-
+const dcTitle = 'This is just another title';
const mockItemWithMetadata: ItemSearchResult = Object.assign(new ItemSearchResult(), {
+ hitHighlights: {
+ 'dc.title': [{
+ value: dcTitle
+ }],
+ },
indexableObject:
Object.assign(new Item(), {
bundles: observableOf({}),
@@ -22,7 +27,7 @@ const mockItemWithMetadata: ItemSearchResult = Object.assign(new ItemSearchResul
'dc.title': [
{
language: 'en_US',
- value: 'This is just another title'
+ value: dcTitle
}
],
'dc.contributor.author': [
@@ -59,7 +64,114 @@ const mockItemWithoutMetadata: ItemSearchResult = Object.assign(new ItemSearchRe
metadata: {}
})
});
-
+const mockPerson: ItemSearchResult = Object.assign(new ItemSearchResult(), {
+ hitHighlights: {
+ 'person.familyName': [{
+ value: 'Michel'
+ }],
+ },
+ 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: 'Science'
+ }],
+ },
+ 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 = {
browseBy: {
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('Michel');
+ });
+ });
+
+ 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('Science');
+ });
+ });
+
describe('When the item has no title', () => {
beforeEach(() => {
publicationListElementComponent.object = mockItemWithoutMetadata;
diff --git a/src/app/shared/object-list/search-result-list-element/search-result-list-element.component.ts b/src/app/shared/object-list/search-result-list-element/search-result-list-element.component.ts
index 72120a6b68..e56b7e970a 100644
--- a/src/app/shared/object-list/search-result-list-element/search-result-list-element.component.ts
+++ b/src/app/shared/object-list/search-result-list-element/search-result-list-element.component.ts
@@ -33,7 +33,7 @@ export class SearchResultListElementComponent, K exten
ngOnInit(): void {
if (hasValue(this.object)) {
this.dso = this.object.indexableObject;
- this.dsoTitle = this.dsoNameService.getName(this.dso);
+ this.dsoTitle = this.dsoNameService.getHitHighlights(this.object, this.dso);
}
}
diff --git a/src/app/shared/shared.module.ts b/src/app/shared/shared.module.ts
index 4bc0b2ccf7..7a1c7e8116 100644
--- a/src/app/shared/shared.module.ts
+++ b/src/app/shared/shared.module.ts
@@ -186,7 +186,6 @@ import {
ImportableListItemControlComponent
} from './object-collection/shared/importable-list-item-control/importable-list-item-control.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 { LogInComponent } from './log-in/log-in.component';
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 { ScopeSelectorModalComponent } from './search-form/scope-selector-modal/scope-selector-modal.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 { LogInOrcidComponent } from './log-in/methods/orcid/log-in-orcid.component';
import { BrowserOnlyPipe } from './utils/browser-only.pipe';
import { ThemedLoadingComponent } from './loading/themed-loading.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';
import { ThemedCollectionDropdownComponent } from './collection-dropdown/themed-collection-dropdown.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 {
AdvancedClaimedTaskActionRatingComponent
@@ -352,8 +350,6 @@ const COMPONENTS = [
ListableNotificationObjectComponent,
DsoPageEditButtonComponent,
MetadataFieldWrapperComponent,
- AdvancedClaimedTaskActionSelectReviewerComponent,
- AdvancedClaimedTaskActionRatingComponent,
];
const ENTRY_COMPONENTS = [
@@ -393,9 +389,7 @@ const ENTRY_COMPONENTS = [
MetadataRepresentationListElementComponent,
ItemMetadataRepresentationListElementComponent,
LogInPasswordComponent,
- LogInShibbolethComponent,
- LogInOidcComponent,
- LogInOrcidComponent,
+ LogInExternalProviderComponent,
ClaimedTaskActionsDeclineTaskComponent,
CollectionDropdownComponent,
ThemedCollectionDropdownComponent,
diff --git a/src/assets/i18n/en.json5 b/src/assets/i18n/en.json5
index 5ece443a31..d024587104 100644
--- a/src/assets/i18n/en.json5
+++ b/src/assets/i18n/en.json5
@@ -3903,6 +3903,8 @@
"submission.import-external.source.crossref": "CrossRef",
+ "submission.import-external.source.datacite": "DataCite",
+
"submission.import-external.source.scielo": "SciELO",
"submission.import-external.source.scopus": "Scopus",