Skip to content

Commit

Permalink
document: improve import control
Browse files Browse the repository at this point in the history
If no identifier has been selected for the control,
we try to search by the main title

* Closes rero/rero-ils#3031.

Co-Authored-by: Bertrand Zuchuat <bertrand.zuchuat@rero.ch>
  • Loading branch information
Garfield-fr committed Oct 3, 2022
1 parent aea6fae commit a9a01ce
Showing 1 changed file with 115 additions and 83 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* RERO ILS UI
* Copyright (C) 2019 RERO
* Copyright (C) 2019-2022 RERO
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
Expand All @@ -22,9 +22,10 @@ import { Record, RecordService } from '@rero/ng-core';
import { DetailRecord } from '@rero/ng-core/lib/record/detail/view/detail-record';
import { cloneDeep } from 'lodash-es';
import { BsModalService } from 'ngx-bootstrap/modal';
import { forkJoin, Observable, of, Subscription } from 'rxjs';
import { Observable, of, Subscription } from 'rxjs';
import { switchMap } from 'rxjs/operators';
import { DocumentApiService } from '../../../api/document-api.service';
import { IdentifierTypes } from '../../../classes/identifiers';
import { OperationLogsService } from '../../../service/operation-logs.service';
import { DialogImportComponent } from './dialog-import/dialog-import.component';

Expand Down Expand Up @@ -57,13 +58,23 @@ export class DocumentDetailViewComponent implements DetailRecord, OnInit, OnDest
ddCssClass = 'col-sm-6 col-md-8 mb-0';

