finished /template methods
This commit is contained in:
		@@ -1,6 +1,8 @@
 | 
			
		||||
import mongoose from 'mongoose';
 | 
			
		||||
import cfenv from 'cfenv';
 | 
			
		||||
 | 
			
		||||
// mongoose.set('debug', true);  // enable mongoose debug
 | 
			
		||||
 | 
			
		||||
// database urls, prod db url is retrieved automatically
 | 
			
		||||
const TESTING_URL = 'mongodb://localhost/dfopdb_test';
 | 
			
		||||
const DEV_URL = 'mongodb://localhost/dfopdb';
 | 
			
		||||
 
 | 
			
		||||
@@ -47,6 +47,7 @@ app.use(require('./helpers/authorize'));  // handle authentication
 | 
			
		||||
app.use('/', require('./routes/root'));
 | 
			
		||||
app.use('/', require('./routes/user'));
 | 
			
		||||
app.use('/', require('./routes/material'));
 | 
			
		||||
app.use('/', require('./routes/template'));
 | 
			
		||||
 | 
			
		||||
// static files
 | 
			
		||||
app.use('/static', express.static('static'));
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										11
									
								
								src/models/measurement_template.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								src/models/measurement_template.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,11 @@
 | 
			
		||||
import mongoose from 'mongoose';
 | 
			
		||||
 | 
			
		||||
const MeasurementTemplateSchema = new mongoose.Schema({
 | 
			
		||||
  name: {type: String, index: {unique: true}},
 | 
			
		||||
  parameters: [{
 | 
			
		||||
    name: String,
 | 
			
		||||
    range: mongoose.Schema.Types.Mixed
 | 
			
		||||
  }]
 | 
			
		||||
}, {minimize: false});  // to allow empty objects
 | 
			
		||||
 | 
			
		||||
export default mongoose.model('measurement_template', MeasurementTemplateSchema);
 | 
			
		||||
							
								
								
									
										11
									
								
								src/models/treatment_template.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								src/models/treatment_template.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,11 @@
 | 
			
		||||
import mongoose from 'mongoose';
 | 
			
		||||
 | 
			
		||||
const TreatmentTemplateSchema = new mongoose.Schema({
 | 
			
		||||
  name: {type: String, index: {unique: true}},
 | 
			
		||||
  parameters: [{
 | 
			
		||||
    name: String,
 | 
			
		||||
    range: mongoose.Schema.Types.Mixed
 | 
			
		||||
  }]
 | 
			
		||||
}, {minimize: false});  // to allow empty objects
 | 
			
		||||
 | 
			
		||||
export default mongoose.model('treatment_template', TreatmentTemplateSchema);
 | 
			
		||||
