Skip to content

Commit

Permalink
1377 patch: implement auth validation at subfield level (#1378)
Browse files Browse the repository at this point in the history
* implement auth validation at subfield level

* bugfix; error handling

---------

Co-authored-by: jbukhari <[email protected]>
  • Loading branch information
jbukhari and jbukhari authored Apr 1, 2024
1 parent 3c7cbf3 commit 7e5faa9
Show file tree
Hide file tree
Showing 2 changed files with 68 additions and 67 deletions.
44 changes: 18 additions & 26 deletions dlx_rest/static/js/import.js
Original file line number Diff line number Diff line change
Expand Up @@ -196,34 +196,28 @@ export let importcomponent = {
// records? If not, error and prevent import.
let validationErrors = []
let fatalErrors = []

if (jmarc.fields.length > 0) {
jmarc.symbolInUse().then( symbolInUse => {
if (symbolInUse) {
this.issues += 1
validationErrors.push({"message": "Duplicate Symbol Warning: The symbol for this record is already in use."})
}
})
for (let field of jmarc.fields) {
let auth = jmarc.authMap[field.tag]
if (auth) {
let headingTag = Object.values(auth)[0]
let thisAuth = new Jmarc("auths")
let newField = thisAuth.createField(headingTag)
for (let subfield of field.subfields) {
if (Object.keys(auth).includes(subfield.code)) {
let newSub = newField.createSubfield(subfield.code)
newSub.value = subfield.value
}
});

for (let field of jmarc.fields.filter(x => ! x.tag.match(/^00/))) {
for (let subfield of field.subfields.filter(x => 'xref' in x)) {
if (subfield.xref instanceof Error) {
// unresolved xrefs are set to an Error object
fatalErrors.push({"message": `Fatal: ${field.tag} ${field.toStr()}`})
}
thisAuth.authExists().then( authExists => {
if (!authExists) {
fatalErrors.push({"message": `Fatal: ${field.tag} ${field.toStr()} has an unmatched or ambiguous authority value. Create the authority record or edit this record before importing.`})
}
})
}
}
}

this.records.push({"jmarc": jmarc, "mrk": mrk, "validationErrors": validationErrors, "fatalErrors": fatalErrors, "checked": false})
}
}).catch(error => {
throw error
})
}
}
Expand All @@ -250,18 +244,16 @@ export let importcomponent = {
}
}
},
submit(record) {
async submit(record) {
let binary = new Blob([record['mrk']])
let jmarc = record['jmarc']
// Only allow one click, so we don't accidentally post multiple records
//e.target.classList.add("disabled")
jmarc.post_mrk(binary).then(
response => {
jmarc.recordId = response.recordId
return response
}
)
return 0
return jmarc.post()
.catch(error => {
// may need some user notifcation here?
throw error
})
},
filterView(e) {
let values = [e.target.value]
Expand Down
91 changes: 50 additions & 41 deletions dlx_rest/static/js/jmarc.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,44 @@ export class Subfield {

return flags
}

async detectAndSetXref() {
/* Tries to look up and set the subfield xref given the subfield value.
Sets xref to an error object if the xref is not found or ambiguous */

const field = this.parentField;
const jmarc = field.parentRecord;
const isAuthorityControlled = jmarc.isAuthorityControlled(field.tag, this.code);

if (isAuthorityControlled) {


const searchStr =
field.subfields
.filter(x => Object.keys(authMap[jmarc.collection][field.tag]).includes(x.code))
.map(x => `${authMap[jmarc.collection][field.tag][x.code]}__${x.code}:'${x.value}'`)
.join(" AND ");

const xref = await fetch(Jmarc.apiUrl + "marc/auths/records?search=" + encodeURIComponent(searchStr))
.then(response => response.json())
.then(json => {
const recordsList = json['data'];

if (recordsList.length === 0) {
return new Error("Unmatched heading")
} else if (recordsList.length > 1) {
return new Error("Ambiguous heading")
} else {
// get the xref from the URL
const parts = recordsList[0].split("/");
return parts[parts.length - 1]
}
}).catch(error => {throw error})

this.xref = xref
return xref
}
}
}

class LinkedSubfield extends Subfield {
Expand Down Expand Up @@ -203,7 +241,7 @@ export class DataField {
this.parentRecord.deleteField(this);
}
} else if (this.tag in amap && subfield.code in amap[this.tag] && ! subfield.xref) {
throw new Error("Invalid authority-controlled value")
throw new Error(`Invalid authority-controlled value: ${this.tag} ${subfield.code} ${subfield.value}`)
}
}
}
Expand Down Expand Up @@ -701,31 +739,35 @@ export class Jmarc {

static async fromMrk(mrk, collection="bibs") {
let jmarc = new Jmarc(collection)

for (let line of mrk.split("\n")) {
let match = line.match(/=(\w{3}) (.*)/)

if (match != null){
let tag = match[1]
let rest = match[2]
if (tag == 'LDR') {
tag = '000'
}
let field = jmarc.createField(tag)
if (field instanceof BibDataField || field instanceof AuthDataField) {

let field = jmarc.createField(tag);
if (field instanceof(ControlField)) {
field.value = rest;
continue
} else {
let indicators = rest.substring(0,2).replace(/\\/g, " ")
jmarc.indicators = [indicators.charAt(0), indicators.charAt(1)]
field.indicators = [indicators.charAt(0), indicators.charAt(1)]
for (let subfield of rest.substring(2, rest.length).split("$")) {
if (subfield.length > 0) {
let code = subfield.substring(0,1)
let value = subfield.substring(1, subfield.length)

if (code.length > 0 && value.length > 0) {
let newSub = field.createSubfield(code)
newSub.value = value
newSub.value = value
await newSub.detectAndSetXref();
}
}
}
} else {
field.value = rest
}
}
}
Expand Down Expand Up @@ -778,39 +820,6 @@ export class Jmarc {
)
}

async post_mrk(content) {
let savedResponse
const formData = new FormData()
return fetch (
this.collectionUrl + '/records?format=mrk',
{
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: content
}
).then (
response => {
savedResponse = response
return response.json()
}
).then (
json => {
//console.log(json)
if (savedResponse.status != 201) {
throw new Error(json['message'])
}

this.url = json['result'];
this.recordId = parseInt(this.url.split('/').slice(-1));
this.updateSavedState();

return Jmarc.get(this.collection, this.recordId)
}
).catch (
error => { throw new Error(error) }
)
}

async put() {
if (! this.recordId) {
return Promise.reject("Can't PUT new record")
Expand Down

0 comments on commit 7e5faa9

Please sign in to comment.