UNPKG

@universis/candidates

Version:

Universis api server plugin for study program candidates, internship selection etc

213 lines (209 loc) 11.9 kB
"use strict";var _fs = _interopRequireDefault(require("fs")); var _path = _interopRequireDefault(require("path")); var _stream = require("stream"); var _exceljs = require("exceljs");function _interopRequireDefault(obj) {return obj && obj.__esModule ? obj : { default: obj };} const XlsxContentType = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'; /** * * @param {PostXlsWithConfigOptions} options * @returns {function(*, *, *): *} */ function xlsPostParserWithConfig(options) { return function (req, res, next) {var _options$name, _options$schema; let opts = Object.assign({ name: 'file', schema: 'schema' }, options); // get file key name let name = (_options$name = options === null || options === void 0 ? void 0 : options.name) !== null && _options$name !== void 0 ? _options$name : opts.name; let schema = (_options$schema = options === null || options === void 0 ? void 0 : options.schema) !== null && _options$schema !== void 0 ? _options$schema : opts.schema; if (req !== null && req !== void 0 && req.files && req !== null && req !== void 0 && req.files[name] && Array.isArray(req === null || req === void 0 ? void 0 : req.files[name]) && req !== null && req !== void 0 && req.files[schema] && Array.isArray(req === null || req === void 0 ? void 0 : req.files[schema])) { const files = req === null || req === void 0 ? void 0 : req.files[name][0]; const config = req === null || req === void 0 ? void 0 : req.files[schema][0]; let configStream; try { configStream = JSON.parse(_fs.default.readFileSync(_path.default.resolve(config.destination, config.filename))); } catch (err) { // throw error for invalid json file return next(err); } // get header row, use fixed value if not defined in config const headerRow = configStream.headerRow || 3; // get columns const columns = configStream.columns; // find max merged column depth, use fixed value if not defined in config let maxLevel = 0; columns.forEach(column => { if (column !== null && column !== void 0 && column.isMerged) {var _column$isMerged; if (column !== null && column !== void 0 && (_column$isMerged = column.isMerged) !== null && _column$isMerged !== void 0 && _column$isMerged.value) { const level = column.isMerged.level; if (level > maxLevel) { maxLevel = level; } } } }); if (files.mimetype === XlsxContentType || /\.(xlsx)$/i.test(files.originalname) && files.mimetype === 'application/octet-stream') { let stream; if (files.buffer instanceof Buffer) { stream = new _stream.Readable(); stream.push(files.buffer); stream.push(null); } else { try { stream = _fs.default.createReadStream(_path.default.resolve(files.destination, files.filename)); } catch (err) { return next(err); } } let body = [],headers = []; // read from a file let workbook = new _exceljs.Workbook(); return workbook.xlsx.read(stream). then(() => { // read workbook let sheet = workbook.getWorksheet(1); sheet.eachRow((row, rowNumber) => { if (rowNumber >= headerRow) { if (rowNumber === headerRow + maxLevel) { headers = row.values; // replace whitespace in headers with a single space headers = headers.map(x => x.replace(/\s/g, " ").trim()); } else { let res = {}; row.values.forEach((v, k) => { if (k > 0) {var _columnInConfig$prope; const columnInConfig = columns.find(column => {var _column$property;return (column === null || column === void 0 ? void 0 : (_column$property = column.property) === null || _column$property === void 0 ? void 0 : _column$property.title.trim()) === headers[k];}); // if property is virtual (not used by model), return if (columnInConfig !== null && columnInConfig !== void 0 && columnInConfig.virtual) { return; } // if it is needed but is not mapped to a model attribute, throw error if (!(columnInConfig !== null && columnInConfig !== void 0 && (_columnInConfig$prope = columnInConfig.property) !== null && _columnInConfig$prope !== void 0 && _columnInConfig$prope.modelAttribute)) { return next(new Error(`Invalid configuration. Model attribute is not defined for column ${headers[k]}`)); } if (!(columnInConfig !== null && columnInConfig !== void 0 && columnInConfig.dataMappings)) {var _v, _v2, _columnInConfig$prope2; if (typeof v === 'object' && (_v = v) !== null && _v !== void 0 && _v.text && (_v2 = v) !== null && _v2 !== void 0 && _v2.hyperlink) { v = v.text; } // attributes may be like "property/childProperty for nested objects. // this makes sure that the correct object is created by splitting the // model attribute to property and childProperty and then appends the // the childProperties to the parent object. if (columnInConfig !== null && columnInConfig !== void 0 && (_columnInConfig$prope2 = columnInConfig.property) !== null && _columnInConfig$prope2 !== void 0 && _columnInConfig$prope2.modelAttribute.includes('/')) {var _columnInConfig$prope3, _columnInConfig$prope4, _columnInConfig$prope5, _columnInConfig$prope6; if (!res[columnInConfig === null || columnInConfig === void 0 ? void 0 : (_columnInConfig$prope3 = columnInConfig.property) === null || _columnInConfig$prope3 === void 0 ? void 0 : _columnInConfig$prope3.modelAttribute.split('/')[0]]) res[columnInConfig === null || columnInConfig === void 0 ? void 0 : (_columnInConfig$prope4 = columnInConfig.property) === null || _columnInConfig$prope4 === void 0 ? void 0 : _columnInConfig$prope4.modelAttribute.split('/')[0]] = {}; if (typeof v === 'string') { v = v.trim(); if (v.length === 0) { // convert empty string to null v = null; } } res[columnInConfig === null || columnInConfig === void 0 ? void 0 : (_columnInConfig$prope5 = columnInConfig.property) === null || _columnInConfig$prope5 === void 0 ? void 0 : _columnInConfig$prope5.modelAttribute.split('/')[0]][columnInConfig === null || columnInConfig === void 0 ? void 0 : (_columnInConfig$prope6 = columnInConfig.property) === null || _columnInConfig$prope6 === void 0 ? void 0 : _columnInConfig$prope6.modelAttribute.split('/')[1]] = v; } else {var _columnInConfig$prope7; if (typeof v === 'string') { v = v.trim(); if (v.length === 0) { // convert empty string to null v = null; } } res[columnInConfig === null || columnInConfig === void 0 ? void 0 : (_columnInConfig$prope7 = columnInConfig.property) === null || _columnInConfig$prope7 === void 0 ? void 0 : _columnInConfig$prope7.modelAttribute] = v; } } else {var _columnInConfig$prope8, _configStream; // get data mappings let mappings = columnInConfig.dataMappings; // find from value const value = mappings.find(x => x.from == v); // if it is not defined, throw error if (!value) { return next(new Error(`Invalid configuration. Incorrect or missing data mappings for column ${headers[k]}`)); } if (res[columnInConfig === null || columnInConfig === void 0 ? void 0 : (_columnInConfig$prope8 = columnInConfig.property) === null || _columnInConfig$prope8 === void 0 ? void 0 : _columnInConfig$prope8.modelAttribute]) {var _columnInConfig$prope9, _columnInConfig$prope10; // append to object if it already exists res[columnInConfig === null || columnInConfig === void 0 ? void 0 : (_columnInConfig$prope9 = columnInConfig.property) === null || _columnInConfig$prope9 === void 0 ? void 0 : _columnInConfig$prope9.modelAttribute] = { ...value.to, ...res[columnInConfig === null || columnInConfig === void 0 ? void 0 : (_columnInConfig$prope10 = columnInConfig.property) === null || _columnInConfig$prope10 === void 0 ? void 0 : _columnInConfig$prope10.modelAttribute] }; } else {var _columnInConfig$prope11; res[columnInConfig === null || columnInConfig === void 0 ? void 0 : (_columnInConfig$prope11 = columnInConfig.property) === null || _columnInConfig$prope11 === void 0 ? void 0 : _columnInConfig$prope11.modelAttribute] = value.to; } // append extra attributes if ((_configStream = configStream) !== null && _configStream !== void 0 && _configStream.extraAttributes) { configStream.extraAttributes.forEach(x => { res[x.modelAttribute] = x.defaultValue; }); } } } }); body.push(res); } } }); req.body = body; return next(); }).catch(err => { return next(err); }); } return next(); } else { return next(new Error("Missing candidate students xlsx file or its json schema.")); } }; } /** * Allows data conversion to xls, independent from res. Similar to xlsParser function * @param {*} data The data to be converted * @returns Xlsx buffer */ function toXlsx(data) { return new Promise((resolve, reject) => { if (Array.isArray(data)) { const workbook = new _exceljs.Workbook(); const sheet = workbook.addWorksheet('Sheet1'); let rows = data.map(row => { let res = {}; Object.keys(row).forEach(key => { // if attribute is an object if (typeof row[key] === 'object' && row[key] !== null) { // if attribute has property name if (row[key].hasOwnProperty('name')) { // return this name res[key] = row[key]['name']; } else { // otherwise return object res[key] = row[key]; } } else { // set property value res[key] = row[key]; } }); return res; }); // add columns if (rows.length > 0) { sheet.columns = Object.keys(rows[0]).map(key => { return { header: key, key: key }; }); } rows.forEach(row => { sheet.addRow(row); }); // write to a new buffer return workbook.xlsx.writeBuffer().then(buffer => { return resolve(buffer); }).catch(err => { return reject(err); }); } else { return reject('Unprocessable entity'); } }); } module.exports.xlsPostParserWithConfig = xlsPostParserWithConfig; module.exports.XlsxContentType = XlsxContentType; module.exports.toXlsx = toXlsx; //# sourceMappingURL=xls.js.map