implemented first /sample methods
This commit is contained in:
		@@ -19,7 +19,7 @@ describe('/material', () => {
 | 
			
		||||
      }).end((err, res) => {
 | 
			
		||||
        if (err) return done(err);
 | 
			
		||||
        const json = require('../test/db.json');
 | 
			
		||||
        should(res.body).have.lengthOf(json.collections.users.length);
 | 
			
		||||
        should(res.body).have.lengthOf(json.collections.materials.length);
 | 
			
		||||
        should(res.body).matchEach(material => {
 | 
			
		||||
          should(material).have.only.keys('_id', 'name', 'supplier', 'group', 'mineral', 'glass_fiber', 'carbon_fiber', 'numbers');
 | 
			
		||||
          should(material).have.property('_id').be.type('string');
 | 
			
		||||
@@ -47,7 +47,7 @@ describe('/material', () => {
 | 
			
		||||
      }).end((err, res) => {
 | 
			
		||||
        if (err) return done(err);
 | 
			
		||||
        const json = require('../test/db.json');
 | 
			
		||||
        should(res.body).have.lengthOf(json.collections.users.length);
 | 
			
		||||
        should(res.body).have.lengthOf(json.collections.materials.length);
 | 
			
		||||
        should(res.body).matchEach(material => {
 | 
			
		||||
          should(material).have.only.keys('_id', 'name', 'supplier', 'group', 'mineral', 'glass_fiber', 'carbon_fiber', 'numbers');
 | 
			
		||||
          should(material).have.property('_id').be.type('string');
 | 
			
		||||
@@ -82,7 +82,7 @@ describe('/material', () => {
 | 
			
		||||
        url: '/material/100000000000000000000001',
 | 
			
		||||
        auth: {basic: 'janedoe'},
 | 
			
		||||
        httpStatus: 200,
 | 
			
		||||
        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}]}
 | 
			
		||||
        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}, {color: 'natural', number: 5514263422}]}
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
    it('returns the right material for an API key', done => {
 | 
			
		||||
@@ -127,7 +127,7 @@ describe('/material', () => {
 | 
			
		||||
        auth: {basic: 'janedoe'},
 | 
			
		||||
        httpStatus: 200,
 | 
			
		||||
        req: {},
 | 
			
		||||
        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}]}
 | 
			
		||||
        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}, {color: 'natural', number: 5514263422}]}
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
    it('keeps unchanged properties', done => {
 | 
			
		||||
@@ -296,7 +296,6 @@ describe('/material', () => {
 | 
			
		||||
        req: {name: 'Crastin CE 2510', supplier: 'Du Pont', group: 'PBT', mineral: 0, glass_fiber: 30, carbon_fiber: 0, numbers: [{color: 'black', number: 5515798402}]}
 | 
			
		||||
      }).end((err, res) => {
 | 
			
		||||
        if (err) return done (err);
 | 
			
		||||
        console.log(res.body);
 | 
			
		||||
        should(res.body).have.only.keys('_id', 'name', 'supplier', 'group', 'mineral', 'glass_fiber', 'carbon_fiber', 'numbers');
 | 
			
		||||
        should(res.body).have.property('_id').be.type('string');
 | 
			
		||||
        should(res.body).have.property('name', 'Crastin CE 2510');
 | 
			
		||||
@@ -324,7 +323,7 @@ describe('/material', () => {
 | 
			
		||||
        if (err) return done (err);
 | 
			
		||||
        MaterialModel.find({name: 'Crastin CE 2510'}).lean().exec((err, data: any) => {
 | 
			
		||||
          if (err) return done (err);
 | 
			
		||||
          console.log(data[0]);
 | 
			
		||||
          should(data).have.lengthOf(1);
 | 
			
		||||
          should(data[0]).have.only.keys('_id', 'name', 'supplier', 'group', 'mineral', 'glass_fiber', 'carbon_fiber', 'numbers', '__v');
 | 
			
		||||
          should(data[0]).have.property('_id');
 | 
			
		||||
          should(data[0]).have.property('name', 'Crastin CE 2510');
 | 
			
		||||
 
 | 
			
		||||
@@ -11,7 +11,7 @@ router.get('/materials', (req, res, next) => {
 | 
			
		||||
  if (!req.auth(res, ['read', 'write', 'maintain', 'dev', 'admin'], 'all')) return;
 | 
			
		||||
 | 
			
		||||
  MaterialModel.find({}).lean().exec((err, data) => {
 | 
			
		||||
    if(err) next(err);
 | 
			
		||||
    if (err) return next(err);
 | 
			
		||||
    res.json(data.map(e => MaterialValidate.output(e)).filter(e => e !== null));  // validate all and filter null values from validation errors
 | 
			
		||||
  });
 | 
			
		||||
});
 | 
			
		||||
@@ -20,8 +20,7 @@ router.get('/material/' + IdValidate.parameter(), (req, res, next) => {
 | 
			
		||||
  if (!req.auth(res, ['read', 'write', 'maintain', 'dev', 'admin'], 'all')) return;
 | 
			
		||||
 | 
			
		||||
  MaterialModel.findById(req.params.id).lean().exec((err, data) => {
 | 
			
		||||
    if(err) next(err);
 | 
			
		||||
    console.log(data);
 | 
			
		||||
    if (err) return next(err);
 | 
			
		||||
    if (data) {
 | 
			
		||||
      res.json(MaterialValidate.output(data));
 | 
			
		||||
    }
 | 
			
		||||
@@ -35,14 +34,14 @@ router.put('/material/' + IdValidate.parameter(), (req, res, next) => {
 | 
			
		||||
  if (!req.auth(res, ['write', 'maintain', 'dev', 'admin'], 'basic')) return;
 | 
			
		||||
 | 
			
		||||
  const {error, value: material} = MaterialValidate.input(req.body, 'change');
 | 
			
		||||
  if(error !== undefined) {
 | 
			
		||||
  if (error) {
 | 
			
		||||
    res.status(400).json({status: 'Invalid body format'});
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (material.hasOwnProperty('name')) {
 | 
			
		||||
    MaterialModel.find({name: material.name}).lean().exec((err, data) => {
 | 
			
		||||
      if(err) next(err);
 | 
			
		||||
      if (err) return next(err);
 | 
			
		||||
      if (data.length > 0 && data[0]._id != req.params.id) {
 | 
			
		||||
        res.status(400).json({status: 'Material name already taken'});
 | 
			
		||||
        return;
 | 
			
		||||
@@ -58,7 +57,7 @@ router.put('/material/' + IdValidate.parameter(), (req, res, next) => {
 | 
			
		||||
 | 
			
		||||
  function f() {  // to resolve async
 | 
			
		||||
    MaterialModel.findByIdAndUpdate(req.params.id, material, {new: true}).lean().exec((err, data) => {
 | 
			
		||||
      if (err) next(err);
 | 
			
		||||
      if (err) return next(err);
 | 
			
		||||
      if (data) {
 | 
			
		||||
        res.json(MaterialValidate.output(data));
 | 
			
		||||
      }
 | 
			
		||||
@@ -73,7 +72,7 @@ router.delete('/material/' + IdValidate.parameter(), (req, res, next) => {
 | 
			
		||||
  if (!req.auth(res, ['write', 'maintain', 'dev', 'admin'], 'basic')) return;
 | 
			
		||||
 | 
			
		||||
  MaterialModel.findByIdAndDelete(req.params.id).lean().exec((err, data) => {
 | 
			
		||||
    if (err) next(err);
 | 
			
		||||
    if (err) return next(err);
 | 
			
		||||
    if (data) {
 | 
			
		||||
      res.json({status: 'OK'})
 | 
			
		||||
    }
 | 
			
		||||
@@ -88,20 +87,20 @@ router.post('/material/new', (req, res, next) => {
 | 
			
		||||
 | 
			
		||||
  // validate input
 | 
			
		||||
  const {error, value: material} = MaterialValidate.input(req.body, 'new');
 | 
			
		||||
  if(error !== undefined) {
 | 
			
		||||
  if (error) {
 | 
			
		||||
    res.status(400).json({status: 'Invalid body format'});
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  MaterialModel.find({name: material.name}).lean().exec((err, data) => {
 | 
			
		||||
    if(err) next(err);
 | 
			
		||||
    if (err) return next(err);
 | 
			
		||||
    if (data.length > 0) {
 | 
			
		||||
      res.status(400).json({status: 'Material name already taken'});
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    new MaterialModel(material).save((err, data) => {
 | 
			
		||||
      if(err) next(err);
 | 
			
		||||
      if (err) return next(err);
 | 
			
		||||
      res.json(MaterialValidate.output(data.toObject()));
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										336
									
								
								src/routes/sample.spec.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										336
									
								
								src/routes/sample.spec.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,336 @@
 | 
			
		||||
import should from 'should/as-function';
 | 
			
		||||
import SampleModel from '../models/sample';
 | 
			
		||||
import NoteModel from '../models/note';
 | 
			
		||||
import NoteFieldModel from '../models/note_field';
 | 
			
		||||
import TestHelper from "../helpers/test";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
describe('/sample', () => {
 | 
			
		||||
  let server;
 | 
			
		||||
  before(done => TestHelper.before(done));
 | 
			
		||||
  beforeEach(done => server = TestHelper.beforeEach(server, done));
 | 
			
		||||
  afterEach(done => TestHelper.afterEach(server, done));
 | 
			
		||||
 | 
			
		||||
  describe('GET /samples', () => {
 | 
			
		||||
    it('returns all samples', done => {
 | 
			
		||||
      TestHelper.request(server, done, {
 | 
			
		||||
        method: 'get',
 | 
			
		||||
        url: '/samples',
 | 
			
		||||
        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.samples.length);
 | 
			
		||||
        should(res.body).matchEach(material => {
 | 
			
		||||
          should(material).have.only.keys('_id', 'number', 'type', 'color', 'batch', 'material_id', 'note_id', 'user_id');
 | 
			
		||||
          should(material).have.property('_id').be.type('string');
 | 
			
		||||
          should(material).have.property('number').be.type('string');
 | 
			
		||||
          should(material).have.property('type').be.type('string');
 | 
			
		||||
          should(material).have.property('color').be.type('string');
 | 
			
		||||
          should(material).have.property('batch').be.type('string');
 | 
			
		||||
          should(material).have.property('material_id').be.type('string');
 | 
			
		||||
          should(material).have.property('note_id');
 | 
			
		||||
          should(material).have.property('user_id').be.type('string');
 | 
			
		||||
        });
 | 
			
		||||
        done();
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
    it('works with an API key', done => {
 | 
			
		||||
      TestHelper.request(server, done, {
 | 
			
		||||
        method: 'get',
 | 
			
		||||
        url: '/samples',
 | 
			
		||||
        auth: {key: 'janedoe'},
 | 
			
		||||
        httpStatus: 200
 | 
			
		||||
      }).end((err, res) => {
 | 
			
		||||
        if (err) return done(err);
 | 
			
		||||
        const json = require('../test/db.json');
 | 
			
		||||
        should(res.body).have.lengthOf(json.collections.samples.length);
 | 
			
		||||
        should(res.body).matchEach(material => {
 | 
			
		||||
          should(material).have.only.keys('_id', 'number', 'type', 'color', 'batch', 'material_id', 'note_id', 'user_id');
 | 
			
		||||
          should(material).have.property('_id').be.type('string');
 | 
			
		||||
          should(material).have.property('number').be.type('string');
 | 
			
		||||
          should(material).have.property('type').be.type('string');
 | 
			
		||||
          should(material).have.property('color').be.type('string');
 | 
			
		||||
          should(material).have.property('batch').be.type('string');
 | 
			
		||||
          should(material).have.property('material_id').be.type('string');
 | 
			
		||||
          should(material).have.property('note_id');
 | 
			
		||||
          should(material).have.property('user_id').be.type('string');
 | 
			
		||||
        });
 | 
			
		||||
        done();
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
    it('rejects unauthorized requests', done => {
 | 
			
		||||
      TestHelper.request(server, done, {
 | 
			
		||||
        method: 'get',
 | 
			
		||||
        url: '/samples',
 | 
			
		||||
        httpStatus: 401
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  describe('POST /sample/new', () => {
 | 
			
		||||
    it('returns the right sample', done => {
 | 
			
		||||
      TestHelper.request(server, done, {
 | 
			
		||||
        method: 'post',
 | 
			
		||||
        url: '/sample/new',
 | 
			
		||||
        auth: {basic: 'janedoe'},
 | 
			
		||||
        httpStatus: 200,
 | 
			
		||||
        req: {number: 'Rng172', color: 'black', type: 'granulate', batch: '1560237365', material_id: '100000000000000000000001', notes: {comment: 'Testcomment', sample_references: [{id: '400000000000000000000003', relation: 'part to this sample'}]}}
 | 
			
		||||
      }).end((err, res) => {
 | 
			
		||||
        if (err) return done (err);
 | 
			
		||||
        should(res.body).have.only.keys('_id', 'number', 'color', 'type', 'batch', 'material_id', 'note_id', 'user_id');
 | 
			
		||||
        should(res.body).have.property('_id').be.type('string');
 | 
			
		||||
        should(res.body).have.property('number', 'Rng172');
 | 
			
		||||
        should(res.body).have.property('color', 'black');
 | 
			
		||||
        should(res.body).have.property('type', 'granulate');
 | 
			
		||||
        should(res.body).have.property('batch', '1560237365');
 | 
			
		||||
        should(res.body).have.property('material_id', '100000000000000000000001');
 | 
			
		||||
        should(res.body).have.property('note_id').be.type('string');
 | 
			
		||||
        should(res.body).have.property('user_id', '000000000000000000000002');
 | 
			
		||||
        done();
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
    it('stores the sample', done => {
 | 
			
		||||
      TestHelper.request(server, done, {
 | 
			
		||||
        method: 'post',
 | 
			
		||||
        url: '/sample/new',
 | 
			
		||||
        auth: {basic: 'janedoe'},
 | 
			
		||||
        httpStatus: 200,
 | 
			
		||||
        req: {number: 'Rng172', color: 'black', type: 'granulate', batch: '1560237365', material_id: '100000000000000000000001', notes: {comment: 'Testcomment', sample_references: [{id: '400000000000000000000003', relation: 'part to this sample'}]}}
 | 
			
		||||
      }).end(err => {
 | 
			
		||||
        if (err) return done (err);
 | 
			
		||||
        SampleModel.find({number: 'Rng172'}).lean().exec((err, data: any) => {
 | 
			
		||||
          if (err) return done (err);
 | 
			
		||||
          should(data).have.lengthOf(1);
 | 
			
		||||
          should(data[0]).have.only.keys('_id', 'number', 'color', 'type', 'batch', 'material_id', 'note_id', 'user_id', '__v');
 | 
			
		||||
          should(data[0]).have.property('_id');
 | 
			
		||||
          should(data[0]).have.property('number', 'Rng172');
 | 
			
		||||
          should(data[0]).have.property('color', 'black');
 | 
			
		||||
          should(data[0]).have.property('type', 'granulate');
 | 
			
		||||
          should(data[0]).have.property('batch', '1560237365');
 | 
			
		||||
          should(data[0].material_id.toString()).be.eql('100000000000000000000001');
 | 
			
		||||
          should(data[0].user_id.toString()).be.eql('000000000000000000000002');
 | 
			
		||||
          should(data[0]).have.property('note_id');
 | 
			
		||||
          NoteModel.findById(data[0].note_id).lean().exec((err, data: any) => {
 | 
			
		||||
            if (err) return done (err);
 | 
			
		||||
            should(data).have.property('_id');
 | 
			
		||||
            should(data).have.property('comment', 'Testcomment');
 | 
			
		||||
            should(data).have.property('sample_references');
 | 
			
		||||
            should(data.sample_references).have.lengthOf(1);
 | 
			
		||||
            should(data.sample_references[0].id.toString()).be.eql('400000000000000000000003');
 | 
			
		||||
            should(data.sample_references[0]).have.property('relation', 'part to this sample');
 | 
			
		||||
            done();
 | 
			
		||||
          });
 | 
			
		||||
        })
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
    it('stores the custom fields', done => {
 | 
			
		||||
      TestHelper.request(server, done, {
 | 
			
		||||
        method: 'post',
 | 
			
		||||
        url: '/sample/new',
 | 
			
		||||
        auth: {basic: 'janedoe'},
 | 
			
		||||
        httpStatus: 200,
 | 
			
		||||
        req: {number: 'Rng172', color: 'black', type: 'granulate', batch: '1560237365', material_id: '100000000000000000000001', notes: {comment: 'Testcomment', sample_references: [], custom_fields: {field1: 'a', field2: 'b', 'not allowed for new applications': true}}}
 | 
			
		||||
      }).end((err, res) => {
 | 
			
		||||
        if (err) return done (err);
 | 
			
		||||
        NoteModel.findById(res.body.note_id).lean().exec((err, data: any) => {
 | 
			
		||||
          if (err) return done(err);
 | 
			
		||||
          should(data).have.property('_id');
 | 
			
		||||
          should(data).have.property('comment', 'Testcomment');
 | 
			
		||||
          should(data).have.property('sample_references').have.lengthOf(0);
 | 
			
		||||
          should(data).have.property('custom_fields');
 | 
			
		||||
          should(data.custom_fields).have.property('field1', 'a');
 | 
			
		||||
          should(data.custom_fields).have.property('field2', 'b');
 | 
			
		||||
          should(data.custom_fields).have.property('not allowed for new applications', true);
 | 
			
		||||
          NoteFieldModel.find({name: 'field1'}).lean().exec((err, data) => {
 | 
			
		||||
            if (err) return done(err);
 | 
			
		||||
            should(data).have.lengthOf(1);
 | 
			
		||||
            should(data[0]).have.property('qty', 1);
 | 
			
		||||
            NoteFieldModel.find({name: 'field2'}).lean().exec((err, data) => {
 | 
			
		||||
              if (err) return done(err);
 | 
			
		||||
              should(data).have.lengthOf(1);
 | 
			
		||||
              should(data[0]).have.property('qty', 1);
 | 
			
		||||
              NoteFieldModel.find({name: 'not allowed for new applications'}).lean().exec((err, data) => {
 | 
			
		||||
                if (err) return done(err);
 | 
			
		||||
                should(data).have.lengthOf(1);
 | 
			
		||||
                should(data[0]).have.property('qty', 3);
 | 
			
		||||
                done();
 | 
			
		||||
              });
 | 
			
		||||
            });
 | 
			
		||||
          });
 | 
			
		||||
        });
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
    it('rejects a color not defined for the material', done => {
 | 
			
		||||
      TestHelper.request(server, done, {
 | 
			
		||||
        method: 'post',
 | 
			
		||||
        url: '/sample/new',
 | 
			
		||||
        auth: {basic: 'janedoe'},
 | 
			
		||||
        httpStatus: 400,
 | 
			
		||||
        req: {number: 'Rng172', color: 'green', type: 'granulate', batch: '1560237365', material_id: '100000000000000000000001', notes: {comment: 'Testcomment', sample_references: [{id: '400000000000000000000003', relation: 'part to this sample'}]}},
 | 
			
		||||
        res: {status: 'Color not available for material'}
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
    it('rejects an unknown material id', done => {
 | 
			
		||||
      TestHelper.request(server, done, {
 | 
			
		||||
        method: 'post',
 | 
			
		||||
        url: '/sample/new',
 | 
			
		||||
        auth: {basic: 'janedoe'},
 | 
			
		||||
        httpStatus: 400,
 | 
			
		||||
        req: {number: 'Rng172', color: 'black', type: 'granulate', batch: '1560237365', material_id: '000000000000000000000001', notes: {comment: 'Testcomment', sample_references: [{id: '400000000000000000000003', relation: 'part to this sample'}]}},
 | 
			
		||||
        res: {status: 'Material not available'}
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
    it('rejects a sample number in use', done => {
 | 
			
		||||
      TestHelper.request(server, done, {
 | 
			
		||||
        method: 'post',
 | 
			
		||||
        url: '/sample/new',
 | 
			
		||||
        auth: {basic: 'janedoe'},
 | 
			
		||||
        httpStatus: 400,
 | 
			
		||||
        req: {number: '1', color: 'black', type: 'granulate', batch: '1560237365', material_id: '100000000000000000000001', notes: {comment: 'Testcomment', sample_references: [{id: '400000000000000000000003', relation: 'part to this sample'}]}},
 | 
			
		||||
        res: {status: 'Sample number already taken'}
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
    it('rejects an invalid sample reference', done => {
 | 
			
		||||
      TestHelper.request(server, done, {
 | 
			
		||||
        method: 'post',
 | 
			
		||||
        url: '/sample/new',
 | 
			
		||||
        auth: {basic: 'janedoe'},
 | 
			
		||||
        httpStatus: 400,
 | 
			
		||||
        req: {number: 'Rng172', color: 'black', type: 'granulate', batch: '1560237365', material_id: '100000000000000000000001', notes: {comment: 'Testcomment', sample_references: [{id: '000000000000000000000003', relation: 'part to this sample'}]}},
 | 
			
		||||
        res: {status: 'Sample reference not available'}
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
    it('rejects a missing color', done => {
 | 
			
		||||
      TestHelper.request(server, done, {
 | 
			
		||||
        method: 'post',
 | 
			
		||||
        url: '/sample/new',
 | 
			
		||||
        auth: {basic: 'janedoe'},
 | 
			
		||||
        httpStatus: 400,
 | 
			
		||||
        req: {number: 'Rng172', type: 'granulate', batch: '1560237365', material_id: '100000000000000000000001', notes: {comment: 'Testcomment', sample_references: [{id: '400000000000000000000003', relation: 'part to this sample'}]}},
 | 
			
		||||
        res: {status: 'Invalid body format'}
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
    it('rejects a missing sample number', done => {
 | 
			
		||||
      TestHelper.request(server, done, {
 | 
			
		||||
        method: 'post',
 | 
			
		||||
        url: '/sample/new',
 | 
			
		||||
        auth: {basic: 'janedoe'},
 | 
			
		||||
        httpStatus: 400,
 | 
			
		||||
        req: {color: 'black', type: 'granulate', batch: '1560237365', material_id: '100000000000000000000001', notes: {comment: 'Testcomment', sample_references: [{id: '400000000000000000000003', relation: 'part to this sample'}]}},
 | 
			
		||||
        res: {status: 'Invalid body format'}
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
    it('rejects a missing type', done => {
 | 
			
		||||
      TestHelper.request(server, done, {
 | 
			
		||||
        method: 'post',
 | 
			
		||||
        url: '/sample/new',
 | 
			
		||||
        auth: {basic: 'janedoe'},
 | 
			
		||||
        httpStatus: 400,
 | 
			
		||||
        req: {number: 'Rng172', color: 'black', batch: '1560237365', material_id: '100000000000000000000001', notes: {comment: 'Testcomment', sample_references: [{id: '400000000000000000000003', relation: 'part to this sample'}]}},
 | 
			
		||||
        res: {status: 'Invalid body format'}
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
    it('rejects a missing batch', done => {
 | 
			
		||||
      TestHelper.request(server, done, {
 | 
			
		||||
        method: 'post',
 | 
			
		||||
        url: '/sample/new',
 | 
			
		||||
        auth: {basic: 'janedoe'},
 | 
			
		||||
        httpStatus: 400,
 | 
			
		||||
        req: {number: 'Rng172', color: 'black', type: 'granulate', material_id: '100000000000000000000001', notes: {comment: 'Testcomment', sample_references: [{id: '400000000000000000000003', relation: 'part to this sample'}]}},
 | 
			
		||||
        res: {status: 'Invalid body format'}
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
    it('rejects a missing material id', done => {
 | 
			
		||||
      TestHelper.request(server, done, {
 | 
			
		||||
        method: 'post',
 | 
			
		||||
        url: '/sample/new',
 | 
			
		||||
        auth: {basic: 'janedoe'},
 | 
			
		||||
        httpStatus: 400,
 | 
			
		||||
        req: {number: 'Rng172', color: 'black', type: 'granulate', batch: '1560237365', notes: {comment: 'Testcomment', sample_references: [{id: '400000000000000000000003', relation: 'part to this sample'}]}},
 | 
			
		||||
        res: {status: 'Invalid body format'}
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
    it('rejects an invalid material id', done => {
 | 
			
		||||
      TestHelper.request(server, done, {
 | 
			
		||||
        method: 'post',
 | 
			
		||||
        url: '/sample/new',
 | 
			
		||||
        auth: {basic: 'janedoe'},
 | 
			
		||||
        httpStatus: 400,
 | 
			
		||||
        req: {number: 'Rng172', color: 'black', type: 'granulate', batch: '1560237365', material_id: '10000000000h000000000001', notes: {comment: 'Testcomment', sample_references: [{id: '400000000000000000000003', relation: 'part to this sample'}]}},
 | 
			
		||||
        res: {status: 'Invalid body format'}
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
    it('rejects an API key', done => {
 | 
			
		||||
      TestHelper.request(server, done, {
 | 
			
		||||
        method: 'post',
 | 
			
		||||
        url: '/sample/new',
 | 
			
		||||
        auth: {key: 'janedoe'},
 | 
			
		||||
        httpStatus: 401,
 | 
			
		||||
        req: {number: 'Rng172', color: 'black', type: 'granulate', batch: '1560237365', material_id: '100000000000000000000001', notes: {comment: 'Testcomment', sample_references: [{id: '400000000000000000000003', relation: 'part to this sample'}]}}
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
    it('rejects requests from a read user', done => {
 | 
			
		||||
      TestHelper.request(server, done, {
 | 
			
		||||
        method: 'post',
 | 
			
		||||
        url: '/sample/new',
 | 
			
		||||
        auth: {basic: 'user'},
 | 
			
		||||
        httpStatus: 403,
 | 
			
		||||
        req: {number: 'Rng172', color: 'black', type: 'granulate', batch: '1560237365', material_id: '100000000000000000000001', notes: {comment: 'Testcomment', sample_references: [{id: '400000000000000000000003', relation: 'part to this sample'}]}}
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
    it('rejects unauthorized requests', done => {
 | 
			
		||||
      TestHelper.request(server, done, {
 | 
			
		||||
        method: 'post',
 | 
			
		||||
        url: '/sample/new',
 | 
			
		||||
        httpStatus: 401,
 | 
			
		||||
        req: {number: 'Rng172', color: 'black', type: 'granulate', batch: '1560237365', material_id: '100000000000000000000001', notes: {comment: 'Testcomment', sample_references: [{id: '400000000000000000000003', relation: 'part to this sample'}]}}
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  describe('GET /sample/notes/fields', () => {
 | 
			
		||||
    it('returns all fields', done => {
 | 
			
		||||
      TestHelper.request(server, done, {
 | 
			
		||||
        method: 'get',
 | 
			
		||||
        url: '/sample/notes/fields',
 | 
			
		||||
        auth: {basic: 'user'},
 | 
			
		||||
        httpStatus: 200
 | 
			
		||||
      }).end((err, res) => {
 | 
			
		||||
        if (err) return done(err);
 | 
			
		||||
        const json = require('../test/db.json');
 | 
			
		||||
        should(res.body).have.lengthOf(json.collections.note_fields.length);
 | 
			
		||||
        should(res.body).matchEach(material => {
 | 
			
		||||
          should(material).have.only.keys('name', 'qty');
 | 
			
		||||
          should(material).have.property('qty').be.type('number');
 | 
			
		||||
        });
 | 
			
		||||
        done();
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
    it('works with an API key', done => {
 | 
			
		||||
      TestHelper.request(server, done, {
 | 
			
		||||
        method: 'get',
 | 
			
		||||
        url: '/sample/notes/fields',
 | 
			
		||||
        auth: {key: 'user'},
 | 
			
		||||
        httpStatus: 200
 | 
			
		||||
      }).end((err, res) => {
 | 
			
		||||
        if (err) return done(err);
 | 
			
		||||
        const json = require('../test/db.json');
 | 
			
		||||
        should(res.body).have.lengthOf(json.collections.note_fields.length);
 | 
			
		||||
        should(res.body).matchEach(material => {
 | 
			
		||||
          should(material).have.only.keys('name', 'qty');
 | 
			
		||||
          should(material).have.property('qty').be.type('number');
 | 
			
		||||
        });
 | 
			
		||||
        done();
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
    it('rejects unauthorized requests', done => {
 | 
			
		||||
      TestHelper.request(server, done, {
 | 
			
		||||
        method: 'get',
 | 
			
		||||
        url: '/sample/notes/fields',
 | 
			
		||||
        httpStatus: 401
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
});
 | 
			
		||||
							
								
								
									
										109
									
								
								src/routes/sample.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										109
									
								
								src/routes/sample.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,109 @@
 | 
			
		||||
import express from 'express';
 | 
			
		||||
 | 
			
		||||
import SampleValidate from './validate/sample';
 | 
			
		||||
import NoteFieldValidate from './validate/note_field';
 | 
			
		||||
import SampleModel from '../models/sample'
 | 
			
		||||
import MaterialModel from '../models/material';
 | 
			
		||||
import NoteModel from '../models/note';
 | 
			
		||||
import NoteFieldModel from '../models/note_field';
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
const router = express.Router();
 | 
			
		||||
 | 
			
		||||
router.get('/samples', (req, res, next) => {
 | 
			
		||||
  if (!req.auth(res, ['read', 'write', 'maintain', 'dev', 'admin'], 'all')) return;
 | 
			
		||||
 | 
			
		||||
  SampleModel.find({}).lean().exec((err, data) => {
 | 
			
		||||
    if (err) return next(err);
 | 
			
		||||
    res.json(data.map(e => SampleValidate.output(e)).filter(e => e !== null));  // validate all and filter null values from validation errors
 | 
			
		||||
  })
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
router.post('/sample/new', (req, res, next) => {
 | 
			
		||||
  if (!req.auth(res, ['write', 'maintain', 'dev', 'admin'], 'basic')) return;
 | 
			
		||||
 | 
			
		||||
  const {error, value: sample} = SampleValidate.input(req.body, 'new');
 | 
			
		||||
  if (error) {
 | 
			
		||||
    return res.status(400).json({status: 'Invalid body format'});
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  MaterialModel.findById(sample.material_id).lean().exec((err, data: any) => {  // validate material_id
 | 
			
		||||
    if (err) return next(err);
 | 
			
		||||
    if (!data) {  // could not find material_id
 | 
			
		||||
      return res.status(400).json({status: 'Material not available'});
 | 
			
		||||
    }
 | 
			
		||||
    if (!data.numbers.find(e => e.color === sample.color)) {  // color for material not specified
 | 
			
		||||
      return res.status(400).json({status: 'Color not available for material'});
 | 
			
		||||
    }
 | 
			
		||||
    SampleModel.findOne({number: sample.number}).lean().exec((err, data) => {  // validate sample number
 | 
			
		||||
      if (err) return next(err);
 | 
			
		||||
      if (data) {  // found entry with sample number
 | 
			
		||||
        return res.status(400).json({status: 'Sample number already taken'});
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      if (sample.notes.sample_references.length > 0) {  // validate sample_references
 | 
			
		||||
        let referencesCount = sample.notes.sample_references.length;
 | 
			
		||||
        sample.notes.sample_references.forEach(reference => {
 | 
			
		||||
          SampleModel.findById(reference.id).lean().exec((err, data) => {
 | 
			
		||||
            if (err) return next(err);
 | 
			
		||||
            if (!data) {
 | 
			
		||||
              return res.status(400).json({status: 'Sample reference not available'});
 | 
			
		||||
            }
 | 
			
		||||
            referencesCount --;
 | 
			
		||||
            if (referencesCount <= 0) {
 | 
			
		||||
              f();
 | 
			
		||||
            }
 | 
			
		||||
          });
 | 
			
		||||
        });
 | 
			
		||||
      }
 | 
			
		||||
      else {
 | 
			
		||||
        f();
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      if (sample.notes.hasOwnProperty('custom_fields') && Object.keys(sample.notes.custom_fields).length > 0) {
 | 
			
		||||
        customFieldsAdd(Object.keys(sample.notes.custom_fields));
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      function f() {  // to resolve async
 | 
			
		||||
        new NoteModel(sample.notes).save((err, data) => {
 | 
			
		||||
          if (err) return next(err);
 | 
			
		||||
          delete sample.notes;
 | 
			
		||||
          sample.note_id = data._id;
 | 
			
		||||
          sample.user_id = req.authDetails.id;
 | 
			
		||||
          new SampleModel(sample).save((err, data) => {
 | 
			
		||||
            if (err) return next(err);
 | 
			
		||||
            res.json(SampleValidate.output(data.toObject()));
 | 
			
		||||
          });
 | 
			
		||||
        });
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
  })
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
router.get('/sample/notes/fields', (req, res, next) => {
 | 
			
		||||
  if (!req.auth(res, ['read', 'write', 'maintain', 'dev', 'admin'], 'all')) return;
 | 
			
		||||
 | 
			
		||||
  NoteFieldModel.find({}).lean().exec((err, data) => {
 | 
			
		||||
    if (err) return next(err);
 | 
			
		||||
    res.json(data.map(e => NoteFieldValidate.output(e)).filter(e => e !== null));  // validate all and filter null values from validation errors
 | 
			
		||||
  })
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
module.exports = router;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
function customFieldsAdd (fields) {
 | 
			
		||||
  fields.forEach(field => {
 | 
			
		||||
    NoteFieldModel.findOneAndUpdate({name: field}, {$inc: {qty: 1}}).lean().exec((err, data) => {  // check if field exists
 | 
			
		||||
      if (err) return console.error(err);
 | 
			
		||||
      if (!data) {  // new field
 | 
			
		||||
        new NoteFieldModel({name: field, qty: 1}).save(err => {
 | 
			
		||||
          if (err) return console.error(err);
 | 
			
		||||
        })
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
}
 | 
			
		||||
@@ -172,7 +172,6 @@ describe('/template', () => {
 | 
			
		||||
          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');
 | 
			
		||||
 
 | 
			
		||||
@@ -41,7 +41,7 @@ router.put('/template/:collection(measurement|treatment)/:name', (req, res, next
 | 
			
		||||
    if (err) next (err);
 | 
			
		||||
    const templateState = data? 'change': 'new';
 | 
			
		||||
    const {error, value: template} = TemplateValidate.input(req.body, templateState);
 | 
			
		||||
    if(error !== undefined) {
 | 
			
		||||
    if (error) {
 | 
			
		||||
      res.status(400).json({status: 'Invalid body format'});
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
@@ -64,7 +64,7 @@ router.put('/template/:collection(measurement|treatment)/:name', (req, res, next
 | 
			
		||||
 | 
			
		||||
    function f() {  // to resolve async
 | 
			
		||||
      collectionModel.findOneAndUpdate({name: req.params.name}, template, {new: true, upsert: true}).lean().exec((err, data) => {
 | 
			
		||||
        if (err) next(err);
 | 
			
		||||
        if (err) return next(err);
 | 
			
		||||
        res.json(TemplateValidate.output(data));
 | 
			
		||||
      });
 | 
			
		||||
    }
 | 
			
		||||
@@ -76,7 +76,7 @@ router.delete('/template/:collection(measurement|treatment)/:name', (req, res, n
 | 
			
		||||
 | 
			
		||||
  (req.params.collection === 'treatment' ? TemplateTreatmentModel : TemplateMeasurementModel)
 | 
			
		||||
    .findOneAndDelete({name: req.params.name}).lean().exec((err, data) => {
 | 
			
		||||
    if (err) next(err);
 | 
			
		||||
    if (err) return next(err);
 | 
			
		||||
    if (data) {
 | 
			
		||||
      res.json({status: 'OK'})
 | 
			
		||||
    }
 | 
			
		||||
@@ -87,5 +87,4 @@ router.delete('/template/:collection(measurement|treatment)/:name', (req, res, n
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
module.exports = router;
 | 
			
		||||
@@ -27,7 +27,7 @@ router.get('/user:username([/](?!key|new).?*|/?)', (req, res, next) => {  // thi
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  UserModel.findOne({name: username}).lean().exec(  (err, data:any) => {
 | 
			
		||||
    if (err) next(err);
 | 
			
		||||
    if (err) return next(err);
 | 
			
		||||
    if (data) {
 | 
			
		||||
      res.json(UserValidate.output(data));  // validate all and filter null values from validation errors
 | 
			
		||||
    }
 | 
			
		||||
@@ -46,7 +46,7 @@ router.put('/user:username([/](?!key|new).?*|/?)', (req, res, next) => {  // thi
 | 
			
		||||
    username = req.params.username;
 | 
			
		||||
  }
 | 
			
		||||
  const {error, value: user} = UserValidate.input(req.body, 'change' + (req.authDetails.level === 'admin'? 'admin' : ''));
 | 
			
		||||
  if(error !== undefined) {
 | 
			
		||||
  if (error) {
 | 
			
		||||
    res.status(400).json({status: 'Invalid body format'});
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
@@ -58,14 +58,14 @@ router.put('/user:username([/](?!key|new).?*|/?)', (req, res, next) => {  // thi
 | 
			
		||||
  // check that user does not already exist if new name was specified
 | 
			
		||||
  if (user.hasOwnProperty('name') && user.name !== username) {
 | 
			
		||||
    UserModel.find({name: user.name}).lean().exec(  (err, data:any) => {
 | 
			
		||||
      if (err) next(err);
 | 
			
		||||
      if (err) return next(err);
 | 
			
		||||
      if (data.length > 0 || UserValidate.isSpecialName(user.name)) {
 | 
			
		||||
        res.status(400).json({status: 'Username already taken'});
 | 
			
		||||
        return;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      UserModel.findOneAndUpdate({name: username}, user, {new: true}).lean().exec(  (err, data:any) => {
 | 
			
		||||
        if (err) next(err);
 | 
			
		||||
        if (err) return next(err);
 | 
			
		||||
        if (data) {
 | 
			
		||||
          res.json(UserValidate.output(data));
 | 
			
		||||
        }
 | 
			
		||||
@@ -77,7 +77,7 @@ router.put('/user:username([/](?!key|new).?*|/?)', (req, res, next) => {  // thi
 | 
			
		||||
  }
 | 
			
		||||
  else {
 | 
			
		||||
    UserModel.findOneAndUpdate({name: username}, user, {new: true}).lean().exec(  (err, data:any) => {
 | 
			
		||||
      if (err) next(err);
 | 
			
		||||
      if (err) return next(err);
 | 
			
		||||
      if (data) {
 | 
			
		||||
        res.json(UserValidate.output(data));  // validate all and filter null values from validation errors
 | 
			
		||||
      }
 | 
			
		||||
@@ -98,7 +98,7 @@ router.delete('/user:username([/](?!key|new).?*|/?)', (req, res, next) => {  //
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  UserModel.findOneAndDelete({name: username}).lean().exec(  (err, data:any) => {
 | 
			
		||||
    if (err) next(err);
 | 
			
		||||
    if (err) return next(err);
 | 
			
		||||
    if (data) {
 | 
			
		||||
      res.json({status: 'OK'})
 | 
			
		||||
    }
 | 
			
		||||
@@ -109,11 +109,10 @@ router.delete('/user:username([/](?!key|new).?*|/?)', (req, res, next) => {  //
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
router.get('/user/key', (req, res, next) => {
 | 
			
		||||
  console.log('hmm');
 | 
			
		||||
  if (!req.auth(res, ['read', 'write', 'maintain', 'dev', 'admin'], 'basic')) return;
 | 
			
		||||
 | 
			
		||||
  UserModel.findOne({name: req.authDetails.username}).lean().exec(  (err, data:any) => {
 | 
			
		||||
    if (err) next(err);
 | 
			
		||||
    if (err) return next(err);
 | 
			
		||||
    res.json({key: data.key});
 | 
			
		||||
  });
 | 
			
		||||
});
 | 
			
		||||
@@ -123,14 +122,14 @@ router.post('/user/new', (req, res, next) => {
 | 
			
		||||
 | 
			
		||||
  // validate input
 | 
			
		||||
  const {error, value: user} = UserValidate.input(req.body, 'new');
 | 
			
		||||
  if(error !== undefined) {
 | 
			
		||||
  if (error) {
 | 
			
		||||
    res.status(400).json({status: 'Invalid body format'});
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // check that user does not already exist
 | 
			
		||||
  UserModel.find({name: user.name}).lean().exec(  (err, data:any) => {
 | 
			
		||||
    if (err) next(err);
 | 
			
		||||
    if (err) return next(err);
 | 
			
		||||
    if (data.length > 0  || UserValidate.isSpecialName(user.name)) {
 | 
			
		||||
      res.status(400).json({status: 'Username already taken'});
 | 
			
		||||
      return;
 | 
			
		||||
@@ -140,7 +139,7 @@ router.post('/user/new', (req, res, next) => {
 | 
			
		||||
    bcrypt.hash(user.pass, 10, (err, hash) => {  // password hashing
 | 
			
		||||
      user.pass = hash;
 | 
			
		||||
      new UserModel(user).save((err, data) => {  // store user
 | 
			
		||||
        if (err) next(err);
 | 
			
		||||
        if (err) return next(err);
 | 
			
		||||
        res.json(UserValidate.output(data.toObject()));
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
@@ -150,15 +149,15 @@ router.post('/user/new', (req, res, next) => {
 | 
			
		||||
router.post('/user/passreset', (req, res, next) => {
 | 
			
		||||
  // check if user/email combo exists
 | 
			
		||||
  UserModel.find({name: req.body.name, email: req.body.email}).lean().exec( (err, data: any) => {
 | 
			
		||||
    if (err) next(err);
 | 
			
		||||
    if (err) return next(err);
 | 
			
		||||
    if (data.length === 1) {  // it exists
 | 
			
		||||
      const newPass = Math.random().toString(36).substring(2);
 | 
			
		||||
      bcrypt.hash(newPass, 10, (err, hash) => {  // password hashing
 | 
			
		||||
        if (err) next(err);
 | 
			
		||||
        if (err) return next(err);
 | 
			
		||||
        UserModel.findByIdAndUpdate(data[0]._id, {pass: hash}, err => {  // write new password
 | 
			
		||||
          if (err) next(err);
 | 
			
		||||
          if (err) return next(err);
 | 
			
		||||
          mail(data[0].email, 'Your new password for the DFOP database', 'Hi, <br><br> You requested to reset your password.<br>Your new password is:<br><br>' + newPass + '<br><br>If you did not request a password reset, talk to the sysadmin quickly!<br><br>Have a nice day.<br><br>The DFOP team', err => {
 | 
			
		||||
            if (err) next(err);
 | 
			
		||||
            if (err) return next(err);
 | 
			
		||||
            res.json({status: 'OK'});
 | 
			
		||||
          });
 | 
			
		||||
        });
 | 
			
		||||
 
 | 
			
		||||
@@ -11,7 +11,16 @@ export default class IdValidate {
 | 
			
		||||
    return this.id.validate(id).error === undefined;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  static parameter() {  // :id url parameter
 | 
			
		||||
  static parameter () {  // :id url parameter
 | 
			
		||||
    return ':id([0-9a-f]{24})';
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  static stringify (data) {
 | 
			
		||||
    Object.keys(data).forEach(key => {
 | 
			
		||||
      if (data[key] !== null && data[key].hasOwnProperty('_bsontype') && data[key]._bsontype === 'ObjectID') {
 | 
			
		||||
        data[key] = data[key].toString();
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
    return data;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@@ -66,7 +66,7 @@ export default class MaterialValidate {  // validate input for material
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  static output (data) {  // validate output from database for needed properties, strip everything else
 | 
			
		||||
    data._id = data._id.toString();
 | 
			
		||||
    data = IdValidate.stringify(data);
 | 
			
		||||
    const {value, error} = joi.object({
 | 
			
		||||
      _id: IdValidate.get(),
 | 
			
		||||
      name: this.material.name,
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										18
									
								
								src/routes/validate/note_field.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								src/routes/validate/note_field.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,18 @@
 | 
			
		||||
import joi from '@hapi/joi';
 | 
			
		||||
 | 
			
		||||
export default class NoteFieldValidate {
 | 
			
		||||
  private static note_field = {
 | 
			
		||||
    name: joi.string()
 | 
			
		||||
      .max(128),
 | 
			
		||||
 | 
			
		||||
    qty: joi.number()
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  static output (data) {
 | 
			
		||||
    const {value, error} = joi.object({
 | 
			
		||||
      name: this.note_field.name,
 | 
			
		||||
      qty: this.note_field.qty
 | 
			
		||||
    }).validate(data, {stripUnknown: true});
 | 
			
		||||
    return error !== undefined? null : value;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										77
									
								
								src/routes/validate/sample.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										77
									
								
								src/routes/validate/sample.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,77 @@
 | 
			
		||||
import joi from '@hapi/joi';
 | 
			
		||||
 | 
			
		||||
import IdValidate from './id';
 | 
			
		||||
 | 
			
		||||
export default class SampleValidate {
 | 
			
		||||
  private static sample = {
 | 
			
		||||
    number: joi.string()
 | 
			
		||||
      .max(128),
 | 
			
		||||
 | 
			
		||||
    color: joi.string()
 | 
			
		||||
      .max(128),
 | 
			
		||||
 | 
			
		||||
    type: joi.string()
 | 
			
		||||
      .max(128),
 | 
			
		||||
 | 
			
		||||
    batch: joi.string()
 | 
			
		||||
      .max(128)
 | 
			
		||||
      .allow(''),
 | 
			
		||||
 | 
			
		||||
    notes: joi.object({
 | 
			
		||||
      comment: joi.string()
 | 
			
		||||
        .max(512),
 | 
			
		||||
 | 
			
		||||
      sample_references: joi.array()
 | 
			
		||||
        .items(joi.object({
 | 
			
		||||
          id: IdValidate.get(),
 | 
			
		||||
 | 
			
		||||
          relation: joi.string()
 | 
			
		||||
            .max(128)
 | 
			
		||||
        })),
 | 
			
		||||
 | 
			
		||||
      custom_fields: joi.object()
 | 
			
		||||
        .pattern(/.*/, joi.alternatives()
 | 
			
		||||
          .try(
 | 
			
		||||
            joi.string().max(128),
 | 
			
		||||
            joi.number(),
 | 
			
		||||
            joi.boolean(),
 | 
			
		||||
            joi.date()
 | 
			
		||||
          )
 | 
			
		||||
        )
 | 
			
		||||
    })
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  static input (data, param) {  // validate data, param: new(everything required)/change(available attributes are validated)
 | 
			
		||||
    if (param === 'new') {
 | 
			
		||||
      return joi.object({
 | 
			
		||||
        number: this.sample.number.required(),
 | 
			
		||||
        color: this.sample.color.required(),
 | 
			
		||||
        type: this.sample.type.required(),
 | 
			
		||||
        batch: this.sample.batch.required(),
 | 
			
		||||
        material_id: IdValidate.get().required(),
 | 
			
		||||
        notes: this.sample.notes.required()
 | 
			
		||||
      }).validate(data);
 | 
			
		||||
    }
 | 
			
		||||
    else if (param === 'change') {
 | 
			
		||||
      return{error: 'Not implemented!', value: {}};
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
      return{error: 'No parameter specified!', value: {}};
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  static output (data) {
 | 
			
		||||
    data = IdValidate.stringify(data);
 | 
			
		||||
    const {value, error} = joi.object({
 | 
			
		||||
      _id: IdValidate.get(),
 | 
			
		||||
      number: this.sample.number,
 | 
			
		||||
      color: this.sample.color,
 | 
			
		||||
      type: this.sample.type,
 | 
			
		||||
      batch: this.sample.batch,
 | 
			
		||||
      material_id: IdValidate.get(),
 | 
			
		||||
      note_id: IdValidate.get().allow(null),
 | 
			
		||||
      user_id: IdValidate.get()
 | 
			
		||||
    }).validate(data, {stripUnknown: true});
 | 
			
		||||
    return error !== undefined? null : value;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@@ -48,7 +48,7 @@ export default class TemplateValidate {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  static output (data) {  // validate output from database for needed properties, strip everything else
 | 
			
		||||
    data._id = data._id.toString();
 | 
			
		||||
    data = IdValidate.stringify(data);
 | 
			
		||||
    const {value, error} = joi.object({
 | 
			
		||||
      _id: IdValidate.get(),
 | 
			
		||||
      name: this.template.name,
 | 
			
		||||
 
 | 
			
		||||
@@ -69,7 +69,7 @@ export default class UserValidate {  // validate input for user
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  static output (data) {  // validate output from database for needed properties, strip everything else
 | 
			
		||||
    data._id = data._id.toString();
 | 
			
		||||
    data = IdValidate.stringify(data);
 | 
			
		||||
    const {value, error} = joi.object({
 | 
			
		||||
      _id: IdValidate.get(),
 | 
			
		||||
      name: this.user.name,
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user