Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@ services/base-service/spa/client/public/bundle.js
services/base-service/spa/client/public/js/
services/base-service/spa/client/dist/
/log/
/harvest/ae-harvest-cache
213 changes: 26 additions & 187 deletions services/base-service/models/sitefarm/api.js
Original file line number Diff line number Diff line change
@@ -1,168 +1,41 @@
const express = require('express');
const router = require('express').Router();
const { config, keycloak, dataModels, logger } = require('@ucd-lib/fin-service-utils');
const path = require('path');

const { dataModels } = require('@ucd-lib/fin-service-utils');
const BaseModel = require('../base/model.js');
const ExpertModel = require('../expert/model.js');
const template = require('./template/modified-date.js');
const expert = new ExpertModel();
const base = new BaseModel();
// const experts = new ExpertModel();

const { defaultEsApiGenerator } = dataModels;
// const {config, keycloak} = require('@ucd-lib/fin-service-utils');
const md5 = require('md5');

const { openapi, json_only, validate_admin_client, validate_miv_client, has_access, fetchExpertId, convertIds } = require('../middleware/index.js')


function siteFarmFormat(req, res, next) {
// This function will take the query return of expert data and format it for sitefarm

var newArray = [];
for (let i in res.doc_array) {
// Expecting a single expert document
let doc = res.doc_array[i];

// Subselect to experts and their works - max return 5 works
doc = expert.subselect(
doc,
{
'is-visible' : true,
expert : { include : true },
grants : {
include : false,
exclude: [
"totalAwardAmount"
],
includeMisformattedd: false,
sort: [
{
"field": "dateTimeInterval.end.dateTime",
"sort": "desc",
"type": "date"
},
{
"field": "name",
"sort": "asc",
"type": "string"
}
]
},
works : {
include :true,
page : 1,
size : 5,
includeMisformatted : false,
sort : [
{
"field": "issued",
"sort": "desc",
"type": "year"
},
{
"field": "title",
"sort": "asc",
"type": "string"
} ]
}
} );

let newDoc = {};

newDoc["@id"] = doc["@id"];
newDoc["publications"] = [];
newDoc["contactInfo"] = doc.contactInfo || {};
newDoc["contactInfo"].hasURL = []; // initialize to empty array
// We need to dig down for the preferred contactInfo website list
// We will grab the first website that is not preferred and has a rank of 20 indicating it is a website list
let websites = doc["@graph"][i].contactInfo?.filter(c => (!c['isPreferred'] || c['isPreferred'] === false) && c['rank'] === 20 && c.hasURL);

// ... but also grab all preferred contactInfo details
for (let j = 0; j < doc["@graph"].length; j++) {
if (doc["@graph"][j]["@type"].includes("Expert")) {
if (doc["@graph"][j]["contactInfo"].isPreferred === true) {
newDoc["contactInfo"] = doc["@graph"][j].contactInfo;
}
}
// If the node is a Work, copy it to the publications array
else if (doc["@graph"][j]["@type"].includes("Work")) {
newDoc["publications"].push(doc["@graph"][j]);
}
}

// Copy other Expert properties to the new document
newDoc["orcidId"] = doc["@graph"][i].orcidId;
newDoc["overview"] = doc["@graph"][i].overview;
newDoc["researcherId"] = doc["@graph"][i].researcherId;
newDoc["scopusId"] = doc["@graph"][i].scopusId;

// Include the website list we filtered for above
newDoc["contactInfo"].hasURL = websites.length > 0 && websites[0].hasURL ? websites[0].hasURL : null;

// ensure website @type's are arrays
if( newDoc["contactInfo"].hasURL ) {
if( !Array.isArray(newDoc["contactInfo"].hasURL) ) {
newDoc["contactInfo"].hasURL = [newDoc["contactInfo"].hasURL];
}
newDoc["contactInfo"].hasURL.forEach((url) => {
let atType = Array.isArray(url['@type']) ? url['@type'] : [url['@type']];
url["@type"] = atType;
});
}

// preserve the modified-date
newDoc["modified-date"] = doc["modified-date"];
newArray.push(newDoc);
}
res.doc_array = newArray;
next();
}


function sitefarm_valid_path(options={}) {
const def = {
"description": "A JSON array of expert profiles including their publications",
"parameters": [
{
"in": "path",
"name": "ids",
"description": "A comma separated list of expert IDs. Ids are in the format of '{idType}:{Id}'. For example 'expertId:12345'",
"required": true,
"schema": {
"type": "string"
}
}
],
};

(options.parameters || []).forEach((param) => {
def.parameters.push(openapi.parameters(param));
});

delete options.parameters;

return openapi.validPath({...def, ...options});
}
const {
openapi,
validate_admin_client,
validate_miv_client,
has_access,
convertIds
} = require('../middleware/index.js')

function sitefarm_valid_path_error(err, req, res, next) {
return res.status(err.status).json({
error: err.message,
validation: err.validationErrors,
schema: err.validationSchema
})
}
const {
siteFarmDefaultSearch,
siteFarmFormat,
siteFarmPreviewFormat,
sitefarm_valid_path,
sitefarm_valid_path_error
} = require('./utils.js');


// This will serve the generated json document(s)
// (as well as the swagger-ui if configured)
router.use(openapi);

const path = require('path');

router.get('/', (req, res) => {
// Send the pre-made swagger.json file
res.sendFile(path.join(__dirname, 'swagger.json'));
// res.redirect('/api/sitefarm/openapi.json');
if( 'preview' in req.query ) {
return res.sendFile(path.join(__dirname, 'swagger-preview.json'));
}
return res.sendFile(path.join(__dirname, 'swagger.json'));
});

router.get(
Expand All @@ -182,47 +55,13 @@ router.get(
validate_miv_client,
has_access('sitefarm'),
convertIds, // convert submitted iamIds to expertIds
async (req, res, next) => {
const expert_model = await model.get_model('expert');
res.doc_array = [];
var doc;
// validate the modified_since date
if (req.query.modified_since) {
const modifiedSinceDate = new Date(req.query.modified_since);
const [year, month, day] = req.query.modified_since.split('-').map(Number);
const isValidDate = modifiedSinceDate.getFullYear() === year &&
modifiedSinceDate.getMonth() + 1 === month &&
modifiedSinceDate.getDate() === day;
if (isNaN(modifiedSinceDate.getTime()) || !isValidDate) {
return res.status(400).json({ error: 'Invalid modified_since date format' });
}
siteFarmDefaultSearch, // sets up search params including modified_since, base es search
(req, res, next) => {
if( 'preview' in req.query ) {
return siteFarmPreviewFormat(req, res, next);
}
const gte_date = req.query.modified_since || '2021-01-01';
const params={
"gte_date": gte_date,
"expert": []
};

if (req?.query.expert) {
params.expert = req.query.expert.split(',');
}
let opts = {
"id": "modified-date",
"params": params
};
await expert.verify_template(template);
res.doc_array = [];
var find = null
try {
find = await base.search(opts);
res.doc_array = find.hits;
res.doc_array = find.hits;
} catch (error) {
return res.status(500).json({ error: 'Error fetching expert data', details: error.message });
}
next();
return siteFarmFormat(req, res, next);
},
siteFarmFormat,
(req, res) => {
res.status(200).json(res.doc_array);
}
Expand Down
Loading