-
-
Notifications
You must be signed in to change notification settings - Fork 28
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Issue #2541
- Loading branch information
Showing
3 changed files
with
152 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
define(["backbone"], (Backbone) => { | ||
const CACHE_PREFIX = "crossref_"; | ||
/** | ||
* @class CrossRef | ||
* @classdesc Handles querying CrossRef API for metadata about a DOI. | ||
* @classcategory Models | ||
* @augments Backbone.Model | ||
* @constructs | ||
* @augments Backbone.Model | ||
* @since 0.0.0 | ||
*/ | ||
const CrossRef = Backbone.Model.extend( | ||
/** @lends CrossRef.prototype */ | ||
{ | ||
/** @inheritdoc */ | ||
type: "CrossRef", | ||
|
||
/** | ||
* Defaults for the CrossRef model. | ||
* @type {object} | ||
* @property {string} baseURL - The base URL for the CrossRef API. | ||
* @property {string} email - The email address to use for "polite" | ||
* requests. See https://github.com/CrossRef/rest-api-doc#good-manners--more-reliable-service). | ||
*/ | ||
defaults() { | ||
return { | ||
baseURL: | ||
MetacatUI.appModel.get("crossRefAPI") || | ||
"https://api.crossref.org/works/", | ||
email: MetacatUI.appModel.get("emailContact") || "", | ||
}; | ||
}, | ||
|
||
/** @inheritdoc */ | ||
url() { | ||
let doi = this.get("doi"); | ||
if (!doi) return null; | ||
// Make sure the DOI is formatted correctly | ||
doi = MetacatUI.appModel.removeAllDOIPrefixes(doi); | ||
this.set("doi", doi); | ||
const doiStr = encodeURIComponent(doi); | ||
const email = this.get("email"); | ||
const emailStr = email ? `?mailto:${email}` : ""; | ||
const baseURL = this.get("baseURL"); | ||
const url = `${baseURL}${doiStr}${emailStr}`; | ||
return url; | ||
}, | ||
|
||
/** @inheritdoc */ | ||
fetch() { | ||
// first check if there's a cached response | ||
const doi = this.get("doi"); | ||
const cachedResponse = this.getCachedResponse(doi); | ||
if (cachedResponse) { | ||
this.set(cachedResponse); | ||
return; | ||
} | ||
|
||
const url = this.url(); | ||
if (!url) return; | ||
const model = this; | ||
// Make the request using native fetch | ||
fetch(url) | ||
.then((response) => { | ||
if (!response.ok) { | ||
throw new Error("Network response was not ok"); | ||
} | ||
return response.json(); | ||
}) | ||
.then((responseJSON) => { | ||
const parsedData = responseJSON.message; | ||
model.cacheResponse(doi, parsedData); | ||
model.set(parsedData); | ||
model.trigger("sync"); | ||
}) | ||
.catch((error) => { | ||
model.trigger("error", error); | ||
model.set("error", "fetchError"); | ||
model.set("errorMessage", error.message); | ||
}); | ||
}, | ||
|
||
/** | ||
* Cache the response from the CrossRef API | ||
* @param {string} doi The DOI for the response | ||
* @param {object} response The response from the CrossRef API | ||
*/ | ||
cacheResponse(doi, response) { | ||
localStorage.setItem(`${CACHE_PREFIX}${doi}`, JSON.stringify(response)); | ||
}, | ||
|
||
/** | ||
* Get the cached response for a DOI | ||
* @param {string} doi The DOI to get the cached response for | ||
* @returns {object|null} The cached response or null if there is no cached response | ||
*/ | ||
getCachedResponse(doi) { | ||
const cachedResponse = localStorage.getItem(`${CACHE_PREFIX}${doi}`); | ||
if (!cachedResponse) return null; | ||
return JSON.parse(cachedResponse); | ||
}, | ||
|
||
/** Clear the cache of CrossRef responses */ | ||
clearCache() { | ||
const keysToRemove = Object.keys(localStorage).filter((key) => | ||
key.startsWith(CACHE_PREFIX), | ||
); | ||
keysToRemove.forEach((key) => localStorage.removeItem(key)); | ||
}, | ||
}, | ||
); | ||
|
||
return CrossRef; | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
"use strict"; | ||
|
||
define(["/test/js/specs/shared/clean-state.js", "models/CrossRefModel"], ( | ||
cleanState, | ||
CrossRef, | ||
) => { | ||
const should = chai.should(); | ||
const expect = chai.expect; | ||
|
||
describe("CrossRef Test Suite", () => { | ||
const state = cleanState(() => { | ||
// Example DOI from: | ||
|
||
// Jerrentrup, A., Mueller, T., Glowalla, U., Herder, M., Henrichs, N., | ||
// Neubauer, A., & Schaefer, J. R. (2018). Teaching medicine with the | ||
// help of “Dr. House.” PLoS ONE, 13(3), Article e0193972. | ||
// https://doi.org/10.1371/journal.pone.0193972 | ||
const crossRef = new CrossRef({ | ||
doi: "https://doi.org/10.1371/journal.pone.0193972", | ||
}); | ||
return { crossRef }; | ||
}, beforeEach); | ||
|
||
it("creates a CrossRef instance", () => { | ||
state.crossRef.should.be.instanceof(CrossRef); | ||
}); | ||
|
||
it("forms valid fetch URLs", () => { | ||
const url = state.crossRef.url(); | ||
|
||
url.should.be.a("string"); | ||
url.should.include("https://api.crossref.org/works/"); | ||
url.should.include("10.1371%2Fjournal.pone.0193972"); | ||
url.should.include("?mailto:[email protected]"); | ||
}); | ||
}); | ||
}); |