From f94653f389cc24f8ffea210b31cb604db9eabbc4 Mon Sep 17 00:00:00 2001 From: VLE2FE Date: Tue, 11 Aug 2020 16:06:51 +0200 Subject: [PATCH 1/4] improved globals and added status and spectrum --- src/db.ts | 4 +-- src/globals.ts | 32 +++++++++++++-------- src/helpers/authorize.ts | 15 ++++++++-- src/helpers/flatten.ts | 5 ++-- src/index.ts | 6 ++-- src/models/changelog.ts | 2 +- src/routes/material.ts | 20 ++++++------- src/routes/measurement.spec.ts | 1 - src/routes/measurement.ts | 14 ++++----- src/routes/root.ts | 2 +- src/routes/sample.ts | 46 ++++++++++++------------------ src/routes/user.ts | 6 ++-- src/routes/validate/material.ts | 3 +- src/routes/validate/measurement.ts | 5 ++-- src/routes/validate/root.ts | 2 +- src/routes/validate/sample.ts | 12 ++++---- src/routes/validate/user.ts | 2 +- src/test/db.json | 8 +++--- src/test/helper.ts | 4 +-- 19 files changed, 101 insertions(+), 88 deletions(-) diff --git a/src/db.ts b/src/db.ts index 933cdc1..2beb95a 100644 --- a/src/db.ts +++ b/src/db.ts @@ -146,7 +146,7 @@ export default class db { }); new ChangelogModel({ action: req.method + ' ' + req.url, - collectionName: thisOrCollection._collection.collectionName, + collection_name: thisOrCollection._collection.collectionName, conditions: thisOrCollection._conditions, data: data, user_id: req.authDetails.id ? req.authDetails.id : null @@ -157,7 +157,7 @@ export default class db { else { // (req, collection, conditions, data) new ChangelogModel({ action: req.method + ' ' + req.url, - collectionName: thisOrCollection, + collection_name: thisOrCollection, conditions: conditions, data: data, user_id: req.authDetails.id ? req.authDetails.id : null diff --git a/src/globals.ts b/src/globals.ts index 2928a89..d1f3d85 100644 --- a/src/globals.ts +++ b/src/globals.ts @@ -1,16 +1,24 @@ -const globals = { - levels: [ // access levels, sorted asc by rights - 'read', - 'write', - 'dev', - 'admin' - ], +// globals for required names in the database. change values here to rename these properties +// the keys are the terms used internally, the values can be changed to other terms used in database and output - status: [ // document statuses - 'deleted', - 'new', - 'validated', - ] +const globals = { + levels: { // access levels, sorted asc by rights + read: 'read', + write: 'write', + dev: 'dev', + admin: 'admin' + }, + + status: { // names of the document statuses + del: 'deleted', + new: 'new', + val: 'validated', + }, + + spectrum: { // names of required spectrum fields + spectrum: 'spectrum', + dpt: 'dpt' + } }; export default globals; \ No newline at end of file diff --git a/src/helpers/authorize.ts b/src/helpers/authorize.ts index 03d344b..bfd6bd3 100644 --- a/src/helpers/authorize.ts +++ b/src/helpers/authorize.ts @@ -1,6 +1,7 @@ import basicAuth from 'basic-auth'; import bcrypt from 'bcryptjs'; import UserModel from '../models/user'; +import globals from '../globals'; // appends req.auth(res, ['levels'], method = 'all') @@ -64,7 +65,12 @@ function basic (req, next): any { // checks basic auth and returns changed user bcrypt.compare(auth.pass, data[0].pass, (err, res) => { // check password if (err) return next(err); if (res === true) { // password correct - resolve({level: data[0].level, name: data[0].name, id: data[0]._id.toString(), location: data[0].location}); + resolve({ + level: Object.entries(globals.levels).find(e => e[1] === data[0].level)[0], + name: data[0].name, + id: data[0]._id.toString(), + location: data[0].location + }); } else { resolve(null); @@ -88,7 +94,12 @@ function key (req, next): any { // checks API key and returns changed user obje UserModel.find({key: req.query.key}).lean().exec( (err, data: any) => { // find user if (err) return next(err); if (data.length === 1) { // one user found - resolve({level: data[0].level, name: data[0].name, id: data[0]._id.toString(), location: data[0].location}); + resolve({ + level: Object.entries(globals.levels).find(e => e[1] === data[0].level)[0], + name: data[0].name, + id: data[0]._id.toString(), + location: data[0].location + }); if (!/^\/api/m.test(req.url)){ delete req.query.key; // delete query parameter to avoid interference with later validation } diff --git a/src/helpers/flatten.ts b/src/helpers/flatten.ts index 5c2d7d5..deb3af9 100644 --- a/src/helpers/flatten.ts +++ b/src/helpers/flatten.ts @@ -1,11 +1,12 @@ +import globals from '../globals'; + export default function flatten (data, keepArray = false) { // flatten object: {a: {b: true}} -> {a.b: true} const result = {}; function recurse (cur, prop) { if (Object(cur) !== cur || Object.keys(cur).length === 0) { result[prop] = cur; } - else if (prop === 'spectrum.dpt') { - console.log('dpt'); + else if (prop === `${globals.spectrum.spectrum}.${globals.spectrum.dpt}`) { result[prop + '.labels'] = cur.map(e => e[0]); result[prop + '.values'] = cur.map(e => e[1]); } diff --git a/src/index.ts b/src/index.ts index a749f6c..1e763b7 100644 --- a/src/index.ts +++ b/src/index.ts @@ -78,10 +78,10 @@ app.use(compression()); // compress responses app.use(express.json({ limit: '5mb'})); app.use(express.urlencoded({ extended: false, limit: '5mb' })); app.use(bodyParser.json()); -const injectionBlackList = ['$', '{', '&&', '||']; app.use(contentFilter({ - urlBlackList: injectionBlackList, - bodyBlackList: injectionBlackList + urlBlackList: ['$', '&&', '||'], + bodyBlackList: ['$', '{', '&&', '||'], + appendFound: true })); // filter URL query attacks app.use((err, req, res, ignore) => { // bodyParser error handling res.status(400).send({status: 'Invalid JSON body'}); diff --git a/src/models/changelog.ts b/src/models/changelog.ts index 75600c4..b26bd16 100644 --- a/src/models/changelog.ts +++ b/src/models/changelog.ts @@ -2,7 +2,7 @@ import mongoose from 'mongoose'; const ChangelogSchema = new mongoose.Schema({ action: String, - collectionName: String, + collection_name: String, conditions: Object, data: Object, user_id: mongoose.Schema.Types.ObjectId diff --git a/src/routes/material.ts b/src/routes/material.ts index 1d9f135..a1cf1e5 100644 --- a/src/routes/material.ts +++ b/src/routes/material.ts @@ -9,10 +9,10 @@ import MaterialSupplierModel from '../models/material_suppliers'; import IdValidate from './validate/id'; import res400 from './validate/res400'; import mongoose from 'mongoose'; -import globals from '../globals'; import db from '../db'; import MaterialTemplateModel from '../models/material_template'; import ParametersValidate from './validate/parameters'; +import globals from '../globals'; @@ -28,14 +28,14 @@ router.get('/materials', (req, res, next) => { if (filters.hasOwnProperty('status')) { if(filters.status === 'all') { - conditions = {$or: [{status: 'validated'}, {status: 'new'}]} + conditions = {$or: [{status: globals.status.val}, {status: globals.status.new}]} } else { conditions = {status: filters.status}; } } else { // default - conditions = {status: 'validated'}; + conditions = {status: globals.status.val}; } MaterialModel.find(conditions).populate('group_id').populate('supplier_id').lean().exec((err, data) => { @@ -46,7 +46,7 @@ router.get('/materials', (req, res, next) => { }); }); -router.get('/materials/:state(new|deleted)', (req, res, next) => { +router.get(`/materials/:state(${globals.status.new}|${globals.status.del})`, (req, res, next) => { if (!req.auth(res, ['dev', 'admin'], 'basic')) return; MaterialModel.find({status: req.params.state}).populate('group_id').populate('supplier_id') @@ -69,7 +69,7 @@ router.get('/material/' + IdValidate.parameter(), (req, res, next) => { } // deleted materials only available for dev/admin - if (data.status === 'deleted' && !req.auth(res, ['dev', 'admin'], 'all')) return; + if (data.status === globals.status.del && !req.auth(res, ['dev', 'admin'], 'all')) return; res.json(MaterialValidate.output(data)); }); }); @@ -105,7 +105,7 @@ router.put('/material/' + IdValidate.parameter(), (req, res, next) => { // check for changes if (!_.isEqual(_.pick(IdValidate.stringify(materialData), _.keys(material)), IdValidate.stringify(material))) { - material.status = 'new'; // set status to new + material.status = globals.status.new; // set status to new } await MaterialModel.findByIdAndUpdate(req.params.id, material, {new: true}) @@ -125,7 +125,7 @@ router.delete('/material/' + IdValidate.parameter(), (req, res, next) => { if (data.length) { return res.status(400).json({status: 'Material still in use'}); } - MaterialModel.findByIdAndUpdate(req.params.id, {status:'deleted'}) + MaterialModel.findByIdAndUpdate(req.params.id, {status: globals.status.del}) .log(req).populate('group_id').populate('supplier_id').lean().exec((err, data) => { if (err) return next(err); if (data) { @@ -141,13 +141,13 @@ router.delete('/material/' + IdValidate.parameter(), (req, res, next) => { router.put('/material/restore/' + IdValidate.parameter(), (req, res, next) => { if (!req.auth(res, ['dev', 'admin'], 'basic')) return; - setStatus('new', req, res, next); + setStatus(globals.status.new, req, res, next); }); router.put('/material/validate/' + IdValidate.parameter(), (req, res, next) => { if (!req.auth(res, ['dev', 'admin'], 'basic')) return; - setStatus('validated', req, res, next); + setStatus(globals.status.val, req, res, next); }); router.post('/material/new', async (req, res, next) => { @@ -163,7 +163,7 @@ router.post('/material/new', async (req, res, next) => { if (!material) return; if (!await propertiesCheck(material.properties, 'new', res, next)) return; - material.status = 'new'; // set status to new + material.status = globals.status.new; // set status to new await new MaterialModel(material).save(async (err, data) => { if (err) return next(err); db.log(req, 'materials', {_id: data._id}, data.toObject()); diff --git a/src/routes/measurement.spec.ts b/src/routes/measurement.spec.ts index 3b1c5ee..668e83b 100644 --- a/src/routes/measurement.spec.ts +++ b/src/routes/measurement.spec.ts @@ -1,7 +1,6 @@ import should from 'should/as-function'; import MeasurementModel from '../models/measurement'; import TestHelper from "../test/helper"; -import globals from '../globals'; describe('/measurement', () => { diff --git a/src/routes/measurement.ts b/src/routes/measurement.ts index 352a98d..48cd9b0 100644 --- a/src/routes/measurement.ts +++ b/src/routes/measurement.ts @@ -8,8 +8,8 @@ import MeasurementValidate from './validate/measurement'; import IdValidate from './validate/id'; import res400 from './validate/res400'; import ParametersValidate from './validate/parameters'; -import globals from '../globals'; import db from '../db'; +import globals from '../globals'; const router = express.Router(); @@ -23,7 +23,7 @@ router.get('/measurement/' + IdValidate.parameter(), (req, res, next) => { return res.status(404).json({status: 'Not found'}); } // deleted measurements only available for dev/admin - if (data.status === 'deleted' && !req.auth(res, ['dev', 'admin'], 'all')) return; + if (data.status === globals.status.del && !req.auth(res, ['dev', 'admin'], 'all')) return; res.json(MeasurementValidate.output(data, req)); }); @@ -53,7 +53,7 @@ router.put('/measurement/' + IdValidate.parameter(), async (req, res, next) => { if (measurement.values) { // fill not changed values from database measurement.values = _.assign({}, data.values, measurement.values); if (!_.isEqual(measurement.values, data.values)) { - measurement.status = 'new'; // set status to new + measurement.status = globals.status.new; // set status to new } } @@ -74,7 +74,7 @@ router.delete('/measurement/' + IdValidate.parameter(), (req, res, next) => { return res.status(404).json({status: 'Not found'}); } if (!await sampleIdCheck(data, req, res, next)) return; - await MeasurementModel.findByIdAndUpdate(req.params.id, {status:'deleted'}) + await MeasurementModel.findByIdAndUpdate(req.params.id, {status: globals.status.del}) .log(req).lean().exec(err => { if (err) return next(err); return res.json({status: 'OK'}); @@ -85,13 +85,13 @@ router.delete('/measurement/' + IdValidate.parameter(), (req, res, next) => { router.put('/measurement/restore/' + IdValidate.parameter(), (req, res, next) => { if (!req.auth(res, ['dev', 'admin'], 'basic')) return; - setStatus('new', req, res, next); + setStatus(globals.status.new, req, res, next); }); router.put('/measurement/validate/' + IdValidate.parameter(), (req, res, next) => { if (!req.auth(res, ['dev', 'admin'], 'basic')) return; - setStatus('validated', req, res, next); + setStatus(globals.status.val, req, res, next); }); router.post('/measurement/new', async (req, res, next) => { @@ -104,7 +104,7 @@ router.post('/measurement/new', async (req, res, next) => { measurement.values = await templateCheck(measurement, 'new', res, next); if (!measurement.values) return; - measurement.status = 'new'; + measurement.status = globals.status.new; await new MeasurementModel(measurement).save((err, data) => { if (err) return next(err); db.log(req, 'measurements', {_id: data._id}, data.toObject()); diff --git a/src/routes/root.ts b/src/routes/root.ts index bc0fc98..23f3b8f 100644 --- a/src/routes/root.ts +++ b/src/routes/root.ts @@ -13,7 +13,7 @@ router.get('/', (req, res) => { }); router.get('/authorized', (req, res) => { - if (!req.auth(res, globals.levels)) return; + if (!req.auth(res, Object.values(globals.levels))) return; res.json({ status: 'Authorization successful', method: req.authDetails.method, diff --git a/src/routes/sample.ts b/src/routes/sample.ts index e50ceac..4d84d1d 100644 --- a/src/routes/sample.ts +++ b/src/routes/sample.ts @@ -17,6 +17,7 @@ import ParametersValidate from './validate/parameters'; import db from '../db'; import csv from '../helpers/csv'; import flatten from '../helpers/flatten'; +import globals from '../globals'; const router = express.Router(); @@ -36,7 +37,7 @@ router.get('/samples', async (req, res, next) => { if (error) return res400(error, res); // spectral data and csv not allowed for read/write users - if ((filters.fields.find(e => /\.dpt$/.test(e)) || filters.output !== 'json') && + if ((filters.fields.find(e => e.indexOf('.' + globals.spectrum.dpt) >= 0) || filters.output !== 'json') && !req.auth(res, ['dev', 'admin'], 'all')) return; // TODO: find a better place for these @@ -260,7 +261,7 @@ router.get('/samples', async (req, res, next) => { // count total number of items before $skip and $limit, only works when from-id is not specified and spectra are not // included - if (!filters.fields.find(e => /spectrum\./.test(e)) && !filters['from-id']) { + if (!filters.fields.find(e => e.indexOf(globals.spectrum.spectrum + '.') >= 0) && !filters['from-id']) { queryPtr.push({$facet: {count: [{$count: 'count'}], samples: []}}); queryPtr = queryPtr[queryPtr.length - 1].$facet.samples; // add rest of aggregation pipeline into $facet } @@ -328,7 +329,7 @@ router.get('/samples', async (req, res, next) => { return res.status(400).json({status: 'Invalid body format', details: 'Measurement key not found'}); } // use different lookup methods with and without spectrum for the best performance - if (fieldsToAdd.find(e => /spectrum\./.test(e))) { + if (fieldsToAdd.find(e => e.indexOf(globals.spectrum.spectrum + '.') >= 0)) { queryPtr.push( {$lookup: {from: 'measurements', localField: '_id', foreignField: 'sample_id', as: 'measurements'}} ); @@ -343,22 +344,12 @@ router.get('/samples', async (req, res, next) => { as: 'measurements' }}); } - measurementTemplates.forEach(template => { // TODO: hard coded dpt for special treatment, change later + measurementTemplates.forEach(template => { addMeasurements(queryPtr, template); - if (measurementFieldsFields.find(e => e === 'spectrum')) { - queryPtr.push({$unwind: '$spectrum'}); + if (measurementFieldsFields.find(e => e === globals.spectrum.spectrum)) { + queryPtr.push({$unwind: '$' + globals.spectrum.spectrum}); } }); - // if (measurementFieldsFields.find(e => e === 'spectrum')) { // TODO: remove hardcoded as well - // queryPtr.push( - // {$addFields: {spectrum: {$filter: {input: '$measurements', cond: { - // $eq: ['$$this.measurement_template', measurementTemplates.filter(e => e.name === 'spectrum')[0]._id] - // }}}}}, - // {$addFields: {spectrum: '$spectrum.values'}}, - // {$unwind: '$spectrum'} - // ); - // } - // queryPtr.push({$unset: 'measurements'}); queryPtr.push({$project: {measurements: 0}}); } @@ -372,7 +363,8 @@ router.get('/samples', async (req, res, next) => { projection._id = false; } queryPtr.push({$project: projection}); - if (!fieldsToAdd.find(e => /spectrum\./.test(e))) { // use streaming when including spectrum files + // use streaming when including spectrum files + if (!fieldsToAdd.find(e => e.indexOf(globals.spectrum.spectrum + '.') >= 0)) { collection.aggregate(query).allowDiskUse(true).exec((err, data) => { if (err) return next(err); if (data[0] && data[0].count) { @@ -439,7 +431,7 @@ router.get('/samples', async (req, res, next) => { } }); -router.get('/samples/:state(new|deleted)', (req, res, next) => { +router.get(`/samples/:state(${globals.status.new}|${globals.status.del})`, (req, res, next) => { if (!req.auth(res, ['dev', 'admin'], 'basic')) return; SampleModel.find({status: req.params.state}).lean().exec((err, data) => { @@ -479,7 +471,7 @@ router.put('/sample/' + IdValidate.parameter(), (req, res, next) => { if (!sampleData) { return res.status(404).json({status: 'Not found'}); } - if (sampleData.status === 'deleted') { + if (sampleData.status === globals.status.del) { return res.status(403).json({status: 'Forbidden'}); } @@ -527,7 +519,7 @@ router.put('/sample/' + IdValidate.parameter(), (req, res, next) => { // check for changes if (!_.isEqual(_.pick(IdValidate.stringify(sampleData), _.keys(sample)), _.omit(sample, ['notes']))) { - sample.status = 'new'; + sample.status = globals.status.new; } await SampleModel.findByIdAndUpdate(req.params.id, sample, {new: true}).log(req).lean().exec((err, data: any) => { @@ -555,7 +547,7 @@ router.delete('/sample/' + IdValidate.parameter(), (req, res, next) => { if (err) return next(err); // set status of associated measurements also to deleted - MeasurementModel.updateMany({sample_id: mongoose.Types.ObjectId(req.params.id)}, {status: 'deleted'}) + MeasurementModel.updateMany({sample_id: mongoose.Types.ObjectId(req.params.id)}, {status: globals.status.del}) .log(req).lean().exec(err => { if (err) return next(err); @@ -589,7 +581,7 @@ router.get('/sample/number/:number', (req, res, next) => { router.put('/sample/restore/' + IdValidate.parameter(), (req, res, next) => { if (!req.auth(res, ['dev', 'admin'], 'basic')) return; - SampleModel.findByIdAndUpdate(req.params.id, {status: 'new'}).log(req).lean().exec((err, data) => { + SampleModel.findByIdAndUpdate(req.params.id, {status: globals.status.new}).log(req).lean().exec((err, data) => { if (err) return next(err); if (!data) { @@ -602,7 +594,7 @@ router.put('/sample/restore/' + IdValidate.parameter(), (req, res, next) => { router.put('/sample/validate/' + IdValidate.parameter(), (req, res, next) => { if (!req.auth(res, ['dev', 'admin'], 'basic')) return; - SampleModel.findByIdAndUpdate(req.params.id, {status: 'validated'}).log(req).lean().exec((err, data) => { + SampleModel.findByIdAndUpdate(req.params.id, {status: globals.status.val}).log(req).lean().exec((err, data) => { if (err) return next(err); if (!data) { return res.status(404).json({status: 'Not found'}); @@ -635,7 +627,7 @@ router.post('/sample/new', async (req, res, next) => { if (!await conditionCheck(sample.condition, 'change', res, next)) return; } - sample.status = 'new'; // set status to new + sample.status = globals.status.new; // set status to new if (sample.hasOwnProperty('number')) { if (!await numberCheck(sample, res, next)) return; } @@ -885,7 +877,7 @@ async function sampleReturn (sampleData, req, res, next) { sampleData = sampleData.toObject(); // deleted samples only available for dev/admin - if (sampleData.status === 'deleted' && !req.auth(res, ['dev', 'admin'], 'all')) return; + if (sampleData.status === globals.status.del && !req.auth(res, ['dev', 'admin'], 'all')) return; sampleData.material = sampleData.material_id; // map data to right keys sampleData.material.group = sampleData.material.group_id.name; sampleData.material.supplier = sampleData.material.supplier_id.name; @@ -896,8 +888,8 @@ async function sampleReturn (sampleData, req, res, next) { sampleData.measurements = data; if (['dev', 'admin'].indexOf(req.authDetails.level) < 0) { // strip dpt values if not dev or admin sampleData.measurements.forEach(measurement => { - if (measurement.values.dpt) { - delete measurement.values.dpt; + if (measurement.values[globals.spectrum.dpt]) { + delete measurement.values[globals.spectrum.dpt]; } }); } diff --git a/src/routes/user.ts b/src/routes/user.ts index e90f1a0..963af27 100644 --- a/src/routes/user.ts +++ b/src/routes/user.ts @@ -60,13 +60,13 @@ router.put('/user:username([/](?!key|new).?*|/?)', async (req, res, next) => { } // get current mail address to compare to given address - const {email: oldMail} = await UserModel.findOne({name: username}).lean().exec().catch(err => next(err)); + const oldUserData = await UserModel.findOne({name: username}).lean().exec().catch(err => next(err)); await UserModel.findOneAndUpdate({name: username}, user, {new: true}).log(req).lean().exec( (err, data:any) => { if (err) return next(err); if (data) { - if (data.mail !== oldMail) { // mail address was changed, send notice to old address - Mail.send(oldMail, 'Email change in your DeFinMa database account', + if (data.mail !== oldUserData.email) { // mail address was changed, send notice to old address + Mail.send(oldUserData.email, 'Email change in your DeFinMa database account', 'Hi,

Your email address of your DeFinMa account was changed to ' + data.mail + '

If you actually did this, just delete this email.' + '

If you did not change your email, someone might be messing around with your account, ' + diff --git a/src/routes/validate/material.ts b/src/routes/validate/material.ts index ebf1c6d..b4532e8 100644 --- a/src/routes/validate/material.ts +++ b/src/routes/validate/material.ts @@ -1,6 +1,7 @@ import Joi from 'joi'; import IdValidate from './id'; +import globals from '../../globals'; export default class MaterialValidate { // validate input for material private static material = { @@ -84,7 +85,7 @@ export default class MaterialValidate { // validate input for material static query (data) { return Joi.object({ - status: Joi.string().valid('validated', 'new', 'all') + status: Joi.string().valid(globals.status.val, globals.status.new, 'all') }).validate(data); } } \ No newline at end of file diff --git a/src/routes/validate/measurement.ts b/src/routes/validate/measurement.ts index f375e98..b7b6650 100644 --- a/src/routes/validate/measurement.ts +++ b/src/routes/validate/measurement.ts @@ -1,6 +1,7 @@ import Joi from 'joi'; import IdValidate from './id'; +import globals from '../../globals'; export default class MeasurementValidate { private static measurement = { @@ -37,8 +38,8 @@ export default class MeasurementValidate { static output (data, req) { // validate output and strip unwanted properties, returns null if not valid data = IdValidate.stringify(data); // spectral data not allowed for read/write users - if (['dev', 'admin'].indexOf(req.authDetails.level) < 0 && data.values.dpt) { - delete data.values.dpt; + if (['dev', 'admin'].indexOf(req.authDetails.level) < 0 && data.values[globals.spectrum.dpt]) { + delete data.values[globals.spectrum.dpt]; } const {value, error} = Joi.object({ _id: IdValidate.get(), diff --git a/src/routes/validate/root.ts b/src/routes/validate/root.ts index 25386fc..a932196 100644 --- a/src/routes/validate/root.ts +++ b/src/routes/validate/root.ts @@ -36,7 +36,7 @@ export default class RootValidate { // validate input for root methods static changelogOutput (data) { data.date = data._id.getTimestamp(); - data.collection = data.collectionName; + data.collection = data.collection_name; data = IdValidate.stringify(data); const {value, error} = Joi.object({ date: this.changelog.timestamp, diff --git a/src/routes/validate/sample.ts b/src/routes/validate/sample.ts index baabecb..976e920 100644 --- a/src/routes/validate/sample.ts +++ b/src/routes/validate/sample.ts @@ -53,7 +53,7 @@ export default class SampleValidate { .min('1970-01-01T00:00:00.000Z'), status: Joi.string() - .valid(...globals.status) + .valid(...Object.values(globals.status)) }; private static sortKeys = [ @@ -68,7 +68,7 @@ export default class SampleValidate { 'material.supplier', 'material.group', 'material.properties.*', - 'measurements.(?!spectrum\.dpt)*' + `measurements.(?!${globals.spectrum.spectrum}.${globals.spectrum.dpt})*` ]; private static fieldKeys = [ @@ -81,7 +81,7 @@ export default class SampleValidate { 'user_id', 'material._id', 'material.numbers', - 'measurements.spectrum.dpt', + `measurements.${globals.spectrum.spectrum}.${globals.spectrum.dpt}`, ]; static input (data, param) { // validate input, set param to 'new' to make all attributes required @@ -215,12 +215,12 @@ export default class SampleValidate { return {error: {details: [{message: 'Invalid JSON string for filter parameter'}]}, value: null} } } - const acceptedStatuses = ['validated', 'new']; + const acceptedStatuses = [globals.status.val, globals.status.new]; if (dev) { // dev and admin can also access deleted samples - acceptedStatuses.push('deleted') + acceptedStatuses.push(globals.status.del) } return Joi.object({ - status: Joi.array().items(Joi.string().valid(...acceptedStatuses)).default(['validated']), + status: Joi.array().items(Joi.string().valid(...acceptedStatuses)).default([globals.status.val]), 'from-id': IdValidate.get(), 'to-page': Joi.number().integer(), 'page-size': Joi.number().integer().min(1), diff --git a/src/routes/validate/user.ts b/src/routes/validate/user.ts index f25e492..1a0dff3 100644 --- a/src/routes/validate/user.ts +++ b/src/routes/validate/user.ts @@ -21,7 +21,7 @@ export default class UserValidate { // validate input for user .max(128), level: Joi.string() - .valid(...globals.levels), + .valid(...Object.values(globals.levels)), location: Joi.string() .alphanum() diff --git a/src/test/db.json b/src/test/db.json index ea037b1..87ef0ff 100644 --- a/src/test/db.json +++ b/src/test/db.json @@ -728,7 +728,7 @@ { "_id" : {"$oid": "120000010000000000000000"}, "action" : "PUT /sample/400000000000000000000001", - "collectionName" : "samples", + "collection_name" : "samples", "conditions" : { "_id" : {"$oid": "400000000000000000000001"} }, @@ -742,7 +742,7 @@ { "_id" : {"$oid": "120000020000000000000000"}, "action" : "PUT /sample/400000000000000000000001", - "collectionName" : "samples", + "collection_name" : "samples", "conditions" : { "_id" : {"$oid": "400000000000000000000001"} }, @@ -756,7 +756,7 @@ { "_id" : {"$oid": "120000030000000000000000"}, "action" : "PUT /sample/400000000000000000000001", - "collectionName" : "samples", + "collection_name" : "samples", "conditions" : { "_id" : {"$oid": "400000000000000000000001"} }, @@ -770,7 +770,7 @@ { "_id" : {"$oid": "120000040000000000000000"}, "action" : "PUT /sample/400000000000000000000001", - "collectionName" : "samples", + "collection_name" : "samples", "conditions" : { "_id" : {"$oid": "400000000000000000000001"} }, diff --git a/src/test/helper.ts b/src/test/helper.ts index 6fe16d8..d4b11e4 100644 --- a/src/test/helper.ts +++ b/src/test/helper.ts @@ -104,9 +104,9 @@ export default class TestHelper { ChangelogModel.findOne({}).sort({_id: -1}).skip(options.log.skip? options.log.skip : 0) .lean().exec((err, data) => { // latest entry if (err) return done(err); - should(data).have.only.keys('_id', 'action', 'collectionName', 'conditions', 'data', 'user_id', '__v'); + should(data).have.only.keys('_id', 'action', 'collection_name', 'conditions', 'data', 'user_id', '__v'); should(data).have.property('action', options.method.toUpperCase() + ' ' + options.url); - should(data).have.property('collectionName', options.log.collection); + should(data).have.property('collection_name', options.log.collection); if (options.log.hasOwnProperty('data')) { should(data).have.property('data', options.log.data); } From a30f24f018151ae7de3b67ad954022b4968031a4 Mon Sep 17 00:00:00 2001 From: VLE2FE Date: Wed, 12 Aug 2020 10:56:12 +0200 Subject: [PATCH 2/4] small fixes --- .idea/API.iml | 6 ++- .idea/dictionaries/VLE2FE.xml | 19 +++++++++ .idea/inspectionProfiles/Project_Default.xml | 19 ++++++++- README.md | 2 +- api/api.yaml | 1 - src/api.ts | 1 + src/customTypes/express.ts | 39 +++++++++++-------- src/routes/material.spec.ts | 1 - src/routes/sample.ts | 29 +++++++------- src/routes/validate/id.ts | 8 +++- src/routes/validate/parameters.ts | 3 +- static/intro-presentation/assets/styles.css | 3 +- .../assets/styles_global.css | 2 +- static/intro-presentation/index.html | 6 +-- static/styles/swagger-ui.css | 5 ++- 15 files changed, 97 insertions(+), 47 deletions(-) diff --git a/.idea/API.iml b/.idea/API.iml index c956989..d1fe0c4 100644 --- a/.idea/API.iml +++ b/.idea/API.iml @@ -1,7 +1,11 @@ - + + + + + diff --git a/.idea/dictionaries/VLE2FE.xml b/.idea/dictionaries/VLE2FE.xml index a241715..5e9cd2d 100644 --- a/.idea/dictionaries/VLE2FE.xml +++ b/.idea/dictionaries/VLE2FE.xml @@ -1,37 +1,53 @@ + adminnew + adminxx akro amodel anwendungsbeschränkt + apidoc + arora batchgranulate bcrypt bnpd + bsontype cfenv + changeadmin colordesignatiomsuppl colordesignationsuppl contentin + crastin definma dfopdb dosiergeschw dpts einspritzgeschw + errback frameguard + frankland functionlink glassfibrecontent isin janedoe + johndoe johnnydoe kfingew latamid lati lyucy materialnumber + nvmrc + oldpass + opblock pagesize + pagesizes pnach preaged + puneet reinforcementmaterial reinforcingmaterial + rewatch samplenumber sdpt signalviolet @@ -42,7 +58,10 @@ stringin testcomment ultramid + unknownroute vorgealtert + xcopy + yankov \ No newline at end of file diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml index 285ddb5..c2536e0 100644 --- a/.idea/inspectionProfiles/Project_Default.xml +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -1,8 +1,25 @@ \ No newline at end of file diff --git a/README.md b/README.md index a1fbc4d..522a5a8 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Digital fingerprint of plastics - API +# DeFinMa - API This is the API to access the database of the digital fingerprint of plastics project. diff --git a/api/api.yaml b/api/api.yaml index 45be8c4..d85acc7 100644 --- a/api/api.yaml +++ b/api/api.yaml @@ -1,6 +1,5 @@ openapi: 3.0.2 - info: title: Digital fingerprint of plastics - API version: 1.0.0 diff --git a/src/api.ts b/src/api.ts index 8988cf1..80ab5a8 100644 --- a/src/api.ts +++ b/src/api.ts @@ -67,6 +67,7 @@ function resolveXDoc (doc) { // resolve x-doc properties recursively // templates +// noinspection LongLine const htmlTplString = ` diff --git a/src/customTypes/express.ts b/src/customTypes/express.ts index 361c961..ce89d49 100644 --- a/src/customTypes/express.ts +++ b/src/customTypes/express.ts @@ -10,7 +10,7 @@ /* =================== USAGE =================== import * as express from "express"; - var app = express(); + let app = express(); =============================================== */ @@ -29,40 +29,44 @@ declare function e(): core.Express; declare namespace e { /** - * This is a built-in middleware function in Express. It parses incoming requests with JSON payloads and is based on body-parser. + * This is a built-in middleware function in Express. It parses incoming requests with JSON payloads and is based on + * body-parser. * @since 4.16.0 */ - var json: typeof bodyParser.json; + let json: typeof bodyParser.json; /** - * This is a built-in middleware function in Express. It parses incoming requests with Buffer payloads and is based on body-parser. + * This is a built-in middleware function in Express. It parses incoming requests with Buffer payloads and is based + * on body-parser. * @since 4.17.0 */ - var raw: typeof bodyParser.raw; + let raw: typeof bodyParser.raw; /** - * This is a built-in middleware function in Express. It parses incoming requests with text payloads and is based on body-parser. + * This is a built-in middleware function in Express. It parses incoming requests with text payloads and is based on + * body-parser. * @since 4.17.0 */ - var text: typeof bodyParser.text; + let text: typeof bodyParser.text; /** * These are the exposed prototypes. */ - var application: Application; - var request: Request; - var response: Response; + let application: Application; + let request: Request; + let response: Response; /** * This is a built-in middleware function in Express. It serves static files and is based on serve-static. */ - var static: typeof serveStatic; + let static: typeof serveStatic; /** - * This is a built-in middleware function in Express. It parses incoming requests with urlencoded payloads and is based on body-parser. + * This is a built-in middleware function in Express. It parses incoming requests with urlencoded payloads and is + * based on body-parser. * @since 4.16.0 */ - var urlencoded: typeof bodyParser.urlencoded; + let urlencoded: typeof bodyParser.urlencoded; /** * This is a built-in middleware function in Express. It parses incoming request query parameters. @@ -95,7 +99,8 @@ declare namespace e { interface Application extends core.Application { } interface CookieOptions extends core.CookieOptions { } interface Errback extends core.Errback { } - interface ErrorRequestHandler

+ interface ErrorRequestHandler

extends core.ErrorRequestHandler { } interface Express extends core.Express { } interface Handler extends core.Handler { } @@ -105,8 +110,10 @@ declare namespace e { interface IRouterMatcher extends core.IRouterMatcher { } interface MediaType extends core.MediaType { } interface NextFunction extends core.NextFunction { } - interface Request

extends core.Request { } - interface RequestHandler

extends core.RequestHandler { } + interface Request

extends core.Request { } + interface RequestHandler

extends core.RequestHandler { } interface RequestParamHandler extends core.RequestParamHandler { } export interface Response extends core.Response { } interface Router extends core.Router { } diff --git a/src/routes/material.spec.ts b/src/routes/material.spec.ts index 0f362ae..1bbae13 100644 --- a/src/routes/material.spec.ts +++ b/src/routes/material.spec.ts @@ -3,7 +3,6 @@ import MaterialModel from '../models/material'; import MaterialGroupModel from '../models/material_groups'; import MaterialSupplierModel from '../models/material_suppliers'; import TestHelper from "../test/helper"; -import globals from '../globals'; describe('/material', () => { diff --git a/src/routes/sample.ts b/src/routes/sample.ts index 4d84d1d..ab8ff1c 100644 --- a/src/routes/sample.ts +++ b/src/routes/sample.ts @@ -581,27 +581,13 @@ router.get('/sample/number/:number', (req, res, next) => { router.put('/sample/restore/' + IdValidate.parameter(), (req, res, next) => { if (!req.auth(res, ['dev', 'admin'], 'basic')) return; - SampleModel.findByIdAndUpdate(req.params.id, {status: globals.status.new}).log(req).lean().exec((err, data) => { - if (err) return next(err); - - if (!data) { - return res.status(404).json({status: 'Not found'}); - } - res.json({status: 'OK'}); - }); + setStatus(globals.status.new, req, res, next); }); router.put('/sample/validate/' + IdValidate.parameter(), (req, res, next) => { if (!req.auth(res, ['dev', 'admin'], 'basic')) return; - SampleModel.findByIdAndUpdate(req.params.id, {status: globals.status.val}).log(req).lean().exec((err, data) => { - if (err) return next(err); - if (!data) { - return res.status(404).json({status: 'Not found'}); - } - - res.json({status: 'OK'}); - }); + setStatus(globals.status.val, req, res, next); }); router.post('/sample/new', async (req, res, next) => { @@ -899,4 +885,15 @@ async function sampleReturn (sampleData, req, res, next) { else { res.status(404).json({status: 'Not found'}); } +} + +function setStatus (status, req, res, next) { + SampleModel.findByIdAndUpdate(req.params.id, {status}).log(req).lean().exec((err, data) => { + if (err) return next(err); + + if (!data) { + return res.status(404).json({status: 'Not found'}); + } + res.json({status: 'OK'}); + }); } \ No newline at end of file diff --git a/src/routes/validate/id.ts b/src/routes/validate/id.ts index e52e688..e0d8362 100644 --- a/src/routes/validate/id.ts +++ b/src/routes/validate/id.ts @@ -1,7 +1,10 @@ import Joi from 'joi'; export default class IdValidate { - private static id = Joi.string().pattern(new RegExp('[0-9a-f]{24}')).length(24).messages({'string.pattern.base': 'Invalid object id'}); + private static id = Joi.string() + .pattern(new RegExp('[0-9a-f]{24}')) + .length(24) + .messages({'string.pattern.base': 'Invalid object id'}); static get () { // return joi validation return this.id; @@ -17,7 +20,8 @@ export default class IdValidate { static stringify (data) { // convert all ObjectID objects to plain strings Object.keys(data).forEach(key => { - if (data[key] !== null && data[key].hasOwnProperty('_bsontype') && data[key]._bsontype === 'ObjectID') { // stringify id + // stringify id + if (data[key] !== null && data[key].hasOwnProperty('_bsontype') && data[key]._bsontype === 'ObjectID') { data[key] = data[key].toString(); } else if (typeof data[key] === 'object' && data[key] !== null) { // deeper into recursion diff --git a/src/routes/validate/parameters.ts b/src/routes/validate/parameters.ts index 8fcc63b..8f24c52 100644 --- a/src/routes/validate/parameters.ts +++ b/src/routes/validate/parameters.ts @@ -1,7 +1,8 @@ import Joi from 'joi'; export default class ParametersValidate { - static input (data, parameters, param) { // data to validate, parameters from template, param: 'new', 'change', 'null'(null values are allowed) + // data to validate, parameters from template, param: 'new', 'change', 'null'(null values are allowed) + static input (data, parameters, param) { let joiObject = {}; parameters.forEach(parameter => { if (parameter.range.hasOwnProperty('values')) { // append right validation method according to parameter diff --git a/static/intro-presentation/assets/styles.css b/static/intro-presentation/assets/styles.css index 3a4aa18..8eba113 100644 --- a/static/intro-presentation/assets/styles.css +++ b/static/intro-presentation/assets/styles.css @@ -23,7 +23,6 @@ .go-btn button { color: #ffffff; border-color: #008ecf; - background: linear-gradient(to bottom, #005691 0%, #005691 50%, #008ecf 50%, #008ecf 100%); border-width: 1px; line-height: 40px; padding: 30px 60px; @@ -33,7 +32,7 @@ text-align: center; cursor: pointer; transition: border, background cubic-bezier(0.38, 0.04, 0.35, 0.96) 600ms; - background-position: 0 0; + background: linear-gradient(to bottom, #005691 0%, #005691 50%, #008ecf 50%, #008ecf 100%) 0 0; background-size: 100% 200%; } diff --git a/static/intro-presentation/assets/styles_global.css b/static/intro-presentation/assets/styles_global.css index 141c069..1bfa1d7 100644 --- a/static/intro-presentation/assets/styles_global.css +++ b/static/intro-presentation/assets/styles_global.css @@ -31,7 +31,7 @@ color: #000; position: absolute; bottom: 10px; - font-size: 8.5px; + font-size: 9px; left: 39px; } diff --git a/static/intro-presentation/index.html b/static/intro-presentation/index.html index 4653f9c..c90b410 100644 --- a/static/intro-presentation/index.html +++ b/static/intro-presentation/index.html @@ -1,5 +1,5 @@ - + DeFinMaDB - Introduction @@ -248,7 +248,7 @@ layout: true class: content, theme-dark-green layout: true -# Thats all +# That's all --- @@ -264,7 +264,7 @@ layout: true