marvin/src/DocCreator.js
2022-09-16 07:34:59 +02:00

478 lines
18 KiB
JavaScript

// Modules
import createReport from 'docx-templates';
import fs, {writeFile} from 'fs';
import {mkdir} from 'node:fs/promises';
import path from 'path';
import replaceSpecialCharacters from "replace-special-characters";
import {parseString, Builder} from 'xml2js';
////////////////////
// Main //
////////////////////
class DocCreator {
constructor(log, objectData) {
// Assign Log.
this.log = log;
// Assign general object data.
this.objectData = objectData;
// Get DateTime.
this.today = new Date();
// Get config file and parse to json.
this.configFile = fs.readFileSync('/resources/files/config/config.json')
this.configJson = JSON.parse(this.configFile.toString())
// Choose the template for selected document type.
switch (objectData.dokumenttyp) {
case 'rp':
this.documentInfo = {
documentType: 'restaurierungsprotokolle', docTypeAbbr: 'rp', templateFile: 'rp-template.docx',
}
break;
case 'lbb':
this.documentInfo = {
documentType: 'leihgabenbegleitblaetter', docTypeAbbr: 'lbb', templateFile: 'lbb-template.docx',
}
break;
case 'a':
this.documentInfo = {
documentType: 'analysen', docTypeAbbr: 'a', templateFile: 'a-template.docx',
}
break;
}
// ObjectId normalisation.
const normCharacterObjectId = replaceSpecialCharacters(objectData.inventarnummer);
this.normObjectId = normCharacterObjectId.replace("__", "_");
// Title normalisation
const replaceEszettTitle = objectData.titel.replace("ß", "-ss-");
let replaceUmlauteTitle = replaceEszettTitle.replace(/[^Ä]+/ig, "Ae");
replaceUmlauteTitle = replaceUmlauteTitle.replace(/[^ä]+/ig, "ae");
replaceUmlauteTitle = replaceUmlauteTitle.replace(/[^Ö]+/ig, "Oe");
replaceUmlauteTitle = replaceUmlauteTitle.replace(/[^ö]+/ig, "oe");
replaceUmlauteTitle = replaceUmlauteTitle.replace(/[^Ü]+/ig, "Ue");
replaceUmlauteTitle = replaceUmlauteTitle.replace(/[^ü]+/ig, "ue");
const normCharacterTitle = replaceSpecialCharacters(replaceUmlauteTitle);
const normSingleSpaceTitle = normCharacterTitle.replace("__", "_");
const normSpacingTitle = normSingleSpaceTitle.replace(/[^A-Z0-9\-]+/ig, "_");
this.normTitle = normSpacingTitle.slice(0, 50);
const folderName = this.normObjectId + '__' + this.normTitle
this.objectPath = path.join(this.configJson.rootDir, folderName);
this.documentPath = path.join(this.objectPath, this.documentInfo.documentType, objectData.datum);
this.filename = this.normObjectId + '__' + this.normTitle + '__' + this.objectData.datum + '__' + this.objectData.dokumenttyp;
this.filenameWithExtension = this.filename + '.docx'
this.temporaryWorkDirPath = path.join(this.objectPath, 'werkstatt');
}
// Fills the docx template.
async fillTemplate() {
// Variables
let buffer;
let configJson
// Create docx document if there was a response.
if (this.objectData.httpStatus === 200) {
try {
// Read template.
const template = fs.readFileSync(path.join('/resources/files/templates/', this.documentInfo.templateFile));
// Create report.
buffer = await createReport({
template, data: {
inventarnummer: this.objectData.inventarnummer ? this.objectData.inventarnummer : 'unbekannt',
titel: this.objectData.titel ? this.objectData.titel : 'unbekannt',
hersteller: this.objectData.hersteller ? this.objectData.hersteller : 'unbekannt',
herstellungsort: this.objectData.herstellungsort ? this.objectData.herstellungsort : 'unbekannt',
herstellungsdatum: this.objectData.herstellungsdatum ? this.objectData.herstellungsdatum : 'unbekannt',
materialTechnik: this.objectData.materialTechnik ? this.objectData.materialTechnik : 'unbekannt',
masse: this.objectData.masse ? this.objectData.masse : 'unbekannt'
}
});
} catch (err) {
// Set error log.
this.log = {
...this.log,
status: 'red',
message: 'Konnte Template nicht erstellen: ' + err,
tip: 'Ist das Template vorhanden?',
};
return this.log
}
try {
const createDocumentPath = await mkdir(this.documentPath, {recursive: true});
const createTemporaryWorkDirPath = await mkdir(this.temporaryWorkDirPath, {recursive: true});
} catch (err) {
// Set error log.
this.log = {
...this.log,
status: 'red',
message: 'Konnte den Pfad nicht erstellen' + err,
tip: 'Bestehen Schreibrechte auf dem Ordner?'
}
return this.log
}
// Write document to disk.
if (buffer) {
fs.writeFileSync(path.join(this.documentPath, this.filenameWithExtension), buffer)
this.log = {
...this.log, status: 'green', message: 'Dokument erstellt',
};
}
} else {
this.log = {
status: 'red',
message: 'Fehler bei der Kommunikation mit dem Objektkatalog',
code: this.objectData.httpStatus,
tip: 'Ist die Inventarnummer richtig?',
};
}
return this.log;
}
async createMetsMods() {
const metsModsString = `
<mets:mets
xmlns:mets="http://www.loc.gov/METS/"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="info:lc/xmlns/premis-v2
http://www.loc.gov/standards/premis/v2/premis-v2-0.xsd
http://www.loc.gov/mods/v3
http://www.loc.gov/standards/mods/v3/mods-3-6.xsd
http://www.loc.gov/METS/
http://www.loc.gov/standards/mets/version17/mets.v1-7.xsd
http://www.loc.gov/mix/v10
http://www.loc.gov/standards/mix/mix10/mix10.xsd">
<mets:metsHdr createDate="${this.today}">
<mets:agent
type="other"
otherType="software"
role="creator">
<mets:name>
${process.env.REACT_APP_NAME} v${process.env.REACT_APP_VERSION}
</mets:name>
</mets:agent>
</mets:metsHdr>
<mets:fileSec>
<mets:fileGrp use="${this.documentInfo.documentType}">
<mets:file id="file__${this.filename}" mimeType="application/vnd.openxmlformats-officedocument.wordprocessingml.document">
<mets:FLocat locType="other" otherLocType="file" xlink:href="${this.filenameWithExtension}"/>
</mets:file>
</mets:fileGrp>
</mets:fileSec>
<mets:structMap type="physical">
<mets:div type="${this.documentInfo.docTypeAbbr}" id="phys_00" dmdid="dmdphys_00">
<mets:fptr fileId="file__${this.filename}"/>
</mets:div>
</mets:structMap>
<mets:structMap type="logical">
<mets:div type="${this.documentInfo.docTypeAbbr}" id="phys_00">
<mets:fptr fileId="file__${this.filename}"/>
</mets:div>
</mets:structMap>
<mets:dmdSec id="dmdlog_00">
<mets:mdWrap mdType="mods">
<mets:xmlData>
<mods:mods xmlns:mods="http://www.loc.gov/mods/v3">
<mods:recordInfo>
<mods:recordIdentifier source="https://objektkatalag.gnm.de">${this.objectData.inventarnummer}</mods:recordIdentifier>
</mods:recordInfo>
<mods:titleInfo>
<mods:title>${this.objectData.titel}</mods:title>
</mods:titleInfo>
<mods:originInfo>
<mods_dateIssued encoding="w3cdtf" keyDate="yes">${this.objectData.herstellungsdatum}</mods_dateIssued>
<mods:place>
<mods:placeTerm type="text">${this.objectData.herstellungsort}</mods:placeTerm>
</mods:place>
</mods:originInfo>
<mods:name type="personal">
<mods:role>
<mods:roleTerm authority="marcrelator" type="code">cre</mods:roleTerm>
</mods:role>
<mods:namePart>${this.objectData.herstellungsort}</mods:namePart>
<mods:displayForm>${this.objectData.herstellungsort}</mods:displayForm>
</mods:name>
<mods:physicalDescription>
<mods:form type="Material and Technique" lang="de"/>
<mods:extent>${this.objectData.masse}</mods:extent>
</mods:physicalDescription>
</mods:mods>
</mets:xmlData>
</mets:mdWrap>
</mets:dmdSec>
</mets:mets>
`
const metModsJson = {
'mets:mets': {
$: {
'xmlns:mets': "http://www.loc.gov/METS/",
'xmlns:xlink': "http://www.w3.org/1999/xlink",
'xmlns:xsi': "http://www.w3.org/2001/XMLSchema-instance",
'xsi:schemaLocation': "info:lc/xmlns/premis-v2 http://www.loc.gov/standards/premis/v2/premis-v2-0.xsd " +
"http://www.loc.gov/mods/v3 http://www.loc.gov/standards/mods/v3/mods-3-6.xsd " +
"http://www.loc.gov/METS/ http://www.loc.gov/standards/mets/version17/mets.v1-7.xsd " +
"http://www.loc.gov/mix/v10 http://www.loc.gov/standards/mix/mix10/mix10.xsd"
},
'mets:metsHdr': {
$: {
// Creation date of the mets/mods xml.
'createDate': this.today // Should be w3ctdf format: YYYY-MM-DDThh:mm:ssTZD
},
'mets:agent': {
// App, which created the xml document
$: {
'type': 'other',
'otherType': 'software',
'role': 'creator'
},
'mets:name': {
// App name and version
_: `${process.env.REACT_APP_NAME} v${process.env.REACT_APP_VERSION}`
}
}
},
'mets:fileSec': {
'mets:fielGrp': {
$: {
// Documenttype
'use': `${this.documentInfo.documentType}`
},
'mets:file': {
// Phyical file
$: {
'id': `file__${this.filename}`,
'mimeType': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
},
'mets:FLocat': {
// Physical location - here in same folder
$: {
'locType': 'other',
'otherLocType': 'file',
'xlink:href': `${this.filenameWithExtension}`
}
}
}
}
},
'mets:structMap': [
{ // These are solo documents only, this may be inappropriate.
$: {
// Physical structure.
'type': 'physical'
},
'mets:div': {
$: {
// Documenttype and id.
'type': `${this.documentInfo.docTypeAbbr}`,
// since we have only one document, id and dmdid are static.
'id': `phys_00`,
'dmdid': 'dmdphys_00'
},
'mets:fptr': {
$: {
// File id from above
'fileId': `file__${this.filename}`
}
}
}
},
{ // These are solo documents only, this may be inappropriate.
$: {
// Physical structure.
'type': 'logical'
},
'mets:div': {
$: {
// Documenttype and id.
'type': `${this.documentInfo.docTypeAbbr}`,
// since we have only one document, id and dmdid are static.
'id': `phys_00`,
'dmdid': 'dmdphys_00'
},
'mets:fptr': {
$: {
// File id from above
'fileId': `file__${this.filename}`
}
}
}
}],
'mets:dmdSec':
{
$: {
// Since we have only one document, dmdlog is static
'id':
`dmdlog_00`
}
,
'mets:mdWrap':
{
$: {
'mdType':
'mods'
}
,
'mets:xmlData':
{
'mods:mods':
{
// Object properties as found at https://objektkatalog.gnm.de.
$: {
'xmlns:mods':
'http://www.loc.gov/mods/v3'
}
,
'mods:recordInfo':
{
'mods:recordIdentifier':
{
// ObjectId.
$: {
'source':
'https://objektkatalag.gnm.de'
}
,
_: `${this.objectData.inventarnummer}`
}
}
,
'mods:titleInfo':
{
// Title.
'mods:title':
{
_: `${this.objectData.titel}`
}
}
,
'mods:originInfo':
{
// Creation date.
'mods_dateIssued':
{
$: {
'encoding':
'w3cdtf', // W3C Date and Time, should be YYYY-MM-DDThh:mm:ssTZD
'keyDate':
'yes'
}
,
_: `${this.objectData.herstellungsdatum}`
}
,
'mods:place':
{
// Creation place
'mods:placeTerm':
{
$: {
'type':
'text'
}
,
_: `${this.objectData.herstellungsort}`
}
}
}
,
'mods:name':
{
// Creator.
$: {
'type':
'personal'
}
,
'mods:role':
{
'mods:roleTerm':
{
$: {
'authority':
'marcrelator',
'type':
'code'
}
,
_: 'cre'
}
}
,
'mods:namePart':
{
_: this.objectData.hersteller
}
,
'mods:displayForm':
{
_: this.objectData.hersteller
}
}
,
'mods:physicalDescription':
{
'mods:form':
{
$: {
'type':
'Material and Technique',
'lang':
'de'
}
}
,
'mods:extent':
{
_: `${this.objectData.masse}`
}
}
}
}
}
}
}
}
let metModsXml
parseString(metsModsString, {trim: true},
function (err, result) {
metModsXml = result;
}
);
console.log(metModsXml, 'from string');
const builder = new Builder()
metModsXml = builder.buildObject(metModsJson);
console.log(metModsXml, 'from Json')
const fileName = `.metsMods__${this.normObjectId}__${this.normTitle}.xml`
fs.writeFileSync(path.join(this.documentPath,fileName),metModsXml.toString(),
function (err) {
if (err) {
console.log(err);
} else {
console.log("The file was saved!");
}
}
)
return true;
}
}
export {DocCreator};