@universis/candidates
Version:
Universis api server plugin for study program candidates, internship selection etc
181 lines (173 loc) • 4.84 kB
JavaScript
import { EdmMapping, EdmType } from '@themost/data';
import EnableAttachmentModel from './EnableAttachmentModel';
import unirest from 'unirest';
import {
DataError,
HttpError,
DataNotFoundError,
TraceUtils,
} from '@themost/common';
import { toXlsx } from '../middlewares';
function tryCloseStream(stream) {
if (stream && typeof stream.close === 'function') {
try {
stream.close();
} catch (error) {
TraceUtils.warn(
`(tryCloseStream) An error occurred while trying to close a stream.`
);
TraceUtils.warn(error);
}
}
}
.entityType('CandidateSource')
class CandidateSource extends EnableAttachmentModel {
constructor() {
super();
}
.param('file', EdmType.EdmStream, false)
.action('attachConfigurationSchema', 'Attachment')
async attachConfigurationSchema(file) {
try {
const context = this.context;
// validate self
const self = await context
.model('CandidateSource')
.where('id')
.equal(this.getId())
.getItem();
if (self == null) {
throw new DataNotFoundError();
}
const attachment = Object.assign(
{
name: file.contentFileName,
},
file
);
// try to add attachment
const result = await super.addAttachment(attachment);
// close stream
tryCloseStream(file);
// define schemaURL based on added attachment's url
self.schemaURL = result.url;
// update (do not use silent)
await context.model('CandidateSource').save(self);
// and return the attachment
return result;
} catch (err) {
// try to close stream
tryCloseStream(file);
// and throw error
throw err;
}
}
.func('exportCandidates', EdmType.EdmStream)
async exportFromSource() {
const context = this.context;
// fetch and validate self
const self = await context
.model('CandidateSource')
.where('id')
.equal(this.getId())
.getItem();
if (self == null) {
throw new DataNotFoundError(
'The specified candidate source cannot be found or is inaccessible.'
);
}
// validate source url
if (!(self.externalSource && self.sourceURL)) {
throw new DataError(
'E_EXT_SOURCE_URL',
'The external source url cannot be empty while exporting students.',
null,
'CandidateSource',
'sourceURL'
);
}
let keychainItem = null;
// check if the source has some keychain identifier
if (self.keychainIdentifier) {
// and validate it
const keychain = context
.getConfiguration()
.getSourceAt('settings/universis/keychain');
// first of all, validate keychain existance
if (!(Array.isArray(keychain) && keychain.length)) {
throw new DataError(
'E_KEYCHAIN_CONFIG',
'The process cannot continue due to invalid keychain configuration.'
);
}
// then try to find the specified identifier
keychainItem = keychain.find(
(item) => item.identifier === self.keychainIdentifier
);
if (keychainItem == null) {
throw new DataError(
'E_KEYCHAIN_ITEM',
'The specified keychain identifier cannot be found inside the keychain configuration',
null,
'CandidateSource',
'keychainIdentifier'
);
}
}
// prepare request
const CandidatesDataRequest = unirest
.get(new URL(self.sourceURL))
.header('Accept', 'application/json')
.header('Content-Type', 'application/json');
// if keychain item requires auth
if (keychainItem && keychainItem.authorizationType) {
switch (keychainItem.authorizationType) {
case 'Basic':
// validate username and password
if (!(keychainItem.username && keychainItem.password)) {
throw new DataError(
'E_CREDENTIALS',
'The username and/or password is/are missing from the keychain configuration. The process cannot continue.'
);
}
// apply basic auth header to request
CandidatesDataRequest.header(
'Authorization',
'Basic ' +
Buffer.from(
`${keychainItem.username}:${keychainItem.password}`
).toString('base64')
);
break;
default:
// throw error for not yet implemented auth type
throw new DataError(
'E_AUTH_TYPE',
'The specified authorization type is not yet implemented.'
);
}
}
// and send the request
return await new Promise((resolve, reject) => {
return CandidatesDataRequest.end(function (response) {
// handle errors first
if (response.error) {
if (response.clientError) {
return reject(new HttpError(response.error.status));
}
return reject(response.error);
}
// convert response body (json) to xlsx
return toXlsx(response.body)
.then((buffer) => {
// and resolve the buffer
return resolve(buffer);
})
.catch((err) => {
return reject(err);
});
});
});
}
}
module.exports = CandidateSource;