@@ -130,7 +130,7 @@ describe('/material', () => {
 | 
			
		||||
        res: {_id: '100000000000000000000001', name: 'Stanyl TW 200 F8', supplier: 'DSM', group: 'PA46', mineral: 0, glass_fiber: 40, carbon_fiber: 0, numbers: [{color: 'black', number: 5514263423}]}
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
    it('returns keeps unchanged properties', done => {
 | 
			
		||||
    it('keeps unchanged properties', done => {
 | 
			
		||||
      TestHelper.request(server, done, {
 | 
			
		||||
        method: 'put',
 | 
			
		||||
        url: '/material/100000000000000000000001',
 | 
			
		||||
@@ -148,11 +148,12 @@ describe('/material', () => {
 | 
			
		||||
        httpStatus: 200,
 | 
			
		||||
        req: {name: 'UltramidTKR4355G7_2', supplier: 'BASF', group: 'PA6/6T', mineral: 0, glass_fiber: 35, carbon_fiber: 0, numbers: [{color: 'black', number: 5514212901}, {color: 'signalviolet', number: 5514612901}]}
 | 
			
		||||
        ,
 | 
			
		||||
      }).end(err => {
 | 
			
		||||
      }).end((err, res) => {
 | 
			
		||||
        if (err) return done(err);
 | 
			
		||||
        should(res.body).be.eql({_id: '100000000000000000000001', name: 'UltramidTKR4355G7_2', supplier: 'BASF', group: 'PA6/6T', mineral: 0, glass_fiber: 35, carbon_fiber: 0, numbers: [{color: 'black', number: 5514212901}, {color: 'signalviolet', number: 5514612901}]});
 | 
			
		||||
        MaterialModel.findById('100000000000000000000001').lean().exec((err, data:any) => {
 | 
			
		||||
          if (err) return done(err);
 | 
			
		||||
          data._id = data._id.toString();
 | 
			
		||||
          data._id = data._id.toString({_id: '100000000000000000000001', name: 'UltramidTKR4355G7_2', supplier: 'BASF', group: 'PA6/6T', mineral: 0, glass_fiber: 35, carbon_fiber: 0, numbers: [{color: 'black', number: 5514212901}, {color: 'signalviolet', number: 5514612901}]});
 | 
			
		||||
          data.numbers = data.numbers.map(e => {return {color: e.color, number: e.number}});
 | 
			
		||||
          should(data).be.eql({_id: '100000000000000000000001', name: 'UltramidTKR4355G7_2', supplier: 'BASF', group: 'PA6/6T', mineral: '0', glass_fiber: '35', carbon_fiber: '0', numbers: [{color: 'black', number: 5514212901}, {color: 'signalviolet', number: 5514612901}], __v: 0}
 | 
			
		||||
          );
 | 
			
		||||
 
 | 
			
		||||
@@ -57,7 +57,7 @@ router.put('/material/' + IdValidate.parameter(), (req, res, next) => {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function f() {  // to resolve async
 | 
			
		||||
    MaterialModel.findByIdAndUpdate(req.params.id, material).lean().exec((err, data) => {
 | 
			
		||||
    MaterialModel.findByIdAndUpdate(req.params.id, material, {new: true}).lean().exec((err, data) => {
 | 
			
		||||
      if (err) next(err);
 | 
			
		||||
      if (data) {
 | 
			
		||||
        res.json(MaterialValidate.output(data));
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										579
									
								
								src/routes/template.spec.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										579
									
								
								src/routes/template.spec.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,579 @@
 | 
			
		||||
import should from 'should/as-function';
 | 
			
		||||
import TemplateTreatmentModel from '../models/treatment_template';
 | 
			
		||||
import TemplateMeasurementModel from '../models/measurement_template';
 | 
			
		||||
import TestHelper from "../helpers/test";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
describe('/template', () => {
 | 
			
		||||
  let server;
 | 
			
		||||
  before(done => TestHelper.before(done));
 | 
			
		||||
  beforeEach(done => server = TestHelper.beforeEach(server, done));
 | 
			
		||||
  afterEach(done => TestHelper.afterEach(server, done));
 | 
			
		||||
 | 
			
		||||
  describe('/template/treatment', () => {
 | 
			
		||||
    describe('GET /template/treatments', () => {
 | 
			
		||||
      it('returns all treatment templates', done => {
 | 
			
		||||
        TestHelper.request(server, done, {
 | 
			
		||||
          method: 'get',
 | 
			
		||||
          url: '/template/treatments',
 | 
			
		||||
          auth: {basic: 'janedoe'},
 | 
			
		||||
          httpStatus: 200
 | 
			
		||||
        }).end((err, res) => {
 | 
			
		||||
          if (err) return done(err);
 | 
			
		||||
          const json = require('../test/db.json');
 | 
			
		||||
          should(res.body).have.lengthOf(json.collections.treatment_templates.length);
 | 
			
		||||
          should(res.body).matchEach(treatment => {
 | 
			
		||||
            should(treatment).have.only.keys('_id', 'name', 'parameters');
 | 
			
		||||
            should(treatment).have.property('_id').be.type('string');
 | 
			
		||||
            should(treatment).have.property('name').be.type('string');
 | 
			
		||||
            should(treatment.parameters).matchEach(number => {
 | 
			
		||||
              should(number).have.only.keys('name', 'range');
 | 
			
		||||
              should(number).have.property('name').be.type('string');
 | 
			
		||||
              should(number).have.property('range').be.type('object');
 | 
			
		||||
            });
 | 
			
		||||
          });
 | 
			
		||||
          done();
 | 
			
		||||
        });
 | 
			
		||||
      });
 | 
			
		||||
      it('rejects an API key', done => {
 | 
			
		||||
        TestHelper.request(server, done, {
 | 
			
		||||
          method: 'get',
 | 
			
		||||
          url: '/template/treatments',
 | 
			
		||||
          auth: {key: 'janedoe'},
 | 
			
		||||
          httpStatus: 401
 | 
			
		||||
        });
 | 
			
		||||
      });
 | 
			
		||||
      it('rejects unauthorized requests', done => {
 | 
			
		||||
        TestHelper.request(server, done, {
 | 
			
		||||
          method: 'get',
 | 
			
		||||
          url: '/template/treatments',
 | 
			
		||||
          httpStatus: 401
 | 
			
		||||
        });
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    describe('GET /template/treatment/{name}', () => {
 | 
			
		||||
      it('returns the right treatment template', done => {
 | 
			
		||||
        TestHelper.request(server, done, {
 | 
			
		||||
          method: 'get',
 | 
			
		||||
          url: '/template/treatment/heat%20treatment',
 | 
			
		||||
          auth: {basic: 'janedoe'},
 | 
			
		||||
          httpStatus: 200,
 | 
			
		||||
          res: {_id: '200000000000000000000001', name: 'heat treatment', parameters: [{name: 'material', range: {values: ['copper', 'hot air']}}, {name: 'weeks', range: {min: 1, max: 10}}]}
 | 
			
		||||
        });
 | 
			
		||||
      });
 | 
			
		||||
      it('rejects an API key', done => {
 | 
			
		||||
        TestHelper.request(server, done, {
 | 
			
		||||
          method: 'get',
 | 
			
		||||
          url: '/template/treatment/heat%20treatment',
 | 
			
		||||
          auth: {key: 'janedoe'},
 | 
			
		||||
          httpStatus: 401
 | 
			
		||||
        });
 | 
			
		||||
      });
 | 
			
		||||
      it('rejects an unknown name', done => {
 | 
			
		||||
        TestHelper.request(server, done, {
 | 
			
		||||
          method: 'get',
 | 
			
		||||
          url: '/template/treatment/xxx',
 | 
			
		||||
          auth: {basic: 'janedoe'},
 | 
			
		||||
          httpStatus: 404
 | 
			
		||||
        });
 | 
			
		||||
      });
 | 
			
		||||
      it('rejects unauthorized requests', done => {
 | 
			
		||||
        TestHelper.request(server, done, {
 | 
			
		||||
          method: 'get',
 | 
			
		||||
          url: '/template/treatment/heat%20treatment',
 | 
			
		||||
          httpStatus: 401
 | 
			
		||||
        });
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    describe('PUT /template/treatment/{name}', () => {
 | 
			
		||||
      it('returns the right treatment template', done => {
 | 
			
		||||
        TestHelper.request(server, done, {
 | 
			
		||||
          method: 'put',
 | 
			
		||||
          url: '/template/treatment/heat%20treatment',
 | 
			
		||||
          auth: {basic: 'admin'},
 | 
			
		||||
          httpStatus: 200,
 | 
			
		||||
          req: {},
 | 
			
		||||
          res: {_id: '200000000000000000000001', name: 'heat treatment', parameters: [{name: 'material', range: {values: ['copper', 'hot air']}}, {name: 'weeks', range: {min: 1, max: 10}}]}
 | 
			
		||||
        });
 | 
			
		||||
      });
 | 
			
		||||
      it('keeps unchanged properties', done => {
 | 
			
		||||
        TestHelper.request(server, done, {
 | 
			
		||||
          method: 'put',
 | 
			
		||||
          url: '/template/treatment/heat%20treatment',
 | 
			
		||||
          auth: {basic: 'admin'},
 | 
			
		||||
          httpStatus: 200,
 | 
			
		||||
          req: {name: 'heat treatment', parameters: [{name: 'material', range: {values: ['copper', 'hot air']}}, {name: 'weeks', range: {min: 1, max: 10}}]},
 | 
			
		||||
          res: {_id: '200000000000000000000001', name: 'heat treatment', parameters: [{name: 'material', range: {values: ['copper', 'hot air']}}, {name: 'weeks', range: {min: 1, max: 10}}]}
 | 
			
		||||
        });
 | 
			
		||||
      });
 | 
			
		||||
      it('changes the given properties', done => {
 | 
			
		||||
        TestHelper.request(server, done, {
 | 
			
		||||
          method: 'put',
 | 
			
		||||
          url: '/template/treatment/heat%20treatment',
 | 
			
		||||
          auth: {basic: 'admin'},
 | 
			
		||||
          httpStatus: 200,
 | 
			
		||||
          req: {name: 'heat aging', parameters: [{name: 'time', range: {min: 1}}]}
 | 
			
		||||
        }).end((err, res) => {
 | 
			
		||||
            if (err) return done(err);
 | 
			
		||||
            should(res.body).be.eql({_id: '200000000000000000000001', name: 'heat aging', parameters: [{name: 'time', range: {min: 1}}]});
 | 
			
		||||
            TemplateTreatmentModel.find({name: 'heat aging'}).lean().exec((err, data:any) => {
 | 
			
		||||
              if (err) return done(err);
 | 
			
		||||
              should(data).have.lengthOf(1);
 | 
			
		||||
              should(data[0]).have.only.keys('_id', 'name', 'parameters');
 | 
			
		||||
              should(data[0]).have.property('name', 'heat aging');
 | 
			
		||||
              should(data[0]).have.property('parameters').have.lengthOf(1);
 | 
			
		||||
              should(data[0].parameters[0]).have.property('name', 'time');
 | 
			
		||||
              should(data[0].parameters[0]).have.property('range');
 | 
			
		||||
              should(data[0].parameters[0].range).have.property('min', 1);
 | 
			
		||||
              done();
 | 
			
		||||
            });
 | 
			
		||||
          });
 | 
			
		||||
      });
 | 
			
		||||
      it('supports values ranges', done => {
 | 
			
		||||
        TestHelper.request(server, done, {
 | 
			
		||||
          method: 'put',
 | 
			
		||||
          url: '/template/treatment/heat%20treatment',
 | 
			
		||||
          auth: {basic: 'admin'},
 | 
			
		||||
          httpStatus: 200,
 | 
			
		||||
          req: {parameters: [{name: 'time', range: {values: [1, 2, 5]}}]},
 | 
			
		||||
          res: {_id: '200000000000000000000001', name: 'heat treatment', parameters: [{name: 'time', range: {values: [1, 2, 5]}}]}
 | 
			
		||||
        });
 | 
			
		||||
      });
 | 
			
		||||
      it('supports min max ranges', done => {
 | 
			
		||||
        TestHelper.request(server, done, {
 | 
			
		||||
          method: 'put',
 | 
			
		||||
          url: '/template/treatment/heat%20treatment',
 | 
			
		||||
          auth: {basic: 'admin'},
 | 
			
		||||
          httpStatus: 200,
 | 
			
		||||
          req: {parameters: [{name: 'time', range: {min: 1, max: 11}}]},
 | 
			
		||||
          res: {_id: '200000000000000000000001', name: 'heat treatment', parameters: [{name: 'time', range: {min: 1, max: 11}}]}
 | 
			
		||||
        });
 | 
			
		||||
      });
 | 
			
		||||
      it('supports empty ranges', done => {
 | 
			
		||||
        TestHelper.request(server, done, {
 | 
			
		||||
          method: 'put',
 | 
			
		||||
          url: '/template/treatment/heat%20treatment',
 | 
			
		||||
          auth: {basic: 'admin'},
 | 
			
		||||
          httpStatus: 200,
 | 
			
		||||
          req: {parameters: [{name: 'time', range: {}}]},
 | 
			
		||||
          res: {_id: '200000000000000000000001', name: 'heat treatment', parameters: [{name: 'time', range: {}}]}
 | 
			
		||||
        });
 | 
			
		||||
      });
 | 
			
		||||
      it('adds a new template for an unknown name', done => {
 | 
			
		||||
        TestHelper.request(server, done, {
 | 
			
		||||
          method: 'put',
 | 
			
		||||
          url: '/template/treatment/heat%20aging',
 | 
			
		||||
          auth: {basic: 'admin'},
 | 
			
		||||
          httpStatus: 200,
 | 
			
		||||
          req: {name: 'heat aging', parameters: [{name: 'time', range: {min: 1}}]}
 | 
			
		||||
        }).end(err => {
 | 
			
		||||
          if (err) return done(err);
 | 
			
		||||
          TemplateTreatmentModel.find({name: 'heat aging'}).lean().exec((err, data:any) => {
 | 
			
		||||
            if (err) return done(err);
 | 
			
		||||
            console.log(data);
 | 
			
		||||
            should(data).have.lengthOf(1);
 | 
			
		||||
            should(data[0]).have.only.keys('_id', 'name', 'parameters', '__v');
 | 
			
		||||
            should(data[0]).have.property('name', 'heat aging');
 | 
			
		||||
            should(data[0].parameters[0]).have.property('name', 'time');
 | 
			
		||||
            should(data[0].parameters[0]).have.property('range');
 | 
			
		||||
            should(data[0].parameters[0].range).have.property('min', 1);
 | 
			
		||||
            done();
 | 
			
		||||
          });
 | 
			
		||||
        });
 | 
			
		||||
      });
 | 
			
		||||
      it('rejects an incomplete template for a new name', done => {
 | 
			
		||||
        TestHelper.request(server, done, {
 | 
			
		||||
          method: 'put',
 | 
			
		||||
          url: '/template/treatment/heat%20aging',
 | 
			
		||||
          auth: {basic: 'admin'},
 | 
			
		||||
          httpStatus: 400,
 | 
			
		||||
          req: {parameters: [{name: 'time'}]},
 | 
			
		||||
          res: {status: 'Invalid body format'}
 | 
			
		||||
        });
 | 
			
		||||
      });
 | 
			
		||||
      it('rejects already existing names', done => {
 | 
			
		||||
        TestHelper.request(server, done, {
 | 
			
		||||
          method: 'put',
 | 
			
		||||
          url: '/template/treatment/heat%20treatment',
 | 
			
		||||
          auth: {basic: 'admin'},
 | 
			
		||||
          httpStatus: 400,
 | 
			
		||||
          req: {name: 'heat treatment 2', parameters: [{name: 'time', range: {min: 1}}]},
 | 
			
		||||
          res: {status: 'Template name already taken'}
 | 
			
		||||
        });
 | 
			
		||||
      });
 | 
			
		||||
      it('rejects wrong properties', done => {
 | 
			
		||||
        TestHelper.request(server, done, {
 | 
			
		||||
          method: 'put',
 | 
			
		||||
          url: '/template/treatment/heat%20aging',
 | 
			
		||||
          auth: {basic: 'admin'},
 | 
			
		||||
          httpStatus: 400,
 | 
			
		||||
          req: {parameters: [{name: 'time'}], xx: 33},
 | 
			
		||||
          res: {status: 'Invalid body format'}
 | 
			
		||||
        });
 | 
			
		||||
      });
 | 
			
		||||
      it('rejects an API key', done => {
 | 
			
		||||
        TestHelper.request(server, done, {
 | 
			
		||||
          method: 'put',
 | 
			
		||||
          url: '/template/treatment/heat%20treatment',
 | 
			
		||||
          auth: {key: 'admin'},
 | 
			
		||||
          httpStatus: 401,
 | 
			
		||||
          req: {}
 | 
			
		||||
        });
 | 
			
		||||
      });
 | 
			
		||||
      it('rejects requests from a write user', done => {
 | 
			
		||||
        TestHelper.request(server, done, {
 | 
			
		||||
          method: 'put',
 | 
			
		||||
          url: '/template/treatment/heat%20treatment',
 | 
			
		||||
          auth: {basic: 'janedoe'},
 | 
			
		||||
          httpStatus: 403,
 | 
			
		||||
          req: {}
 | 
			
		||||
        });
 | 
			
		||||
      });
 | 
			
		||||
      it('rejects unauthorized requests', done => {
 | 
			
		||||
        TestHelper.request(server, done, {
 | 
			
		||||
          method: 'put',
 | 
			
		||||
          url: '/template/treatment/heat%20treatment',
 | 
			
		||||
          httpStatus: 401,
 | 
			
		||||
          req: {}
 | 
			
		||||
        });
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    describe('DELETE /template/treatment/{name}', () => {
 | 
			
		||||
      it('deletes the template', done => {
 | 
			
		||||
        TestHelper.request(server, done, {
 | 
			
		||||
          method: 'delete',
 | 
			
		||||
          url: '/template/treatment/heat%20treatment',
 | 
			
		||||
          auth: {basic: 'admin'},
 | 
			
		||||
          httpStatus: 200
 | 
			
		||||
        }).end((err, res) => {
 | 
			
		||||
          if (err) return done(err);
 | 
			
		||||
          should(res.body).be.eql({status: 'OK'});
 | 
			
		||||
          TemplateTreatmentModel.find({name: 'heat treatment'}).lean().exec((err, data:any) => {
 | 
			
		||||
            if (err) return done(err);
 | 
			
		||||
            should(data).have.lengthOf(0);
 | 
			
		||||
            done();
 | 
			
		||||
          });
 | 
			
		||||
        });
 | 
			
		||||
      });
 | 
			
		||||
      it('rejects deleting a template still in use');
 | 
			
		||||
      it('rejects an API key', done => {
 | 
			
		||||
        TestHelper.request(server, done, {
 | 
			
		||||
          method: 'delete',
 | 
			
		||||
          url: '/template/treatment/heat%20treatment',
 | 
			
		||||
          auth: {key: 'admin'},
 | 
			
		||||
          httpStatus: 401
 | 
			
		||||
        });
 | 
			
		||||
      });
 | 
			
		||||
      it('rejects requests from a write user', done => {
 | 
			
		||||
        TestHelper.request(server, done, {
 | 
			
		||||
          method: 'delete',
 | 
			
		||||
          url: '/template/treatment/heat%20treatment',
 | 
			
		||||
          auth: {basic: 'janedoe'},
 | 
			
		||||
          httpStatus: 403
 | 
			
		||||
        })
 | 
			
		||||
      });
 | 
			
		||||
      it('returns 404 for an unknown name', done => {
 | 
			
		||||
        TestHelper.request(server, done, {
 | 
			
		||||
          method: 'delete',
 | 
			
		||||
          url: '/template/treatment/xxx',
 | 
			
		||||
          auth: {basic: 'admin'},
 | 
			
		||||
          httpStatus: 404
 | 
			
		||||
        })
 | 
			
		||||
      });
 | 
			
		||||
      it('rejects unauthorized requests', done => {
 | 
			
		||||
        TestHelper.request(server, done, {
 | 
			
		||||
          method: 'delete',
 | 
			
		||||
          url: '/template/treatment/heat%20treatment',
 | 
			
		||||
          httpStatus: 401
 | 
			
		||||
        })
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  describe('/template/measurement', () => {
 | 
			
		||||
    describe('GET /template/measurements', () => {
 | 
			
		||||
      it('returns all measurement templates', done => {
 | 
			
		||||
        TestHelper.request(server, done, {
 | 
			
		||||
          method: 'get',
 | 
			
		||||
          url: '/template/measurements',
 | 
			
		||||
          auth: {basic: 'janedoe'},
 | 
			
		||||
          httpStatus: 200
 | 
			
		||||
        }).end((err, res) => {
 | 
			
		||||
          if (err) return done(err);
 | 
			
		||||
          const json = require('../test/db.json');
 | 
			
		||||
          should(res.body).have.lengthOf(json.collections.measurement_templates.length);
 | 
			
		||||
          should(res.body).matchEach(measurement => {
 | 
			
		||||
            should(measurement).have.only.keys('_id', 'name', 'parameters');
 | 
			
		||||
            should(measurement).have.property('_id').be.type('string');
 | 
			
		||||
            should(measurement).have.property('name').be.type('string');
 | 
			
		||||
            should(measurement.parameters).matchEach(number => {
 | 
			
		||||
              should(number).have.only.keys('name', 'range');
 | 
			
		||||
              should(number).have.property('name').be.type('string');
 | 
			
		||||
              should(number).have.property('range').be.type('object');
 | 
			
		||||
            });
 | 
			
		||||
          });
 | 
			
		||||
          done();
 | 
			
		||||
        });
 | 
			
		||||
      });
 | 
			
		||||
      it('rejects an API key', done => {
 | 
			
		||||
        TestHelper.request(server, done, {
 | 
			
		||||
          method: 'get',
 | 
			
		||||
          url: '/template/measurements',
 | 
			
		||||
          auth: {key: 'janedoe'},
 | 
			
		||||
          httpStatus: 401
 | 
			
		||||
        });
 | 
			
		||||
      });
 | 
			
		||||
      it('rejects unauthorized requests', done => {
 | 
			
		||||
        TestHelper.request(server, done, {
 | 
			
		||||
          method: 'get',
 | 
			
		||||
          url: '/template/measurements',
 | 
			
		||||
          httpStatus: 401
 | 
			
		||||
        });
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    describe('GET /template/measurement/{name}', () => {
 | 
			
		||||
      it('returns the right measurement template', done => {
 | 
			
		||||
        TestHelper.request(server, done, {
 | 
			
		||||
          method: 'get',
 | 
			
		||||
          url: '/template/measurement/spectrum',
 | 
			
		||||
          auth: {basic: 'janedoe'},
 | 
			
		||||
          httpStatus: 200,
 | 
			
		||||
          res: {_id: '300000000000000000000001', name: 'spectrum', parameters: [{name: 'dpt', range: {}}]}
 | 
			
		||||
        });
 | 
			
		||||
      });
 | 
			
		||||
      it('rejects an API key', done => {
 | 
			
		||||
        TestHelper.request(server, done, {
 | 
			
		||||
          method: 'get',
 | 
			
		||||
          url: '/template/measurement/spectrum',
 | 
			
		||||
          auth: {key: 'janedoe'},
 | 
			
		||||
          httpStatus: 401
 | 
			
		||||
        });
 | 
			
		||||
      });
 | 
			
		||||
      it('rejects an unknown name', done => {
 | 
			
		||||
        TestHelper.request(server, done, {
 | 
			
		||||
          method: 'get',
 | 
			
		||||
          url: '/template/measurement/xxx',
 | 
			
		||||
          auth: {basic: 'janedoe'},
 | 
			
		||||
          httpStatus: 404
 | 
			
		||||
        });
 | 
			
		||||
      });
 | 
			
		||||
      it('rejects unauthorized requests', done => {
 | 
			
		||||
        TestHelper.request(server, done, {
 | 
			
		||||
          method: 'get',
 | 
			
		||||
          url: '/template/measurement/spectrum',
 | 
			
		||||
          httpStatus: 401
 | 
			
		||||
        });
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    describe('PUT /template/measurement/{name}', () => {
 | 
			
		||||
      it('returns the right measurement template', done => {
 | 
			
		||||
        TestHelper.request(server, done, {
 | 
			
		||||
          method: 'put',
 | 
			
		||||
          url: '/template/measurement/spectrum',
 | 
			
		||||
          auth: {basic: 'admin'},
 | 
			
		||||
          httpStatus: 200,
 | 
			
		||||
          req: {},
 | 
			
		||||
          res: {_id: '300000000000000000000001', name: 'spectrum', parameters: [{name: 'dpt', range: {}}]}
 | 
			
		||||
        });
 | 
			
		||||
      });
 | 
			
		||||
      it('keeps unchanged properties', done => {
 | 
			
		||||
        TestHelper.request(server, done, {
 | 
			
		||||
          method: 'put',
 | 
			
		||||
          url: '/template/measurement/spectrum',
 | 
			
		||||
          auth: {basic: 'admin'},
 | 
			
		||||
          httpStatus: 200,
 | 
			
		||||
          req: {name: 'spectrum', parameters: [{name: 'dpt', range: {}}]},
 | 
			
		||||
          res: {_id: '300000000000000000000001', name: 'spectrum', parameters: [{name: 'dpt', range: {}}]}
 | 
			
		||||
        });
 | 
			
		||||
      });
 | 
			
		||||
      it('changes the given properties', done => {
 | 
			
		||||
        TestHelper.request(server, done, {
 | 
			
		||||
          method: 'put',
 | 
			
		||||
          url: '/template/measurement/spectrum',
 | 
			
		||||
          auth: {basic: 'admin'},
 | 
			
		||||
          httpStatus: 200,
 | 
			
		||||
          req: {name: 'IR spectrum', parameters: [{name: 'data point table', range: {min: 0, max: 1000}}]},
 | 
			
		||||
        }).end((err, res) => {
 | 
			
		||||
          if (err) return done(err);
 | 
			
		||||
          should(res.body).be.eql({_id: '300000000000000000000001', name: 'IR spectrum', parameters: [{name: 'data point table', range: {min: 0, max: 1000}}]});
 | 
			
		||||
          TemplateMeasurementModel.find({name: 'IR spectrum'}).lean().exec((err, data:any) => {
 | 
			
		||||
            if (err) return done(err);
 | 
			
		||||
            should(data).have.lengthOf(1);
 | 
			
		||||
            should(data[0]).have.only.keys('_id', 'name', 'parameters');
 | 
			
		||||
            should(data[0]).have.property('name', 'IR spectrum');
 | 
			
		||||
            should(data[0]).have.property('parameters').have.lengthOf(1);
 | 
			
		||||
            should(data[0].parameters[0]).have.property('name', 'data point table');
 | 
			
		||||
            should(data[0].parameters[0]).have.property('range');
 | 
			
		||||
            should(data[0].parameters[0].range).have.property('min', 0);
 | 
			
		||||
            should(data[0].parameters[0].range).have.property('max', 1000);
 | 
			
		||||
            done();
 | 
			
		||||
          });
 | 
			
		||||
        });
 | 
			
		||||
      });
 | 
			
		||||
      it('supports values ranges', done => {
 | 
			
		||||
        TestHelper.request(server, done, {
 | 
			
		||||
          method: 'put',
 | 
			
		||||
          url: '/template/measurement/spectrum',
 | 
			
		||||
          auth: {basic: 'admin'},
 | 
			
		||||
          httpStatus: 200,
 | 
			
		||||
          req: {parameters: [{name: 'dpt', range: {values: [1, 2, 5]}}]},
 | 
			
		||||
          res: {_id: '300000000000000000000001', name: 'spectrum', parameters: [{name: 'dpt', range: {values: [1, 2, 5]}}]}
 | 
			
		||||
        });
 | 
			
		||||
      });
 | 
			
		||||
      it('supports min max ranges', done => {
 | 
			
		||||
        TestHelper.request(server, done, {
 | 
			
		||||
          method: 'put',
 | 
			
		||||
          url: '/template/measurement/spectrum',
 | 
			
		||||
          auth: {basic: 'admin'},
 | 
			
		||||
          httpStatus: 200,
 | 
			
		||||
          req: {parameters: [{name: 'dpt', range: {min: 0, max: 1000}}]},
 | 
			
		||||
          res: {_id: '300000000000000000000001', name: 'spectrum', parameters: [{name: 'dpt', range: {min: 0, max: 1000}}]}
 | 
			
		||||
        });
 | 
			
		||||
      });
 | 
			
		||||
      it('supports empty ranges', done => {
 | 
			
		||||
        TestHelper.request(server, done, {
 | 
			
		||||
          method: 'put',
 | 
			
		||||
          url: '/template/measurement/kf',
 | 
			
		||||
          auth: {basic: 'admin'},
 | 
			
		||||
          httpStatus: 200,
 | 
			
		||||
          req: {parameters: [{name: 'weight %', range: {}}]},
 | 
			
		||||
          res: {_id: '300000000000000000000002', name: 'kf', parameters: [{name: 'weight %', range: {}}]}
 | 
			
		||||
        });
 | 
			
		||||
      });
 | 
			
		||||
      it('adds a new template for an unknown name', done => {
 | 
			
		||||
        TestHelper.request(server, done, {
 | 
			
		||||
          method: 'put',
 | 
			
		||||
          url: '/template/measurement/vz',
 | 
			
		||||
          auth: {basic: 'admin'},
 | 
			
		||||
          httpStatus: 200,
 | 
			
		||||
          req: {name: 'vz', parameters: [{name: 'vz', range: {min: 1}}]}
 | 
			
		||||
        }).end(err => {
 | 
			
		||||
          if (err) return done(err);
 | 
			
		||||
          TemplateMeasurementModel.find({name: 'vz'}).lean().exec((err, data:any) => {
 | 
			
		||||
            if (err) return done(err);
 | 
			
		||||
            should(data).have.lengthOf(1);
 | 
			
		||||
            should(data[0]).have.only.keys('_id', 'name', 'parameters', '__v');
 | 
			
		||||
            should(data[0]).have.property('name', 'vz');
 | 
			
		||||
            should(data[0]).have.property('parameters').have.lengthOf(1);
 | 
			
		||||
            should(data[0].parameters[0]).have.property('name', 'vz');
 | 
			
		||||
            should(data[0].parameters[0]).have.property('range');
 | 
			
		||||
            should(data[0].parameters[0].range).have.property('min', 1);
 | 
			
		||||
            done();
 | 
			
		||||
          });
 | 
			
		||||
        });
 | 
			
		||||
      });
 | 
			
		||||
      it('rejects an incomplete template for a new name', done => {
 | 
			
		||||
        TestHelper.request(server, done, {
 | 
			
		||||
          method: 'put',
 | 
			
		||||
          url: '/template/measurement/vz',
 | 
			
		||||
          auth: {basic: 'admin'},
 | 
			
		||||
          httpStatus: 400,
 | 
			
		||||
          req: {parameters: [{name: 'vz'}]},
 | 
			
		||||
          res: {status: 'Invalid body format'}
 | 
			
		||||
        });
 | 
			
		||||
      });
 | 
			
		||||
      it('rejects already existing names', done => {
 | 
			
		||||
        TestHelper.request(server, done, {
 | 
			
		||||
          method: 'put',
 | 
			
		||||
          url: '/template/measurement/spectrum',
 | 
			
		||||
          auth: {basic: 'admin'},
 | 
			
		||||
          httpStatus: 400,
 | 
			
		||||
          req: {name: 'kf', parameters: [{name: 'dpt', range: {min: 1}}]},
 | 
			
		||||
          res: {status: 'Template name already taken'}
 | 
			
		||||
        });
 | 
			
		||||
      });
 | 
			
		||||
      it('rejects wrong properties', done => {
 | 
			
		||||
        TestHelper.request(server, done, {
 | 
			
		||||
          method: 'put',
 | 
			
		||||
          url: '/template/measurement/spectrum',
 | 
			
		||||
          auth: {basic: 'admin'},
 | 
			
		||||
          httpStatus: 400,
 | 
			
		||||
          req: {parameters: [{name: 'dpt'}], xx: 33},
 | 
			
		||||
          res: {status: 'Invalid body format'}
 | 
			
		||||
        });
 | 
			
		||||
      });
 | 
			
		||||
      it('rejects an API key', done => {
 | 
			
		||||
        TestHelper.request(server, done, {
 | 
			
		||||
          method: 'put',
 | 
			
		||||
          url: '/template/measurement/spectrum',
 | 
			
		||||
          auth: {key: 'admin'},
 | 
			
		||||
          httpStatus: 401,
 | 
			
		||||
          req: {}
 | 
			
		||||
        });
 | 
			
		||||
      });
 | 
			
		||||
      it('rejects requests from a write user', done => {
 | 
			
		||||
        TestHelper.request(server, done, {
 | 
			
		||||
          method: 'put',
 | 
			
		||||
          url: '/template/measurement/spectrum',
 | 
			
		||||
          auth: {basic: 'janedoe'},
 | 
			
		||||
          httpStatus: 403,
 | 
			
		||||
          req: {}
 | 
			
		||||
        });
 | 
			
		||||
      });
 | 
			
		||||
      it('rejects unauthorized requests', done => {
 | 
			
		||||
        TestHelper.request(server, done, {
 | 
			
		||||
          method: 'put',
 | 
			
		||||
          url: '/template/measurement/spectrum',
 | 
			
		||||
          httpStatus: 401,
 | 
			
		||||
          req: {}
 | 
			
		||||
        });
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    describe('DELETE /template/measurement/{name}', () => {
 | 
			
		||||
      it('deletes the template', done => {
 | 
			
		||||
        TestHelper.request(server, done, {
 | 
			
		||||
          method: 'delete',
 | 
			
		||||
          url: '/template/measurement/spectrum',
 | 
			
		||||
          auth: {basic: 'admin'},
 | 
			
		||||
          httpStatus: 200
 | 
			
		||||
        }).end((err, res) => {
 | 
			
		||||
          if (err) return done(err);
 | 
			
		||||
          should(res.body).be.eql({status: 'OK'});
 | 
			
		||||
          TemplateMeasurementModel.find({name: 'spectrum'}).lean().exec((err, data:any) => {
 | 
			
		||||
            if (err) return done(err);
 | 
			
		||||
            should(data).have.lengthOf(0);
 | 
			
		||||
            done();
 | 
			
		||||
          });
 | 
			
		||||
        });
 | 
			
		||||
      });
 | 
			
		||||
      it('rejects deleting a template still in use');
 | 
			
		||||
      it('rejects an API key', done => {
 | 
			
		||||
        TestHelper.request(server, done, {
 | 
			
		||||
          method: 'delete',
 | 
			
		||||
          url: '/template/measurement/spectrum',
 | 
			
		||||
          auth: {key: 'admin'},
 | 
			
		||||
          httpStatus: 401
 | 
			
		||||
        });
 | 
			
		||||
      });
 | 
			
		||||
      it('rejects requests from a write user', done => {
 | 
			
		||||
        TestHelper.request(server, done, {
 | 
			
		||||
          method: 'delete',
 | 
			
		||||
          url: '/template/measurement/spectrum',
 | 
			
		||||
          auth: {basic: 'janedoe'},
 | 
			
		||||
          httpStatus: 403
 | 
			
		||||
        })
 | 
			
		||||
      });
 | 
			
		||||
      it('returns 404 for an unknown name', done => {
 | 
			
		||||
        TestHelper.request(server, done, {
 | 
			
		||||
          method: 'delete',
 | 
			
		||||
          url: '/template/measurement/xxx',
 | 
			
		||||
          auth: {basic: 'admin'},
 | 
			
		||||
          httpStatus: 404
 | 
			
		||||
        })
 | 
			
		||||
      });
 | 
			
		||||
      it('rejects unauthorized requests', done => {
 | 
			
		||||
        TestHelper.request(server, done, {
 | 
			
		||||
          method: 'delete',
 | 
			
		||||
          url: '/template/measurement/spectrum',
 | 
			
		||||
          httpStatus: 401
 | 
			
		||||
        })
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
});
 | 
			
		||||
							
								
								
									
										91
									
								
								src/routes/template.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										91
									
								
								src/routes/template.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,91 @@
 | 
			
		||||
import express from 'express';
 | 
			
		||||
 | 
			
		||||
import TemplateValidate from './validate/template';
 | 
			
		||||
import TemplateTreatmentModel from '../models/treatment_template';
 | 
			
		||||
import TemplateMeasurementModel from '../models/measurement_template';
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
const router = express.Router();
 | 
			
		||||
 | 
			
		||||
router.get('/template/:collection(measurements|treatments)', (req, res, next) => {
 | 
			
		||||
  if (!req.auth(res, ['read', 'write', 'maintain', 'dev', 'admin'], 'basic')) return;
 | 
			
		||||
 | 
			
		||||
  (req.params.collection === 'treatments' ? TemplateTreatmentModel : TemplateMeasurementModel)
 | 
			
		||||
    .find({}).lean().exec((err, data) => {
 | 
			
		||||
     if (err) next (err);
 | 
			
		||||
     res.json(data.map(e => TemplateValidate.output(e)).filter(e => e !== null));  // validate all and filter null values from validation errors
 | 
			
		||||
  });
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
router.get('/template/:collection(measurement|treatment)/:name', (req, res, next) => {
 | 
			
		||||
  if (!req.auth(res, ['read', 'write', 'maintain', 'dev', 'admin'], 'basic')) return;
 | 
			
		||||
 | 
			
		||||
  (req.params.collection === 'treatment' ? TemplateTreatmentModel : TemplateMeasurementModel)
 | 
			
		||||
    .findOne({name: req.params.name}).lean().exec((err, data) => {
 | 
			
		||||
    if (err) next (err);
 | 
			
		||||
    if (data) {
 | 
			
		||||
      res.json(TemplateValidate.output(data));
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
      res.status(404).json({status: 'Not found'});
 | 
			
		||||
    }
 | 
			
		||||
  });
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
router.put('/template/:collection(measurement|treatment)/:name', (req, res, next) => {
 | 
			
		||||
  if (!req.auth(res, ['maintain', 'admin'], 'basic')) return;
 | 
			
		||||
 | 
			
		||||
  const collectionModel = req.params.collection === 'treatment' ? TemplateTreatmentModel : TemplateMeasurementModel;
 | 
			
		||||
 | 
			
		||||
  collectionModel.findOne({name: req.params.name}).lean().exec((err, data) => {
 | 
			
		||||
    if (err) next (err);
 | 
			
		||||
    const templateState = data? 'change': 'new';
 | 
			
		||||
    const {error, value: template} = TemplateValidate.input(req.body, templateState);
 | 
			
		||||
    if(error !== undefined) {
 | 
			
		||||
      res.status(400).json({status: 'Invalid body format'});
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (template.hasOwnProperty('name') && template.name !== req.params.name) {
 | 
			
		||||
      collectionModel.find({name: template.name}).lean().exec((err, data) => {
 | 
			
		||||
        if (err) next (err);
 | 
			
		||||
        if (data.length > 0) {
 | 
			
		||||
          res.status(400).json({status: 'Template name already taken'});
 | 
			
		||||
          return;
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
          f();
 | 
			
		||||
        }
 | 
			
		||||
      });
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
      f();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function f() {  // to resolve async
 | 
			
		||||
      collectionModel.findOneAndUpdate({name: req.params.name}, template, {new: true, upsert: true}).lean().exec((err, data) => {
 | 
			
		||||
        if (err) next(err);
 | 
			
		||||
        res.json(TemplateValidate.output(data));
 | 
			
		||||
      });
 | 
			
		||||
    }
 | 
			
		||||
  });
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
router.delete('/template/:collection(measurement|treatment)/:name', (req, res, next) => {
 | 
			
		||||
  if (!req.auth(res, ['maintain', 'admin'], 'basic')) return;
 | 
			
		||||
 | 
			
		||||
  (req.params.collection === 'treatment' ? TemplateTreatmentModel : TemplateMeasurementModel)
 | 
			
		||||
    .findOneAndDelete({name: req.params.name}).lean().exec((err, data) => {
 | 
			
		||||
    if (err) next(err);
 | 
			
		||||
    if (data) {
 | 
			
		||||
      res.json({status: 'OK'})
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
      res.status(404).json({status: 'Not found'});
 | 
			
		||||
    }
 | 
			
		||||
  });
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
module.exports = router;
 | 
			
		||||
							
								
								
									
										59
									
								
								src/routes/validate/template.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								src/routes/validate/template.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,59 @@
 | 
			
		||||
import joi from '@hapi/joi';
 | 
			
		||||
import IdValidate from './id';
 | 
			
		||||
 | 
			
		||||
export default class TemplateValidate {
 | 
			
		||||
  private static template = {
 | 
			
		||||
    name: joi.string()
 | 
			
		||||
      .max(128),
 | 
			
		||||
 | 
			
		||||
    parameters: joi.array()
 | 
			
		||||
      .min(1)
 | 
			
		||||
      .items(
 | 
			
		||||
        joi.object({
 | 
			
		||||
          name: joi.string()
 | 
			
		||||
            .max(128)
 | 
			
		||||
            .required(),
 | 
			
		||||
 | 
			
		||||
          range: joi.object({
 | 
			
		||||
            values: joi.array()
 | 
			
		||||
              .min(1),
 | 
			
		||||
 | 
			
		||||
            min: joi.number(),
 | 
			
		||||
 | 
			
		||||
            max: joi.number()
 | 
			
		||||
          })
 | 
			
		||||
            .oxor('values', 'min')
 | 
			
		||||
            .oxor('values', 'max')
 | 
			
		||||
            .required()
 | 
			
		||||
        })
 | 
			
		||||
      )
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  static input (data, param) {  // validate data, param: new(everything required)/change(available attributes are validated)
 | 
			
		||||
    if (param === 'new') {
 | 
			
		||||
      return joi.object({
 | 
			
		||||
        name: this.template.name.required(),
 | 
			
		||||
        parameters: this.template.parameters.required()
 | 
			
		||||
      }).validate(data);
 | 
			
		||||
    }
 | 
			
		||||
    else if (param === 'change') {
 | 
			
		||||
      return joi.object({
 | 
			
		||||
        name: this.template.name,
 | 
			
		||||
        parameters: this.template.parameters
 | 
			
		||||
      }).validate(data);
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
      return{error: 'No parameter specified!', value: {}};
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  static output (data) {  // validate output from database for needed properties, strip everything else
 | 
			
		||||
    data._id = data._id.toString();
 | 
			
		||||
    const {value, error} = joi.object({
 | 
			
		||||
      _id: IdValidate.get(),
 | 
			
		||||
      name: this.template.name,
 | 
			
		||||
      parameters: this.template.parameters
 | 
			
		||||
    }).validate(data, {stripUnknown: true});
 | 
			
		||||
    return error !== undefined? null : value;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@@ -84,6 +84,72 @@
 | 
			
		||||
        ],
 | 
			
		||||
        "__v": 0
 | 
			
		||||
      }
 | 
			
		||||
    ],
 | 
			
		||||
    "treatment_templates": [
 | 
			
		||||
      {
 | 
			
		||||
        "_id": {"$oid":"200000000000000000000001"},
 | 
			
		||||
        "name": "heat treatment",
 | 
			
		||||
        "parameters": [
 | 
			
		||||
          {
 | 
			
		||||
            "name": "material",
 | 
			
		||||
            "range": {
 | 
			
		||||
              "values": [
 | 
			
		||||
                "copper",
 | 
			
		||||
                "hot air"
 | 
			
		||||
              ]
 | 
			
		||||
            }
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            "name": "weeks",
 | 
			
		||||
            "range": {
 | 
			
		||||
              "min": 1,
 | 
			
		||||
              "max": 10
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
        ]
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        "_id": {"$oid":"200000000000000000000002"},
 | 
			
		||||
        "name": "heat treatment 2",
 | 
			
		||||
        "parameters": [
 | 
			
		||||
          {
 | 
			
		||||
            "name": "material",
 | 
			
		||||
            "range": {}
 | 
			
		||||
          }
 | 
			
		||||
        ]
 | 
			
		||||
      }
 | 
			
		||||
    ],
 | 
			
		||||
    "measurement_templates": [
 | 
			
		||||
      {
 | 
			
		||||
        "_id": {"$oid":"300000000000000000000001"},
 | 
			
		||||
        "name": "spectrum",
 | 
			
		||||
        "parameters": [
 | 
			
		||||
          {
 | 
			
		||||
            "name": "dpt",
 | 
			
		||||
            "range": {}
 | 
			
		||||
          }
 | 
			
		||||
        ]
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        "_id": {"$oid":"300000000000000000000002"},
 | 
			
		||||
        "name": "kf",
 | 
			
		||||
        "parameters": [
 | 
			
		||||
          {
 | 
			
		||||
            "name": "weight %",
 | 
			
		||||
            "range": {
 | 
			
		||||
              "min": 0,
 | 
			
		||||
              "max": 1.5
 | 
			
		||||
            }
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            "name": "standard deviation",
 | 
			
		||||
            "range": {
 | 
			
		||||
              "min": 0,
 | 
			
		||||
              "max": 0.5
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
        ]
 | 
			
		||||
      }
 | 
			
		||||
    ]
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user