code improvements
This commit is contained in:
		@@ -16,7 +16,7 @@ Testing is done with mocha and can be executed using `npm test`.
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
## General structure
 | 
					## General structure
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[index.ts](./src/index.ts) is exectued when starting the server. It includes all setup tasks, registers middleware,
 | 
					[index.ts](./src/index.ts) is executed when starting the server. It includes all setup tasks, registers middleware,
 | 
				
			||||||
routes and error handlers. Setting the `NODE_ENV` environment variable allows starting the server either in 
 | 
					routes and error handlers. Setting the `NODE_ENV` environment variable allows starting the server either in 
 | 
				
			||||||
`production`, `development` or `test` mode.
 | 
					`production`, `development` or `test` mode.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -149,7 +149,6 @@ export default class db {
 | 
				
			|||||||
  // changelog entry, expects (req, this (from query helper)) or (req, collection, conditions, data)
 | 
					  // changelog entry, expects (req, this (from query helper)) or (req, collection, conditions, data)
 | 
				
			||||||
  static log(req, thisOrCollection, conditions = null, data = null) {
 | 
					  static log(req, thisOrCollection, conditions = null, data = null) {
 | 
				
			||||||
    if (! (conditions || data)) {  // (req, this)
 | 
					    if (! (conditions || data)) {  // (req, this)
 | 
				
			||||||
      console.log(11);
 | 
					 | 
				
			||||||
      data = thisOrCollection._update ? _.cloneDeep(thisOrCollection._update) : {};  // replace undefined with {}
 | 
					      data = thisOrCollection._update ? _.cloneDeep(thisOrCollection._update) : {};  // replace undefined with {}
 | 
				
			||||||
      // replace keys with a leading $
 | 
					      // replace keys with a leading $
 | 
				
			||||||
      Object.keys(data).forEach(key => {
 | 
					      Object.keys(data).forEach(key => {
 | 
				
			||||||
@@ -158,7 +157,6 @@ export default class db {
 | 
				
			|||||||
          delete data[key];
 | 
					          delete data[key];
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      });
 | 
					      });
 | 
				
			||||||
      console.log(thisOrCollection._conditions);
 | 
					 | 
				
			||||||
      new ChangelogModel(this.logEscape(_.cloneDeep({
 | 
					      new ChangelogModel(this.logEscape(_.cloneDeep({
 | 
				
			||||||
        action: req.method + ' ' + req.url,
 | 
					        action: req.method + ' ' + req.url,
 | 
				
			||||||
        collection_name: thisOrCollection._collection.collectionName,
 | 
					        collection_name: thisOrCollection._collection.collectionName,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,7 @@
 | 
				
			|||||||
import {parseAsync} from 'json2csv';
 | 
					import {parseAsync} from 'json2csv';
 | 
				
			||||||
import flatten from './flatten';
 | 
					import flatten from './flatten';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default function csv(input: any[], f: (err, data) => void) {
 | 
					export default function csv(input: any[], f: (err, data) => void) {  // parse JSON to CSV
 | 
				
			||||||
  parseAsync(input.map(e => flatten(e)), {includeEmptyRows: true})
 | 
					  parseAsync(input.map(e => flatten(e)), {includeEmptyRows: true})
 | 
				
			||||||
    .then(csv => f(null, csv))
 | 
					    .then(csv => f(null, csv))
 | 
				
			||||||
    .catch(err => f(err, null));
 | 
					    .catch(err => f(err, null));
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,10 +3,10 @@ import globals from '../globals';
 | 
				
			|||||||
export default function flatten (data, keepArray = false) {  // flatten object: {a: {b: true}} -> {a.b: true}
 | 
					export default function flatten (data, keepArray = false) {  // flatten object: {a: {b: true}} -> {a.b: true}
 | 
				
			||||||
  const result = {};
 | 
					  const result = {};
 | 
				
			||||||
  function recurse (cur, prop) {
 | 
					  function recurse (cur, prop) {
 | 
				
			||||||
    if (Object(cur) !== cur || Object.keys(cur).length === 0) {
 | 
					    if (Object(cur) !== cur || Object.keys(cur).length === 0) {  // simple value
 | 
				
			||||||
      result[prop] = cur;
 | 
					      result[prop] = cur;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    else if (prop === `${globals.spectrum.spectrum}.${globals.spectrum.dpt}`) {
 | 
					    else if (prop === `${globals.spectrum.spectrum}.${globals.spectrum.dpt}`) {  // convert spectrum for ML
 | 
				
			||||||
      result[prop + '.labels'] = cur.map(e => parseFloat(e[0]));
 | 
					      result[prop + '.labels'] = cur.map(e => parseFloat(e[0]));
 | 
				
			||||||
      result[prop + '.values'] = cur.map(e => parseFloat(e[1]));
 | 
					      result[prop + '.values'] = cur.map(e => parseFloat(e[1]));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -27,7 +27,7 @@ export default function flatten (data, keepArray = false) {  // flatten object:
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    else {
 | 
					    else {  // object
 | 
				
			||||||
      let isEmpty = true;
 | 
					      let isEmpty = true;
 | 
				
			||||||
      for (let p in cur) {
 | 
					      for (let p in cur) {
 | 
				
			||||||
        isEmpty = false;
 | 
					        isEmpty = false;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,10 +4,10 @@ import axios from 'axios';
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
export default class Mail{
 | 
					export default class Mail{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  static readonly address = 'definma@bosch-iot.com';
 | 
					  static readonly address = 'definma@bosch-iot.com';  // email address
 | 
				
			||||||
  static uri: string;
 | 
					  static uri: string;                                 // mail API URI
 | 
				
			||||||
  static auth = {username: '', password: ''};
 | 
					  static auth = {username: '', password: ''};         // mail API credentials
 | 
				
			||||||
  static mailPass: string;
 | 
					  static mailPass: string;                            // mail API generates password
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  static init() {
 | 
					  static init() {
 | 
				
			||||||
    if (process.env.NODE_ENV === 'production') {  // only send mails in production
 | 
					    if (process.env.NODE_ENV === 'production') {  // only send mails in production
 | 
				
			||||||
@@ -51,14 +51,14 @@ export default class Mail{
 | 
				
			|||||||
      }).then(() => {  // init done successfully
 | 
					      }).then(() => {  // init done successfully
 | 
				
			||||||
        console.info('Mail service established successfully');
 | 
					        console.info('Mail service established successfully');
 | 
				
			||||||
        this.send('lukas.veit@bosch.com', 'Mail Service started', new Date().toString());
 | 
					        this.send('lukas.veit@bosch.com', 'Mail Service started', new Date().toString());
 | 
				
			||||||
      }).catch(err => {  // anywhere an error occurred
 | 
					      }).catch(err => {  // somewhere an error occurred
 | 
				
			||||||
        console.error(`Mail init error: ${err.request.method} ${err.request.path}: ${err.response.status}`,
 | 
					        console.error(`Mail init error: ${err.request.method} ${err.request.path}: ${err.response.status}`,
 | 
				
			||||||
          err.response.data);
 | 
					          err.response.data);
 | 
				
			||||||
      });
 | 
					      });
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  static send (mailAddress, subject, content, f: (x?) => void = () => {}) {  // callback, executed empty or with error
 | 
					  static send (mailAddress, subject, content, f: (x?) => void = () => {}) {  // callback executed empty or with error
 | 
				
			||||||
    if (process.env.NODE_ENV === 'production') {  // only send mails in production
 | 
					    if (process.env.NODE_ENV === 'production') {  // only send mails in production
 | 
				
			||||||
      axios({
 | 
					      axios({
 | 
				
			||||||
        method: 'post',
 | 
					        method: 'post',
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -100,6 +100,9 @@ app.use(require('./helpers/authorize'));  // handle authentication
 | 
				
			|||||||
// redirect /api routes for Angular proxy in development
 | 
					// redirect /api routes for Angular proxy in development
 | 
				
			||||||
if (process.env.NODE_ENV !== 'production') {
 | 
					if (process.env.NODE_ENV !== 'production') {
 | 
				
			||||||
  app.use('/api/:url([^]+)', (req, res) => {
 | 
					  app.use('/api/:url([^]+)', (req, res) => {
 | 
				
			||||||
 | 
					    if (/help\//.test(req.params.url)) { // encode URI again for help route
 | 
				
			||||||
 | 
					      req.params.url = 'help/' + encodeURIComponent(req.params.url.replace('help/', ''));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    req.url = '/' + req.params.url;
 | 
					    req.url = '/' + req.params.url;
 | 
				
			||||||
    app.handle(req, res);
 | 
					    app.handle(req, res);
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -25,21 +25,7 @@ router.get('/materials', (req, res, next) => {
 | 
				
			|||||||
    MaterialValidate.query(req.query, ['dev', 'admin'].indexOf(req.authDetails.level) >= 0);
 | 
					    MaterialValidate.query(req.query, ['dev', 'admin'].indexOf(req.authDetails.level) >= 0);
 | 
				
			||||||
  if (error) return res400(error, res);
 | 
					  if (error) return res400(error, res);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  let conditions;
 | 
					  MaterialModel.find(filters).sort({name: 1}).populate('group_id').populate('supplier_id')
 | 
				
			||||||
 | 
					 | 
				
			||||||
  if (filters.hasOwnProperty('status')) {
 | 
					 | 
				
			||||||
    if(filters.status === 'all') {
 | 
					 | 
				
			||||||
      conditions = {$or: [{status: globals.status.val}, {status: globals.status.new}]}
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    else {
 | 
					 | 
				
			||||||
      conditions = {status: filters.status};
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  else {  // default
 | 
					 | 
				
			||||||
    conditions = {status: globals.status.val};
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  MaterialModel.find(conditions).sort({name: 1}).populate('group_id').populate('supplier_id')
 | 
					 | 
				
			||||||
    .lean().exec((err, data) => {
 | 
					    .lean().exec((err, data) => {
 | 
				
			||||||
    if (err) return next(err);
 | 
					    if (err) return next(err);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -22,16 +22,12 @@ import globals from '../globals';
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
const router = express.Router();
 | 
					const router = express.Router();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// TODO: do not use streaming for spectrum filenames
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
router.get('/samples', async (req, res, next) => {
 | 
					router.get('/samples', async (req, res, next) => {
 | 
				
			||||||
  if (!req.auth(res, ['read', 'write', 'dev', 'admin'], 'all')) return;
 | 
					  if (!req.auth(res, ['read', 'write', 'dev', 'admin'], 'all')) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const {error, value: filters} = SampleValidate.query(req.query, ['dev', 'admin'].indexOf(req.authDetails.level) >= 0);
 | 
					  const {error, value: filters} = SampleValidate.query(req.query, ['dev', 'admin'].indexOf(req.authDetails.level) >= 0);
 | 
				
			||||||
  console.log(error);
 | 
					 | 
				
			||||||
  if (error) return res400(error, res);
 | 
					  if (error) return res400(error, res);
 | 
				
			||||||
  console.log(filters.filters);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // spectral data and csv not allowed for read/write users
 | 
					  // spectral data and csv not allowed for read/write users
 | 
				
			||||||
  if ((filters.fields.find(e => e.indexOf('.' + globals.spectrum.dpt) >= 0) || filters.output !== 'json') &&
 | 
					  if ((filters.fields.find(e => e.indexOf('.' + globals.spectrum.dpt) >= 0) || filters.output !== 'json') &&
 | 
				
			||||||
@@ -388,7 +384,6 @@ router.get('/samples', async (req, res, next) => {
 | 
				
			|||||||
    projection._id = false;
 | 
					    projection._id = false;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  queryPtr.push({$project: projection});
 | 
					  queryPtr.push({$project: projection});
 | 
				
			||||||
  console.log(JSON.stringify(query));
 | 
					 | 
				
			||||||
  // use streaming when including spectrum files
 | 
					  // use streaming when including spectrum files
 | 
				
			||||||
  if (!fieldsToAdd.find(e => e.indexOf(globals.spectrum.spectrum + '.' + globals.spectrum.dpt) >= 0)) {
 | 
					  if (!fieldsToAdd.find(e => e.indexOf(globals.spectrum.spectrum + '.' + globals.spectrum.dpt) >= 0)) {
 | 
				
			||||||
    collection.aggregate(query).allowDiskUse(true).exec((err, data) => {
 | 
					    collection.aggregate(query).allowDiskUse(true).exec((err, data) => {
 | 
				
			||||||
@@ -687,8 +682,6 @@ async function numberGenerate (sample, req, res, next) {
 | 
				
			|||||||
  const sampleData = await SampleModel
 | 
					  const sampleData = await SampleModel
 | 
				
			||||||
    .aggregate([
 | 
					    .aggregate([
 | 
				
			||||||
      {$match: {number: new RegExp('^' + req.authDetails.location + '[0-9]+$', 'm')}},
 | 
					      {$match: {number: new RegExp('^' + req.authDetails.location + '[0-9]+$', 'm')}},
 | 
				
			||||||
      // {$addFields: {number2: {$toDecimal: {$arrayElemAt: [{$split: [{$arrayElemAt:
 | 
					 | 
				
			||||||
      //   [{$split: ['$number', 'Rng']}, 1]}, '_']}, 0]}}}},  // not working with MongoDb 3.6
 | 
					 | 
				
			||||||
      {$addFields: {sortNumber: {$let: {
 | 
					      {$addFields: {sortNumber: {$let: {
 | 
				
			||||||
        vars: {tmp: {$concat: ['000000000000000000000000000000',
 | 
					        vars: {tmp: {$concat: ['000000000000000000000000000000',
 | 
				
			||||||
              {$arrayElemAt: [{$split:
 | 
					              {$arrayElemAt: [{$split:
 | 
				
			||||||
@@ -701,7 +694,6 @@ async function numberGenerate (sample, req, res, next) {
 | 
				
			|||||||
    .exec()
 | 
					    .exec()
 | 
				
			||||||
    .catch(err => next(err));
 | 
					    .catch(err => next(err));
 | 
				
			||||||
  if (sampleData instanceof Error) return false;
 | 
					  if (sampleData instanceof Error) return false;
 | 
				
			||||||
  console.log(sampleData);
 | 
					 | 
				
			||||||
  let number = (sampleData[0] ? Number(sampleData[0].number.replace(/[^0-9]+/g, '')) : 0);
 | 
					  let number = (sampleData[0] ? Number(sampleData[0].number.replace(/[^0-9]+/g, '')) : 0);
 | 
				
			||||||
  if (numberBuffer[req.authDetails.location] && numberBuffer[req.authDetails.location] >= number) {
 | 
					  if (numberBuffer[req.authDetails.location] && numberBuffer[req.authDetails.location] >= number) {
 | 
				
			||||||
    number = numberBuffer[req.authDetails.location];
 | 
					    number = numberBuffer[req.authDetails.location];
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -64,8 +64,6 @@ router.put('/template/:collection(measurement|condition|material)/' + IdValidate
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (!_.isEqual(_.pick(templateData, _.keys(template)), template)) {  // data was changed
 | 
					  if (!_.isEqual(_.pick(templateData, _.keys(template)), template)) {  // data was changed
 | 
				
			||||||
    console.log(template);
 | 
					 | 
				
			||||||
    console.log(templateData);
 | 
					 | 
				
			||||||
    if (!template.parameters || _.isEqual(templateData.parameters, template.parameters)) {  // only name was changed
 | 
					    if (!template.parameters || _.isEqual(templateData.parameters, template.parameters)) {  // only name was changed
 | 
				
			||||||
      model(req).findByIdAndUpdate(req.params.id, {name: template.name}, {new: true})
 | 
					      model(req).findByIdAndUpdate(req.params.id, {name: template.name}, {new: true})
 | 
				
			||||||
        .log(req).lean().exec((err, data) => {
 | 
					        .log(req).lean().exec((err, data) => {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -199,7 +199,6 @@ export default class SampleValidate {
 | 
				
			|||||||
            data.filters[i] = decodeURIComponent(data.filters[i]);
 | 
					            data.filters[i] = decodeURIComponent(data.filters[i]);
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
          catch (ignore) {}
 | 
					          catch (ignore) {}
 | 
				
			||||||
          console.log(data.filters[i]);
 | 
					 | 
				
			||||||
          data.filters[i] = JSON.parse(data.filters[i]);
 | 
					          data.filters[i] = JSON.parse(data.filters[i]);
 | 
				
			||||||
          data.filters[i].values = data.filters[i].values.map(e => {  // validate filter values
 | 
					          data.filters[i].values = data.filters[i].values.map(e => {  // validate filter values
 | 
				
			||||||
            if (e === null) {  // null values are always allowed
 | 
					            if (e === null) {  // null values are always allowed
 | 
				
			||||||
@@ -241,7 +240,6 @@ export default class SampleValidate {
 | 
				
			|||||||
              validator = Joi.object(this.sample);
 | 
					              validator = Joi.object(this.sample);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            const {value, error} = validator.validate({[field]: e});
 | 
					            const {value, error} = validator.validate({[field]: e});
 | 
				
			||||||
            console.log(error);
 | 
					 | 
				
			||||||
            if (error) throw error;  // reject invalid values
 | 
					            if (error) throw error;  // reject invalid values
 | 
				
			||||||
            return value[field];
 | 
					            return value[field];
 | 
				
			||||||
          });
 | 
					          });
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -75,7 +75,7 @@ export default class UserValidate {  // validate input for user
 | 
				
			|||||||
      }).validate(data);
 | 
					      }).validate(data);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    else {
 | 
					    else {
 | 
				
			||||||
      return{error: 'No parameter specified!', value: {}};
 | 
					      return {error: 'No parameter specified!', value: {}};
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user