- added new class CollectionRole.ts
All checks were successful
CI Pipeline / japa-tests (push) Successful in 50s
All checks were successful
CI Pipeline / japa-tests (push) Successful in 50s
- added relation 'collectionRole' to Collection.ts class - added 'ListSets' and =GetRecord request for OaiController.ts - npm updates - added utility-functions.ts
This commit is contained in:
parent
ebb24cc75c
commit
2a7480d2ed
9 changed files with 349 additions and 91 deletions
|
@ -10,7 +10,11 @@ import { StatusCodes } from 'http-status-codes';
|
|||
import { transform } from 'saxon-js';
|
||||
// import { Xslt, xmlParse } from 'xslt-processor'
|
||||
import { OaiErrorCodes, OaiModelError } from 'App/Exceptions/OaiErrorCodes';
|
||||
import { OaiModelException } from 'App/Exceptions/OaiModelException';
|
||||
import { OaiModelException, BadOaiModelException } from 'App/Exceptions/OaiModelException';
|
||||
import Dataset from 'App/Models/Dataset';
|
||||
import Collection from 'App/Models/Collection';
|
||||
import { getDomain } from 'App/Utils/utility-functions';
|
||||
import XmlModel from 'App/Library/XmlModel';
|
||||
|
||||
interface XslTParameter {
|
||||
[key: string]: any;
|
||||
|
@ -21,9 +25,12 @@ interface Dictionary {
|
|||
}
|
||||
|
||||
export default class OaiController {
|
||||
// private deliveringDocumentStates = ["published", "deleted"];
|
||||
private deliveringDocumentStates = ['published', 'deleted'];
|
||||
// private sampleRegEx = /^[A-Za-zäüÄÜß0-9\-_.!~]+$/;
|
||||
private xsltParameter: XslTParameter;
|
||||
// private configuration: Configuration;
|
||||
// private tokenWorker: TokenWorker;
|
||||
|
||||
/**
|
||||
* Holds xml representation of document information to be processed.
|
||||
*
|
||||
|
@ -61,7 +68,7 @@ export default class OaiController {
|
|||
}
|
||||
// const oaiRequest: OaiParameter = request.body;
|
||||
try {
|
||||
this.handleRequest(oaiRequest, request);
|
||||
await this.handleRequest(oaiRequest, request);
|
||||
} catch (error) {
|
||||
if (error instanceof OaiModelException) {
|
||||
const code = error.oaiCode;
|
||||
|
@ -106,7 +113,7 @@ export default class OaiController {
|
|||
response.status(StatusCodes.OK).send(xmlOutput);
|
||||
}
|
||||
|
||||
protected handleRequest(oaiRequest: Dictionary, request: RequestContract) {
|
||||
protected async handleRequest(oaiRequest: Dictionary, request: RequestContract) {
|
||||
// Setup stylesheet
|
||||
// $this->loadStyleSheet('datasetxml2oai-pmh.xslt');
|
||||
|
||||
|
@ -130,17 +137,17 @@ export default class OaiController {
|
|||
this.handleIdentify();
|
||||
} else if (verb === 'ListMetadataFormats') {
|
||||
this.handleListMetadataFormats();
|
||||
} else if (verb == 'GetRecord') {
|
||||
await this.handleGetRecord(oaiRequest);
|
||||
}
|
||||
// else if (verb == "GetRecord") {
|
||||
// await this.handleGetRecord(oaiRequest);
|
||||
// } else if (verb == "ListRecords") {
|
||||
// else if (verb == "ListRecords") {
|
||||
// await this.handleListRecords(oaiRequest);
|
||||
// } else if (verb == "ListIdentifiers") {
|
||||
// await this.handleListIdentifiers(oaiRequest);
|
||||
// } else if (verb == "ListSets") {
|
||||
// await this.handleListSets();
|
||||
// }
|
||||
else {
|
||||
else if (verb == 'ListSets') {
|
||||
await this.handleListSets();
|
||||
} else {
|
||||
this.handleIllegalVerb();
|
||||
}
|
||||
} else {
|
||||
|
@ -182,6 +189,206 @@ export default class OaiController {
|
|||
this.xml.root().ele('Datasets');
|
||||
}
|
||||
|
||||
protected async handleListSets() {
|
||||
const repIdentifier = 'tethys.at';
|
||||
this.xsltParameter['repIdentifier'] = repIdentifier;
|
||||
const datasetElement = this.xml.root().ele('Datasets');
|
||||
|
||||
const sets: { [key: string]: string } = {
|
||||
'open_access': 'Set for open access licenses',
|
||||
'doc-type:ResearchData': 'Set for document type ResearchData',
|
||||
// ...(await this.getSetsForDatasetTypes()),
|
||||
...(await this.getSetsForCollections()),
|
||||
// ... await this.getSetsForProjects(),
|
||||
} as Dictionary;
|
||||
|
||||
for (const [key, value] of Object.entries(sets)) {
|
||||
const setElement = datasetElement.ele('Rdr_Sets');
|
||||
setElement.att('Type', key);
|
||||
setElement.att('TypeName', value);
|
||||
}
|
||||
}
|
||||
|
||||
protected async handleGetRecord(oaiRequest: Dictionary) {
|
||||
const repIdentifier = 'tethys.at';
|
||||
this.xsltParameter['repIdentifier'] = repIdentifier;
|
||||
|
||||
const dataId = this.validateAndGetIdentifier(oaiRequest);
|
||||
const dataset = await Dataset.query().where('publish_id', dataId).preload('xmlCache').preload('collections').first();
|
||||
|
||||
if (!dataset || !dataset.publish_id) {
|
||||
throw new OaiModelException(
|
||||
StatusCodes.INTERNAL_SERVER_ERROR,
|
||||
'The value of the identifier argument is unknown or illegal in this repository.',
|
||||
OaiErrorCodes.IDDOESNOTEXIST,
|
||||
);
|
||||
}
|
||||
|
||||
const metadataPrefix = this.validateAndGetMetadataPrefix(oaiRequest);
|
||||
this.xsltParameter['oai_metadataPrefix'] = metadataPrefix;
|
||||
// do not deliver datasets which are restricted by document state defined in deliveringStates
|
||||
this.validateDatasetState(dataset);
|
||||
|
||||
// add xml elements
|
||||
const datasetNode = this.xml.root().ele('Datasets');
|
||||
await this.createXmlRecord(dataset, datasetNode);
|
||||
}
|
||||
|
||||
private validateAndGetIdentifier(oaiRequest: Dictionary): number {
|
||||
// Identifier references metadata Urn, not plain Id!
|
||||
// Currently implemented as 'oai:foo.bar.de:{docId}' or 'urn:nbn...-123'
|
||||
if (!('identifier' in oaiRequest)) {
|
||||
throw new BadOaiModelException('The prefix of the identifier argument is unknown.');
|
||||
}
|
||||
const dataId = Number(this.getDocumentIdByIdentifier(oaiRequest.identifier));
|
||||
if (isNaN(dataId)) {
|
||||
throw new OaiModelException(
|
||||
StatusCodes.INTERNAL_SERVER_ERROR,
|
||||
'The value of the identifier argument is illegal in this repository.',
|
||||
OaiErrorCodes.BADARGUMENT,
|
||||
);
|
||||
}
|
||||
return dataId;
|
||||
}
|
||||
|
||||
private validateAndGetMetadataPrefix(oaiRequest: Dictionary): string {
|
||||
let metadataPrefix = '';
|
||||
if ('metadataPrefix' in oaiRequest) {
|
||||
metadataPrefix = oaiRequest['metadataPrefix'];
|
||||
} else {
|
||||
throw new OaiModelException(
|
||||
StatusCodes.INTERNAL_SERVER_ERROR,
|
||||
'The prefix of the metadata argument is unknown.',
|
||||
OaiErrorCodes.BADARGUMENT,
|
||||
);
|
||||
}
|
||||
return metadataPrefix;
|
||||
}
|
||||
|
||||
private validateDatasetState(dataset: Dataset): void {
|
||||
if (dataset.server_state == null || !this.deliveringDocumentStates.includes(dataset.server_state)) {
|
||||
throw new OaiModelException(
|
||||
StatusCodes.INTERNAL_SERVER_ERROR,
|
||||
'Document is not available for OAI export!',
|
||||
OaiErrorCodes.NORECORDSMATCH,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private async createXmlRecord(dataset: Dataset, datasetNode: XMLBuilder) {
|
||||
const domNode = await this.getDatasetXmlDomNode(dataset);
|
||||
|
||||
if (domNode) {
|
||||
// add frontdoor url and data-type
|
||||
dataset.publish_id && this.addLandingPageAttribute(domNode, dataset.publish_id.toString());
|
||||
this.addSpecInformation(domNode, 'data-type:' + dataset.type);
|
||||
|
||||
// if (dataset.collections) {
|
||||
// for (const coll of dataset.collections) {
|
||||
// const collRole = await coll.getCollectionRole();
|
||||
// this.addSpecInformation(domNode, collRole.oai_name + ':' + coll.number);
|
||||
// }
|
||||
// }
|
||||
|
||||
datasetNode.import(domNode);
|
||||
}
|
||||
}
|
||||
|
||||
private async getDatasetXmlDomNode(dataset: Dataset) {
|
||||
const xmlModel = new XmlModel(dataset);
|
||||
// xmlModel.setModel(dataset);
|
||||
xmlModel.excludeEmptyFields();
|
||||
xmlModel.caching = true;
|
||||
// const cache = dataset.xmlCache ? dataset.xmlCache : null;
|
||||
// dataset.load('xmlCache');
|
||||
if (dataset.xmlCache) {
|
||||
xmlModel.xmlCache = dataset.xmlCache;
|
||||
}
|
||||
|
||||
// return cache.getDomDocument();
|
||||
const domDocument: XMLBuilder | null = await xmlModel.getDomDocument();
|
||||
return domDocument;
|
||||
}
|
||||
|
||||
private addSpecInformation(domNode: XMLBuilder, information: string) {
|
||||
domNode.ele('SetSpec').att('Value', information);
|
||||
}
|
||||
|
||||
private addLandingPageAttribute(domNode: XMLBuilder, dataid: string) {
|
||||
const baseDomain = process.env.BASE_DOMAIN || 'localhost';
|
||||
const url = 'https://' + getDomain(baseDomain) + '/dataset/' + dataid;
|
||||
// add attribute du dataset xml element
|
||||
domNode.att('landingpage', url);
|
||||
}
|
||||
|
||||
private getDocumentIdByIdentifier(oaiIdentifier: string): string {
|
||||
const identifierParts: string[] = oaiIdentifier.split(':'); // explode(":", $oaiIdentifier);
|
||||
const dataId: string = identifierParts[2];
|
||||
// switch (identifierParts[0]) {
|
||||
// case 'oai':
|
||||
// if (isset($identifierParts[2])) {
|
||||
// $dataId = $identifierParts[2];
|
||||
// }
|
||||
// break;
|
||||
// default:
|
||||
// throw new OaiModelException(
|
||||
// 'The prefix of the identifier argument is unknown.',
|
||||
// OaiModelError::BADARGUMENT
|
||||
// );
|
||||
// break;
|
||||
// }
|
||||
|
||||
// if (empty($dataId) or !preg_match('/^\d+$/', $dataId)) {
|
||||
// throw new OaiModelException(
|
||||
// 'The value of the identifier argument is unknown or illegal in this repository.',
|
||||
// OaiModelError::IDDOESNOTEXIST
|
||||
// );
|
||||
|
||||
return dataId;
|
||||
}
|
||||
|
||||
private async getSetsForCollections(): Promise<Dictionary> {
|
||||
const sets: { [key: string]: string } = {} as Dictionary;
|
||||
|
||||
const collections = await Collection.query()
|
||||
.select('name', 'number', 'role_id')
|
||||
.whereHas('collectionRole', (query) => {
|
||||
query.where('visible_oai', true);
|
||||
})
|
||||
.preload('collectionRole');
|
||||
|
||||
collections.forEach((collection) => {
|
||||
// if collection has a collection role (classification like ddc):
|
||||
if (collection.number) {
|
||||
// collection.load('collectionRole');
|
||||
const setSpec = collection.collectionRole?.oai_name + ':' + collection.number;
|
||||
sets[setSpec] = `Set ${collection.number} '${collection.name}'`;
|
||||
}
|
||||
});
|
||||
return sets;
|
||||
}
|
||||
|
||||
// private async getSetsForDatasetTypes(): Promise<IDictionary> {
|
||||
// const sets: { [key: string]: string } = {} as IDictionary;
|
||||
|
||||
// const datasets: Array<Dataset> = await Dataset.findAll({
|
||||
// attributes: ["type"],
|
||||
// where: { server_state: { [Sequelize.Op.eq]: "published" } },
|
||||
// });
|
||||
// datasets.forEach((dataset) => {
|
||||
// if (dataset.type && false == preg_match(this.sampleRegEx, dataset.type)) {
|
||||
// const msg = `Invalid SetSpec (data-type='${dataset.type}').
|
||||
// Allowed characters are [${this.sampleRegEx}].`;
|
||||
// Logger.err(`OAI: ${msg}`);
|
||||
// // Log::error("OAI-PMH: $msg");
|
||||
// return;
|
||||
// }
|
||||
// const setSpec = "data-type:" + dataset.type;
|
||||
// sets[setSpec] = `Set for document type '${dataset.type}'`;
|
||||
// });
|
||||
// return sets;
|
||||
// }
|
||||
|
||||
private handleIllegalVerb() {
|
||||
this.xsltParameter['oai_error_code'] = 'badVerb';
|
||||
this.xsltParameter['oai_error_message'] = 'The verb provided in the request is illegal.';
|
||||
|
|
|
@ -33,8 +33,8 @@ import ClamScan from 'clamscan';
|
|||
import { ValidationException } from '@ioc:Adonis/Core/Validator';
|
||||
import Drive from '@ioc:Adonis/Core/Drive';
|
||||
import { Exception } from '@adonisjs/core/build/standalone';
|
||||
import XmlModel from 'App/Library/XmlModel';
|
||||
import { XMLBuilder } from 'xmlbuilder2/lib/interfaces';
|
||||
// import XmlModel from 'App/Library/XmlModel';
|
||||
// import { XMLBuilder } from 'xmlbuilder2/lib/interfaces';
|
||||
|
||||
export default class DatasetController {
|
||||
public async index({ auth, request, inertia }: HttpContextContract) {
|
||||
|
@ -579,23 +579,6 @@ export default class DatasetController {
|
|||
'files.extnames': 'file extension is not supported',
|
||||
};
|
||||
|
||||
private async getDatasetXmlDomNode(dataset: Dataset) {
|
||||
// dataset.fetchValues();
|
||||
const xmlModel = new XmlModel(dataset);
|
||||
// xmlModel.setModel(dataset);
|
||||
xmlModel.excludeEmptyFields();
|
||||
xmlModel.caching = true;
|
||||
// const cache = dataset.xmlCache ? dataset.xmlCache : null;
|
||||
// dataset.load('xmlCache');
|
||||
if (dataset.xmlCache) {
|
||||
xmlModel.xmlCache = dataset.xmlCache;
|
||||
}
|
||||
|
||||
// return cache.getDomDocument();
|
||||
const domDocument: XMLBuilder | null = await xmlModel.getDomDocument();
|
||||
return domDocument;
|
||||
}
|
||||
|
||||
// public async release({ params, view }) {
|
||||
public async release({ request, inertia, response }: HttpContextContract) {
|
||||
const id = request.param('id');
|
||||
|
|
Loading…
Add table
editor.link_modal.header
Reference in a new issue