/** Mapping types for import */
private mappingtypes = {
private _mappingtypes = {
'bf:Ean': 'bf:Isbn',
'bf:Isbn': 'bf:Isbn',
'bf:Issn': 'bf:IssnL',
'bf:IssnL': 'bf:Issn'
};

/** Identifiers used to check for duplicates */
private _identifiersList = [
IdentifierTypes.ISBN,
IdentifierTypes.ISSN,
IdentifierTypes.DOI,
IdentifierTypes.LCCN,
IdentifierTypes.L_ISSN,
IdentifierTypes.EAN
];

/**
* Is operation log enabled
* @return boolean
Expand All @@ -72,6 +83,54 @@ export class DocumentDetailViewComponent implements DetailRecord, OnInit, OnDest
return this._operationLogsService.isLogVisible('documents');
}

/** Source for imported record. */
get source() {
if (this._activatedRouter.snapshot && this._activatedRouter.snapshot.params && this._activatedRouter.snapshot.params.type !== null) {
return this._activatedRouter.snapshot.params.type.replace('import_', '');
}
return null;
}

/** External identifier for imported record. */
get pid(): string | null {
if (this._activatedRouter.snapshot && this._activatedRouter.snapshot.params && this._activatedRouter.snapshot.params.pid !== null) {
return this._activatedRouter.snapshot.params.pid;
}
return null;
}

/**
* Related resources to display below 'Subjects'
*/
get relatedResources() {
if (this.record.metadata.electronicLocator) {
return this.record.metadata.electronicLocator.filter(
(electronicLocator: any) => [
'hiddenUrl', 'noInfo', 'resource', 'relatedResource', 'versionOfResource'
].some(t => t === electronicLocator.type && electronicLocator.content !== 'coverImage')
);
}
}

/**
* Resources to display like a holding
*/
get resources() {
if (this.record.metadata.electronicLocator) {
return this.record.metadata.electronicLocator.filter(
(electronicLocator: any) => ['resource', 'versionOfResource'].some(t => t === electronicLocator.type)
);
}
}

/**
* Get Current language interface
* @return string - language
*/
get currentLanguage(): string {
return this._translateService.currentLang;
}

/**
* Constructor
* @param _translateService - TranslateService to translate some strings.
Expand All @@ -93,7 +152,7 @@ export class DocumentDetailViewComponent implements DetailRecord, OnInit, OnDest
) { }

/** On init hook */
ngOnInit() {
ngOnInit(): void {
this._recordObs = this.record$.pipe(
switchMap((record: any) => {
this.record = record;
Expand All @@ -114,6 +173,20 @@ export class DocumentDetailViewComponent implements DetailRecord, OnInit, OnDest
});
}

/** On destroy hook */
ngOnDestroy(): void {
this._recordObs.unsubscribe();
}

/**
* Allow to filter provisionActivity keeping only activities that are 'Publication'
* @param element: the element to check
* @return True if element is a 'Publication', False otherwise
*/
filterPublicationProvisionActivity(element: any): boolean {
return ('key' in element && element.key === 'bf:Publication');
}

/**
* Import Document
* @param event - Event
Expand All @@ -122,21 +195,42 @@ export class DocumentDetailViewComponent implements DetailRecord, OnInit, OnDest
*/
importDocument(event: Event, record: any, data: { source: string, pid: string }): void {
event.preventDefault();
const keysTypes = Object.keys(this.mappingtypes);
const rec = record.metadata;
const route = ['/records', 'documents', 'new'];
const queryParams = [];
// If we have identifiers
if (rec.identifiedBy) {
const queryParams = [];
rec.identifiedBy.forEach((identifier: any) => {
if (['bf:Isbn', 'bf:Issn', 'bf:Doi', 'bf:Lccn', 'bf:IssnL', 'bf:Ean'].includes(identifier.type)) {
// We select only a defined part of the identifier
rec.identifiedBy
.filter((identifier: any) => this._identifiersList.includes(identifier.type))
.map((identifier: any) => {
queryParams.push(this._extractAndFormatQueryParams(identifier));
if (keysTypes.indexOf(identifier.type) > -1) {
if (identifier.type in this._mappingtypes) {
const cidentifier = cloneDeep(identifier);
cidentifier.type = this.mappingtypes[cidentifier.type];
cidentifier.type = this._mappingtypes[cidentifier.type];
queryParams.push(this._extractAndFormatQueryParams(cidentifier));
}
});
}

// If we do not have a identifier and we have a title
// TODO: Nice to have - create an backend API entrypoint to detect the duplicate resource.
// https://github.com/rero/rero-ils/issues/2900 (Generalize to all resources)
if (queryParams.length === 0 && rec.title) {
// We extract the title
const titles = rec.title.filter((rtitle: any) => rtitle.type === 'bf:Title' && '_text' in rtitle);
if (titles.length > 0) {
// We clean the text string by deleting some characters
const regex = /["\[\]]/gi;
queryParams.push(`title._text:"${titles[0]._text.replace(regex, '')}"`);
}
});
}

// No identifier and no title, we redirect to the add form.
if (queryParams.length === 0) {
this._router.navigate(route, { queryParams: data });
} else {
// Find documents(s) with query params
const query = queryParams.join(' OR ');
this._recordService.getRecords(
'documents', query, 1, undefined, undefined, undefined, { accept: 'application/rero+json' }
Expand All @@ -157,70 +251,6 @@ export class DocumentDetailViewComponent implements DetailRecord, OnInit, OnDest
});
}
});
} else {
this._router.navigate(route, { queryParams: data });
}
}

/** Source for imported record. */
get source() {
if (this._activatedRouter.snapshot && this._activatedRouter.snapshot.params && this._activatedRouter.snapshot.params.type !== null) {
return this._activatedRouter.snapshot.params.type.replace('import_', '');
}
return null;
}

/** External identifier for imported record. */
get pid() {
if (this._activatedRouter.snapshot && this._activatedRouter.snapshot.params && this._activatedRouter.snapshot.params.pid !== null) {
return this._activatedRouter.snapshot.params.pid;
}
return null;
}

/** On destroy hook */
ngOnDestroy(): void {
this._recordObs.unsubscribe();
}

/**
* Get Current language interface
* @return string - language
*/
get currentLanguage() {
return this._translateService.currentLang;
}

/**
* Allow to filter provisionActivity keeping only activities that are 'Publication'
* @param element: the element to check
* @return True if element is a 'Publication', False otherwise
*/
filterPublicationProvisionActivity(element: any): boolean {
return ('key' in element && element.key === 'bf:Publication');
}

/**
* Related resources to display below 'Subjects'
*/
get relatedResources() {
if (this.record.metadata.electronicLocator) {
return this.record.metadata.electronicLocator.filter(
(electronicLocator: any) => [
'hiddenUrl', 'noInfo', 'resource', 'relatedResource', 'versionOfResource'
].some(t => t === electronicLocator.type && electronicLocator.content !== 'coverImage')
);
}
}

/**
* Resources to display like a holding
*/
get resources() {
if (this.record.metadata.electronicLocator) {
return this.record.metadata.electronicLocator.filter(
(electronicLocator: any) => ['resource', 'versionOfResource'].some(t => t === electronicLocator.type)
);
}
}

Expand Down Expand Up @@ -258,15 +288,20 @@ export class DocumentDetailViewComponent implements DetailRecord, OnInit, OnDest
getPartOfLabel(hostDocument: any) {
switch (hostDocument.metadata.issuance.subtype) {
case 'periodical':
return this._translateService.instant('Journal');
return this._translateService.instant('Journal');
case 'monographicSeries':
return this._translateService.instant('Series');
return this._translateService.instant('Series');
default:
return this._translateService.instant('Published in');
return this._translateService.instant('Published in');
}
}

contributionTypeParam(contribution: any) {
/**
* Translate the type of the contribution for url
* @param contribution - document contribution
* @returns string, the translated type
*/
contributionTypeParam(contribution: any): string {
switch (contribution.type) {
case 'bf:Person':
return 'persons';
Expand All @@ -282,14 +317,11 @@ export class DocumentDetailViewComponent implements DetailRecord, OnInit, OnDest
* @param identifier - IdentifiedBy object
* @return string, query formatted
*/
private _extractAndFormatQueryParams(identifier: any): string {
private _extractAndFormatQueryParams(identifier: any): string {
const query = [];
/* const type = identifier.type.replace(/:/g, '\\:');
const value = identifier.value.replace(/:/g, '\\:'); */
query.push(`identifiedBy.type:"${identifier.type}"`);
query.push(`identifiedBy.value:"${identifier.value}"`);
if (identifier.source) {
/* const source = identifier.source.replace(/:/g, '\\:'); */
query.push(`identifiedBy.source:"${identifier.source}"`);
}
return `(${query.join(' AND ')})`;
Expand Down

0 comments on commit a9a01ce

Please sign in to comment.