sample number generation
This commit is contained in:
		@@ -16,6 +16,7 @@ SampleProperties:
 | 
				
			|||||||
  properties:
 | 
					  properties:
 | 
				
			||||||
    number:
 | 
					    number:
 | 
				
			||||||
      type: string
 | 
					      type: string
 | 
				
			||||||
 | 
					      readOnly: true
 | 
				
			||||||
      example: Rng172
 | 
					      example: Rng172
 | 
				
			||||||
    type:
 | 
					    type:
 | 
				
			||||||
      type: string
 | 
					      type: string
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,7 +9,7 @@ import UserModel from '../models/user';
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
module.exports = async (req, res, next) => {
 | 
					module.exports = async (req, res, next) => {
 | 
				
			||||||
  let givenMethod = '';  // authorization method given by client, basic taken preferred
 | 
					  let givenMethod = '';  // authorization method given by client, basic taken preferred
 | 
				
			||||||
  let user = {name: '', level: '', id: ''};               // user object
 | 
					  let user = {name: '', level: '', id: '', location: ''};               // user object
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // test authentications
 | 
					  // test authentications
 | 
				
			||||||
  const userBasic = await basic(req, next);
 | 
					  const userBasic = await basic(req, next);
 | 
				
			||||||
@@ -46,7 +46,8 @@ module.exports = async (req, res, next) => {
 | 
				
			|||||||
    method: givenMethod,
 | 
					    method: givenMethod,
 | 
				
			||||||
    username: user.name,
 | 
					    username: user.name,
 | 
				
			||||||
    level: user.level,
 | 
					    level: user.level,
 | 
				
			||||||
    id: user.id
 | 
					    id: user.id,
 | 
				
			||||||
 | 
					    location: user.location
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  next();
 | 
					  next();
 | 
				
			||||||
@@ -63,7 +64,7 @@ function basic (req, next): any {  // checks basic auth and returns changed user
 | 
				
			|||||||
          bcrypt.compare(auth.pass, data[0].pass, (err, res) => {  // check password
 | 
					          bcrypt.compare(auth.pass, data[0].pass, (err, res) => {  // check password
 | 
				
			||||||
            if (err) return next(err);
 | 
					            if (err) return next(err);
 | 
				
			||||||
            if (res === true) {
 | 
					            if (res === true) {
 | 
				
			||||||
              resolve({level: data[0].level, name: data[0].name, id: data[0]._id.toString()});
 | 
					              resolve({level: data[0].level, name: data[0].name, id: data[0]._id.toString(), location: data[0].location});
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            else {
 | 
					            else {
 | 
				
			||||||
              resolve(null);
 | 
					              resolve(null);
 | 
				
			||||||
@@ -87,7 +88,7 @@ function key (req, next): any {  // checks API key and returns changed user obje
 | 
				
			|||||||
      UserModel.find({key: req.query.key}).lean().exec( (err, data: any) => {  // find user
 | 
					      UserModel.find({key: req.query.key}).lean().exec( (err, data: any) => {  // find user
 | 
				
			||||||
        if (err) return next(err);
 | 
					        if (err) return next(err);
 | 
				
			||||||
        if (data.length === 1) {  // one user found
 | 
					        if (data.length === 1) {  // one user found
 | 
				
			||||||
          resolve({level: data[0].level, name: data[0].name, id: data[0]._id.toString()});
 | 
					          resolve({level: data[0].level, name: data[0].name, id: data[0]._id.toString(), location: data[0].location});
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        else {
 | 
					        else {
 | 
				
			||||||
          resolve(null);
 | 
					          resolve(null);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -253,7 +253,7 @@ describe('/condition', () => {
 | 
				
			|||||||
          if (err) return done(err);
 | 
					          if (err) return done(err);
 | 
				
			||||||
          should(data).have.only.keys('_id', 'sample_id', 'number', 'parameters', 'treatment_template', 'status', '__v');
 | 
					          should(data).have.only.keys('_id', 'sample_id', 'number', 'parameters', 'treatment_template', 'status', '__v');
 | 
				
			||||||
          should(data.sample_id.toString()).be.eql('400000000000000000000001');
 | 
					          should(data.sample_id.toString()).be.eql('400000000000000000000001');
 | 
				
			||||||
          should(data).have.property('number', 'A6');
 | 
					          should(data).have.property('number', 'A2');
 | 
				
			||||||
          should(data.treatment_template.toString()).be.eql('200000000000000000000001');
 | 
					          should(data.treatment_template.toString()).be.eql('200000000000000000000001');
 | 
				
			||||||
          should(data).have.property('status', -1);
 | 
					          should(data).have.property('status', -1);
 | 
				
			||||||
          should(data).have.property('parameters');
 | 
					          should(data).have.property('parameters');
 | 
				
			||||||
@@ -346,7 +346,7 @@ describe('/condition', () => {
 | 
				
			|||||||
        should(res.body).have.only.keys('_id', 'sample_id', 'number', 'parameters', 'treatment_template');
 | 
					        should(res.body).have.only.keys('_id', 'sample_id', 'number', 'parameters', 'treatment_template');
 | 
				
			||||||
        should(res.body).have.property('_id').be.type('string');
 | 
					        should(res.body).have.property('_id').be.type('string');
 | 
				
			||||||
        should(res.body).have.property('sample_id', '400000000000000000000002');
 | 
					        should(res.body).have.property('sample_id', '400000000000000000000002');
 | 
				
			||||||
        should(res.body).have.property('number', 'A7');
 | 
					        should(res.body).have.property('number', 'A2');
 | 
				
			||||||
        should(res.body).have.property('treatment_template', '200000000000000000000001');
 | 
					        should(res.body).have.property('treatment_template', '200000000000000000000001');
 | 
				
			||||||
        should(res.body).have.property('parameters');
 | 
					        should(res.body).have.property('parameters');
 | 
				
			||||||
        should(res.body.parameters).have.property('material', 'hot air');
 | 
					        should(res.body.parameters).have.property('material', 'hot air');
 | 
				
			||||||
@@ -367,7 +367,30 @@ describe('/condition', () => {
 | 
				
			|||||||
          if (err) return done(err);
 | 
					          if (err) return done(err);
 | 
				
			||||||
          should(data).have.only.keys('_id', 'sample_id', 'number', 'parameters', 'treatment_template', 'status', '__v');
 | 
					          should(data).have.only.keys('_id', 'sample_id', 'number', 'parameters', 'treatment_template', 'status', '__v');
 | 
				
			||||||
          should(data.sample_id.toString()).be.eql('400000000000000000000002');
 | 
					          should(data.sample_id.toString()).be.eql('400000000000000000000002');
 | 
				
			||||||
          should(data).have.property('number', 'A7');
 | 
					          should(data).have.property('number', 'A2');
 | 
				
			||||||
 | 
					          should(data.treatment_template.toString()).be.eql('200000000000000000000001');
 | 
				
			||||||
 | 
					          should(data).have.property('status', 0);
 | 
				
			||||||
 | 
					          should(data).have.property('parameters');
 | 
				
			||||||
 | 
					          should(data.parameters).have.property('material', 'hot air');
 | 
				
			||||||
 | 
					          should(data.parameters).have.property('weeks', 10);
 | 
				
			||||||
 | 
					          done();
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    it('stores the first condition as 1', done => {
 | 
				
			||||||
 | 
					      TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					        method: 'post',
 | 
				
			||||||
 | 
					        url: '/condition/new',
 | 
				
			||||||
 | 
					        auth: {basic: 'admin'},
 | 
				
			||||||
 | 
					        httpStatus: 200,
 | 
				
			||||||
 | 
					        req: {sample_id: '400000000000000000000003', parameters: {material: 'hot air', weeks: 10}, treatment_template: '200000000000000000000001'}
 | 
				
			||||||
 | 
					      }).end((err, res) => {
 | 
				
			||||||
 | 
					        if (err) return done(err);
 | 
				
			||||||
 | 
					        ConditionModel.findById(res.body._id).lean().exec((err, data: any) => {
 | 
				
			||||||
 | 
					          if (err) return done(err);
 | 
				
			||||||
 | 
					          should(data).have.only.keys('_id', 'sample_id', 'number', 'parameters', 'treatment_template', 'status', '__v');
 | 
				
			||||||
 | 
					          should(data.sample_id.toString()).be.eql('400000000000000000000003');
 | 
				
			||||||
 | 
					          should(data).have.property('number', 'A1');
 | 
				
			||||||
          should(data.treatment_template.toString()).be.eql('200000000000000000000001');
 | 
					          should(data.treatment_template.toString()).be.eql('200000000000000000000001');
 | 
				
			||||||
          should(data).have.property('status', 0);
 | 
					          should(data).have.property('status', 0);
 | 
				
			||||||
          should(data).have.property('parameters');
 | 
					          should(data).have.property('parameters');
 | 
				
			||||||
@@ -518,7 +541,7 @@ describe('/condition', () => {
 | 
				
			|||||||
        should(res.body).have.only.keys('_id', 'sample_id', 'number', 'parameters', 'treatment_template');
 | 
					        should(res.body).have.only.keys('_id', 'sample_id', 'number', 'parameters', 'treatment_template');
 | 
				
			||||||
        should(res.body).have.property('_id').be.type('string');
 | 
					        should(res.body).have.property('_id').be.type('string');
 | 
				
			||||||
        should(res.body).have.property('sample_id', '400000000000000000000002');
 | 
					        should(res.body).have.property('sample_id', '400000000000000000000002');
 | 
				
			||||||
        should(res.body).have.property('number', 'A7');
 | 
					        should(res.body).have.property('number', 'A2');
 | 
				
			||||||
        should(res.body).have.property('treatment_template', '200000000000000000000001');
 | 
					        should(res.body).have.property('treatment_template', '200000000000000000000001');
 | 
				
			||||||
        should(res.body).have.property('parameters');
 | 
					        should(res.body).have.property('parameters');
 | 
				
			||||||
        should(res.body.parameters).have.property('material', 'hot air');
 | 
					        should(res.body.parameters).have.property('material', 'hot air');
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -107,15 +107,14 @@ async function sampleIdCheck (condition, req, res, next) {  // validate sample_i
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
async function numberGenerate (condition, treatmentData, next) {  // validate number, returns false if invalid
 | 
					async function numberGenerate (condition, treatmentData, next) {  // validate number, returns false if invalid
 | 
				
			||||||
  const conditionData = await ConditionModel
 | 
					  const conditionData = await ConditionModel
 | 
				
			||||||
    .find({number: new RegExp('^' + treatmentData.number_prefix + '[0-9]+$', 'm')})
 | 
					    .find({sample_id: condition.sample_id, number: new RegExp('^' + treatmentData.number_prefix + '[0-9]+$', 'm')})
 | 
				
			||||||
    .sort({number: -1})
 | 
					    .sort({number: -1})
 | 
				
			||||||
    .limit(1)
 | 
					    .limit(1)
 | 
				
			||||||
    .lean()
 | 
					    .lean()
 | 
				
			||||||
    .exec()
 | 
					    .exec()
 | 
				
			||||||
    .catch(err => next(err)) as any;
 | 
					    .catch(err => next(err)) as any;
 | 
				
			||||||
  if (conditionData instanceof Error) return false;
 | 
					  if (conditionData instanceof Error) return false;
 | 
				
			||||||
  console.log(conditionData);
 | 
					  return treatmentData.number_prefix + (conditionData.length > 0 ? Number(conditionData[0].number.replace(/[^0-9]+/g, '')) + 1 : 1);
 | 
				
			||||||
  return treatmentData.number_prefix + (Number(conditionData[0].number.replace(/[^0-9]+/g, '')) + 1);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
async function treatmentCheck (condition, param, res, next) {  // validate treatment template, returns false if invalid, otherwise template data
 | 
					async function treatmentCheck (condition, param, res, next) {  // validate treatment template, returns false if invalid, otherwise template data
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,7 +3,7 @@ import SampleModel from '../models/sample';
 | 
				
			|||||||
import NoteModel from '../models/note';
 | 
					import NoteModel from '../models/note';
 | 
				
			||||||
import NoteFieldModel from '../models/note_field';
 | 
					import NoteFieldModel from '../models/note_field';
 | 
				
			||||||
import TestHelper from "../test/helper";
 | 
					import TestHelper from "../test/helper";
 | 
				
			||||||
// TODO: generate sample number
 | 
					
 | 
				
			||||||
// TODO: think again which parameters are required at POST
 | 
					// TODO: think again which parameters are required at POST
 | 
				
			||||||
 | 
					
 | 
				
			||||||
describe('/sample', () => {
 | 
					describe('/sample', () => {
 | 
				
			||||||
@@ -87,7 +87,7 @@ describe('/sample', () => {
 | 
				
			|||||||
        url: '/sample/400000000000000000000001',
 | 
					        url: '/sample/400000000000000000000001',
 | 
				
			||||||
        auth: {basic: 'janedoe'},
 | 
					        auth: {basic: 'janedoe'},
 | 
				
			||||||
        httpStatus: 200,
 | 
					        httpStatus: 200,
 | 
				
			||||||
        req: {number: '1', type: 'granulate', color: 'black', batch: '', material_id: '100000000000000000000004', notes: {}}
 | 
					        req: {type: 'granulate', color: 'black', batch: '', material_id: '100000000000000000000004', notes: {}}
 | 
				
			||||||
      }).end((err, res) => {
 | 
					      }).end((err, res) => {
 | 
				
			||||||
        if (err) return done(err);
 | 
					        if (err) return done(err);
 | 
				
			||||||
        should(res.body).be.eql({_id: '400000000000000000000001', number: '1', type: 'granulate', color: 'black', batch: '', material_id: '100000000000000000000004', note_id: null, user_id: '000000000000000000000002'});
 | 
					        should(res.body).be.eql({_id: '400000000000000000000001', number: '1', type: 'granulate', color: 'black', batch: '', material_id: '100000000000000000000004', note_id: null, user_id: '000000000000000000000002'});
 | 
				
			||||||
@@ -156,14 +156,14 @@ describe('/sample', () => {
 | 
				
			|||||||
        url: '/sample/400000000000000000000001',
 | 
					        url: '/sample/400000000000000000000001',
 | 
				
			||||||
        auth: {basic: 'janedoe'},
 | 
					        auth: {basic: 'janedoe'},
 | 
				
			||||||
        httpStatus: 200,
 | 
					        httpStatus: 200,
 | 
				
			||||||
        req: {number: '10', type: 'part', color: 'signalviolet', batch: '114531', material_id: '100000000000000000000002', notes: {comment: 'Testcomment', sample_references: [{id: '400000000000000000000003', relation: 'part to this sample'}]}}
 | 
					        req: {type: 'part', color: 'signalviolet', batch: '114531', material_id: '100000000000000000000002', notes: {comment: 'Testcomment', sample_references: [{id: '400000000000000000000003', relation: 'part to this sample'}]}}
 | 
				
			||||||
      }).end(err => {
 | 
					      }).end(err => {
 | 
				
			||||||
        if (err) return done (err);
 | 
					        if (err) return done (err);
 | 
				
			||||||
        SampleModel.findById('400000000000000000000001').lean().exec((err, data: any) => {
 | 
					        SampleModel.findById('400000000000000000000001').lean().exec((err, data: any) => {
 | 
				
			||||||
          if (err) return done (err);
 | 
					          if (err) return done (err);
 | 
				
			||||||
          should(data).have.only.keys('_id', 'number', 'color', 'type', 'batch', 'material_id', 'note_id', 'user_id', 'status', '__v');
 | 
					          should(data).have.only.keys('_id', 'number', 'color', 'type', 'batch', 'material_id', 'note_id', 'user_id', 'status', '__v');
 | 
				
			||||||
          should(data).have.property('_id');
 | 
					          should(data).have.property('_id');
 | 
				
			||||||
          should(data).have.property('number', '10');
 | 
					          should(data).have.property('number', '1');
 | 
				
			||||||
          should(data).have.property('color', 'signalviolet');
 | 
					          should(data).have.property('color', 'signalviolet');
 | 
				
			||||||
          should(data).have.property('type', 'part');
 | 
					          should(data).have.property('type', 'part');
 | 
				
			||||||
          should(data).have.property('batch', '114531');
 | 
					          should(data).have.property('batch', '114531');
 | 
				
			||||||
@@ -228,7 +228,7 @@ describe('/sample', () => {
 | 
				
			|||||||
        url: '/sample/400000000000000000000002',
 | 
					        url: '/sample/400000000000000000000002',
 | 
				
			||||||
        auth: {basic: 'janedoe'},
 | 
					        auth: {basic: 'janedoe'},
 | 
				
			||||||
        httpStatus: 200,
 | 
					        httpStatus: 200,
 | 
				
			||||||
        req: {number: '111'}
 | 
					        req: {type: 'part'}
 | 
				
			||||||
      }).end((err, res) => {
 | 
					      }).end((err, res) => {
 | 
				
			||||||
        if (err) return done (err);
 | 
					        if (err) return done (err);
 | 
				
			||||||
        NoteModel.findById(res.body.note_id).lean().exec((err, data) => {
 | 
					        NoteModel.findById(res.body.note_id).lean().exec((err, data) => {
 | 
				
			||||||
@@ -263,7 +263,7 @@ describe('/sample', () => {
 | 
				
			|||||||
        url: '/sample/400000000000000000000001',
 | 
					        url: '/sample/400000000000000000000001',
 | 
				
			||||||
        auth: {basic: 'janedoe'},
 | 
					        auth: {basic: 'janedoe'},
 | 
				
			||||||
        httpStatus: 400,
 | 
					        httpStatus: 400,
 | 
				
			||||||
        req: {number: '10', type: 'part', color: 'signalviolet', batch: '114531', material_id: '100000000000000000000001', notes: {comment: 'Testcomment', sample_references: [{id: '400000000000000000000003', relation: 'part to this sample'}]}},
 | 
					        req: {type: 'part', color: 'signalviolet', batch: '114531', material_id: '100000000000000000000001', notes: {comment: 'Testcomment', sample_references: [{id: '400000000000000000000003', relation: 'part to this sample'}]}},
 | 
				
			||||||
        res: {status: 'Color not available for material'}
 | 
					        res: {status: 'Color not available for material'}
 | 
				
			||||||
      });
 | 
					      });
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
@@ -273,18 +273,18 @@ describe('/sample', () => {
 | 
				
			|||||||
        url: '/sample/400000000000000000000001',
 | 
					        url: '/sample/400000000000000000000001',
 | 
				
			||||||
        auth: {basic: 'janedoe'},
 | 
					        auth: {basic: 'janedoe'},
 | 
				
			||||||
        httpStatus: 400,
 | 
					        httpStatus: 400,
 | 
				
			||||||
        req: {number: '10', type: 'part', color: 'signalviolet', batch: '114531', material_id: '000000000000000000000002', notes: {comment: 'Testcomment', sample_references: [{id: '400000000000000000000003', relation: 'part to this sample'}]}},
 | 
					        req: {type: 'part', color: 'signalviolet', batch: '114531', material_id: '000000000000000000000002', notes: {comment: 'Testcomment', sample_references: [{id: '400000000000000000000003', relation: 'part to this sample'}]}},
 | 
				
			||||||
        res: {status: 'Material not available'}
 | 
					        res: {status: 'Material not available'}
 | 
				
			||||||
      });
 | 
					      });
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
    it('rejects a sample number in use', done => {
 | 
					    it('rejects a sample number', done => {
 | 
				
			||||||
      TestHelper.request(server, done, {
 | 
					      TestHelper.request(server, done, {
 | 
				
			||||||
        method: 'put',
 | 
					        method: 'put',
 | 
				
			||||||
        url: '/sample/400000000000000000000001',
 | 
					        url: '/sample/400000000000000000000001',
 | 
				
			||||||
        auth: {basic: 'janedoe'},
 | 
					        auth: {basic: 'janedoe'},
 | 
				
			||||||
        httpStatus: 400,
 | 
					        httpStatus: 400,
 | 
				
			||||||
        req: {number: '21', type: 'part', color: 'signalviolet', batch: '114531', material_id: '100000000000000000000002', notes: {comment: 'Testcomment', sample_references: [{id: '400000000000000000000003', relation: 'part to this sample'}]}},
 | 
					        req: {number: 25, type: 'part', color: 'signalviolet', batch: '114531', material_id: '100000000000000000000002', notes: {comment: 'Testcomment', sample_references: [{id: '400000000000000000000003', relation: 'part to this sample'}]}},
 | 
				
			||||||
        res: {status: 'Sample number already taken'}
 | 
					        res: {status: 'Invalid body format', details: '"number" is not allowed'}
 | 
				
			||||||
      });
 | 
					      });
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
    it('rejects an invalid sample reference', done => {
 | 
					    it('rejects an invalid sample reference', done => {
 | 
				
			||||||
@@ -293,7 +293,7 @@ describe('/sample', () => {
 | 
				
			|||||||
        url: '/sample/400000000000000000000001',
 | 
					        url: '/sample/400000000000000000000001',
 | 
				
			||||||
        auth: {basic: 'janedoe'},
 | 
					        auth: {basic: 'janedoe'},
 | 
				
			||||||
        httpStatus: 400,
 | 
					        httpStatus: 400,
 | 
				
			||||||
        req: {number: '10', type: 'part', color: 'signalviolet', batch: '114531', material_id: '100000000000000000000002', notes: {comment: 'Testcomment', sample_references: [{id: '000000000000000000000003', relation: 'part to this sample'}]}},
 | 
					        req: {type: 'part', color: 'signalviolet', batch: '114531', material_id: '100000000000000000000002', notes: {comment: 'Testcomment', sample_references: [{id: '000000000000000000000003', relation: 'part to this sample'}]}},
 | 
				
			||||||
        res: {status: 'Sample reference not available'}
 | 
					        res: {status: 'Sample reference not available'}
 | 
				
			||||||
      });
 | 
					      });
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
@@ -303,7 +303,7 @@ describe('/sample', () => {
 | 
				
			|||||||
        url: '/sample/400000000000000000000001',
 | 
					        url: '/sample/400000000000000000000001',
 | 
				
			||||||
        auth: {basic: 'janedoe'},
 | 
					        auth: {basic: 'janedoe'},
 | 
				
			||||||
        httpStatus: 400,
 | 
					        httpStatus: 400,
 | 
				
			||||||
        req: {number: '10', type: 'part', color: 'signalviolet', batch: '114531', material_id: '10000000000h000000000001', notes: {comment: 'Testcomment', sample_references: [{id: '400000000000000000000003', relation: 'part to this sample'}]}},
 | 
					        req: {type: 'part', color: 'signalviolet', batch: '114531', material_id: '10000000000h000000000001', notes: {comment: 'Testcomment', sample_references: [{id: '400000000000000000000003', relation: 'part to this sample'}]}},
 | 
				
			||||||
        res: {status: 'Invalid body format', details: '"material_id" with value "10000000000h000000000001" fails to match the required pattern: /[0-9a-f]{24}/'}
 | 
					        res: {status: 'Invalid body format', details: '"material_id" with value "10000000000h000000000001" fails to match the required pattern: /[0-9a-f]{24}/'}
 | 
				
			||||||
      });
 | 
					      });
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
@@ -313,7 +313,7 @@ describe('/sample', () => {
 | 
				
			|||||||
        url: '/sample/10000000000h000000000001',
 | 
					        url: '/sample/10000000000h000000000001',
 | 
				
			||||||
        auth: {basic: 'janedoe'},
 | 
					        auth: {basic: 'janedoe'},
 | 
				
			||||||
        httpStatus: 404,
 | 
					        httpStatus: 404,
 | 
				
			||||||
        req: {number: '10', type: 'part', color: 'signalviolet', batch: '114531', material_id: '100000000000000000000002', notes: {comment: 'Testcomment', sample_references: [{id: '400000000000000000000003', relation: 'part to this sample'}]}},
 | 
					        req: {type: 'part', color: 'signalviolet', batch: '114531', material_id: '100000000000000000000002', notes: {comment: 'Testcomment', sample_references: [{id: '400000000000000000000003', relation: 'part to this sample'}]}},
 | 
				
			||||||
      });
 | 
					      });
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
    it('rejects an API key', done => {
 | 
					    it('rejects an API key', done => {
 | 
				
			||||||
@@ -322,7 +322,7 @@ describe('/sample', () => {
 | 
				
			|||||||
        url: '/sample/400000000000000000000001',
 | 
					        url: '/sample/400000000000000000000001',
 | 
				
			||||||
        auth: {key: 'janedoe'},
 | 
					        auth: {key: 'janedoe'},
 | 
				
			||||||
        httpStatus: 401,
 | 
					        httpStatus: 401,
 | 
				
			||||||
        req: {number: '10', type: 'part', color: 'signalviolet', batch: '114531', material_id: '100000000000000000000002', notes: {comment: 'Testcomment', sample_references: [{id: '400000000000000000000003', relation: 'part to this sample'}]}},
 | 
					        req: {type: 'part', color: 'signalviolet', batch: '114531', material_id: '100000000000000000000002', notes: {comment: 'Testcomment', sample_references: [{id: '400000000000000000000003', relation: 'part to this sample'}]}},
 | 
				
			||||||
      });
 | 
					      });
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
    it('rejects changes for samples from another user for a write user', done => {
 | 
					    it('rejects changes for samples from another user for a write user', done => {
 | 
				
			||||||
@@ -350,7 +350,7 @@ describe('/sample', () => {
 | 
				
			|||||||
        url: '/sample/400000000000000000000001',
 | 
					        url: '/sample/400000000000000000000001',
 | 
				
			||||||
        auth: {basic: 'user'},
 | 
					        auth: {basic: 'user'},
 | 
				
			||||||
        httpStatus: 403,
 | 
					        httpStatus: 403,
 | 
				
			||||||
        req: {number: '10', type: 'part', color: 'signalviolet', batch: '114531', material_id: '100000000000000000000002', notes: {comment: 'Testcomment', sample_references: [{id: '400000000000000000000003', relation: 'part to this sample'}]}},
 | 
					        req: {type: 'part', color: 'signalviolet', batch: '114531', material_id: '100000000000000000000002', notes: {comment: 'Testcomment', sample_references: [{id: '400000000000000000000003', relation: 'part to this sample'}]}},
 | 
				
			||||||
      });
 | 
					      });
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
    it('returns 404 for an unknown sample', done => {
 | 
					    it('returns 404 for an unknown sample', done => {
 | 
				
			||||||
@@ -359,7 +359,7 @@ describe('/sample', () => {
 | 
				
			|||||||
        url: '/sample/000000000000000000000001',
 | 
					        url: '/sample/000000000000000000000001',
 | 
				
			||||||
        auth: {basic: 'janedoe'},
 | 
					        auth: {basic: 'janedoe'},
 | 
				
			||||||
        httpStatus: 404,
 | 
					        httpStatus: 404,
 | 
				
			||||||
        req: {number: '10', type: 'part', color: 'signalviolet', batch: '114531', material_id: '100000000000000000000002', notes: {comment: 'Testcomment', sample_references: [{id: '400000000000000000000003', relation: 'part to this sample'}]}}
 | 
					        req: {type: 'part', color: 'signalviolet', batch: '114531', material_id: '100000000000000000000002', notes: {comment: 'Testcomment', sample_references: [{id: '400000000000000000000003', relation: 'part to this sample'}]}}
 | 
				
			||||||
      });
 | 
					      });
 | 
				
			||||||
    })
 | 
					    })
 | 
				
			||||||
    it('rejects unauthorized requests', done => {
 | 
					    it('rejects unauthorized requests', done => {
 | 
				
			||||||
@@ -367,7 +367,7 @@ describe('/sample', () => {
 | 
				
			|||||||
        method: 'put',
 | 
					        method: 'put',
 | 
				
			||||||
        url: '/sample/400000000000000000000001',
 | 
					        url: '/sample/400000000000000000000001',
 | 
				
			||||||
        httpStatus: 401,
 | 
					        httpStatus: 401,
 | 
				
			||||||
        req: {number: '10', type: 'part', color: 'signalviolet', batch: '114531', material_id: '100000000000000000000002', notes: {comment: 'Testcomment', sample_references: [{id: '400000000000000000000003', relation: 'part to this sample'}]}},
 | 
					        req: {type: 'part', color: 'signalviolet', batch: '114531', material_id: '100000000000000000000002', notes: {comment: 'Testcomment', sample_references: [{id: '400000000000000000000003', relation: 'part to this sample'}]}},
 | 
				
			||||||
      });
 | 
					      });
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
@@ -531,12 +531,12 @@ describe('/sample', () => {
 | 
				
			|||||||
        url: '/sample/new',
 | 
					        url: '/sample/new',
 | 
				
			||||||
        auth: {basic: 'janedoe'},
 | 
					        auth: {basic: 'janedoe'},
 | 
				
			||||||
        httpStatus: 200,
 | 
					        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'}]}}
 | 
					        req: {color: 'black', type: 'granulate', batch: '1560237365', material_id: '100000000000000000000001', notes: {comment: 'Testcomment', sample_references: [{id: '400000000000000000000003', relation: 'part to this sample'}]}}
 | 
				
			||||||
      }).end((err, res) => {
 | 
					      }).end((err, res) => {
 | 
				
			||||||
        if (err) return done (err);
 | 
					        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.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('_id').be.type('string');
 | 
				
			||||||
        should(res.body).have.property('number', 'Rng172');
 | 
					        should(res.body).have.property('number', 'Rng34');
 | 
				
			||||||
        should(res.body).have.property('color', 'black');
 | 
					        should(res.body).have.property('color', 'black');
 | 
				
			||||||
        should(res.body).have.property('type', 'granulate');
 | 
					        should(res.body).have.property('type', 'granulate');
 | 
				
			||||||
        should(res.body).have.property('batch', '1560237365');
 | 
					        should(res.body).have.property('batch', '1560237365');
 | 
				
			||||||
@@ -552,15 +552,15 @@ describe('/sample', () => {
 | 
				
			|||||||
        url: '/sample/new',
 | 
					        url: '/sample/new',
 | 
				
			||||||
        auth: {basic: 'janedoe'},
 | 
					        auth: {basic: 'janedoe'},
 | 
				
			||||||
        httpStatus: 200,
 | 
					        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'}]}}
 | 
					        req: {color: 'black', type: 'granulate', batch: '1560237365', material_id: '100000000000000000000001', notes: {comment: 'Testcomment', sample_references: [{id: '400000000000000000000003', relation: 'part to this sample'}]}}
 | 
				
			||||||
      }).end(err => {
 | 
					      }).end(err => {
 | 
				
			||||||
        if (err) return done (err);
 | 
					        if (err) return done (err);
 | 
				
			||||||
        SampleModel.find({number: 'Rng172'}).lean().exec((err, data: any) => {
 | 
					        SampleModel.find({number: 'Rng34'}).lean().exec((err, data: any) => {
 | 
				
			||||||
          if (err) return done (err);
 | 
					          if (err) return done (err);
 | 
				
			||||||
          should(data).have.lengthOf(1);
 | 
					          should(data).have.lengthOf(1);
 | 
				
			||||||
          should(data[0]).have.only.keys('_id', 'number', 'color', 'type', 'batch', 'material_id', 'note_id', 'user_id', 'status', '__v');
 | 
					          should(data[0]).have.only.keys('_id', 'number', 'color', 'type', 'batch', 'material_id', 'note_id', 'user_id', 'status', '__v');
 | 
				
			||||||
          should(data[0]).have.property('_id');
 | 
					          should(data[0]).have.property('_id');
 | 
				
			||||||
          should(data[0]).have.property('number', 'Rng172');
 | 
					          should(data[0]).have.property('number', 'Rng34');
 | 
				
			||||||
          should(data[0]).have.property('color', 'black');
 | 
					          should(data[0]).have.property('color', 'black');
 | 
				
			||||||
          should(data[0]).have.property('type', 'granulate');
 | 
					          should(data[0]).have.property('type', 'granulate');
 | 
				
			||||||
          should(data[0]).have.property('batch', '1560237365');
 | 
					          should(data[0]).have.property('batch', '1560237365');
 | 
				
			||||||
@@ -587,7 +587,7 @@ describe('/sample', () => {
 | 
				
			|||||||
        url: '/sample/new',
 | 
					        url: '/sample/new',
 | 
				
			||||||
        auth: {basic: 'janedoe'},
 | 
					        auth: {basic: 'janedoe'},
 | 
				
			||||||
        httpStatus: 200,
 | 
					        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}}}
 | 
					        req: {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) => {
 | 
					      }).end((err, res) => {
 | 
				
			||||||
        if (err) return done (err);
 | 
					        if (err) return done (err);
 | 
				
			||||||
        NoteModel.findById(res.body.note_id).lean().exec((err, data: any) => {
 | 
					        NoteModel.findById(res.body.note_id).lean().exec((err, data: any) => {
 | 
				
			||||||
@@ -618,13 +618,34 @@ describe('/sample', () => {
 | 
				
			|||||||
        });
 | 
					        });
 | 
				
			||||||
      });
 | 
					      });
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					    it('stores a new sample location as 1', done => {
 | 
				
			||||||
 | 
					      TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					        method: 'post',
 | 
				
			||||||
 | 
					        url: '/sample/new',
 | 
				
			||||||
 | 
					        auth: {basic: 'johnnydoe'},
 | 
				
			||||||
 | 
					        httpStatus: 200,
 | 
				
			||||||
 | 
					        req: {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', 'Fe1');
 | 
				
			||||||
 | 
					        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', '000000000000000000000004');
 | 
				
			||||||
 | 
					        done();
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
    it('rejects a color not defined for the material', done => {
 | 
					    it('rejects a color not defined for the material', done => {
 | 
				
			||||||
      TestHelper.request(server, done, {
 | 
					      TestHelper.request(server, done, {
 | 
				
			||||||
        method: 'post',
 | 
					        method: 'post',
 | 
				
			||||||
        url: '/sample/new',
 | 
					        url: '/sample/new',
 | 
				
			||||||
        auth: {basic: 'janedoe'},
 | 
					        auth: {basic: 'janedoe'},
 | 
				
			||||||
        httpStatus: 400,
 | 
					        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'}]}},
 | 
					        req: {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'}
 | 
					        res: {status: 'Color not available for material'}
 | 
				
			||||||
      });
 | 
					      });
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
@@ -634,18 +655,18 @@ describe('/sample', () => {
 | 
				
			|||||||
        url: '/sample/new',
 | 
					        url: '/sample/new',
 | 
				
			||||||
        auth: {basic: 'janedoe'},
 | 
					        auth: {basic: 'janedoe'},
 | 
				
			||||||
        httpStatus: 400,
 | 
					        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'}]}},
 | 
					        req: {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'}
 | 
					        res: {status: 'Material not available'}
 | 
				
			||||||
      });
 | 
					      });
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
    it('rejects a sample number in use', done => {
 | 
					    it('rejects a sample number', done => {
 | 
				
			||||||
      TestHelper.request(server, done, {
 | 
					      TestHelper.request(server, done, {
 | 
				
			||||||
        method: 'post',
 | 
					        method: 'post',
 | 
				
			||||||
        url: '/sample/new',
 | 
					        url: '/sample/new',
 | 
				
			||||||
        auth: {basic: 'janedoe'},
 | 
					        auth: {basic: 'janedoe'},
 | 
				
			||||||
        httpStatus: 400,
 | 
					        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'}]}},
 | 
					        req: {number: 'Rng34', 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'}
 | 
					        res: {status: 'Invalid body format', details: '"number" is not allowed'}
 | 
				
			||||||
      });
 | 
					      });
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
    it('rejects an invalid sample reference', done => {
 | 
					    it('rejects an invalid sample reference', done => {
 | 
				
			||||||
@@ -654,7 +675,7 @@ describe('/sample', () => {
 | 
				
			|||||||
        url: '/sample/new',
 | 
					        url: '/sample/new',
 | 
				
			||||||
        auth: {basic: 'janedoe'},
 | 
					        auth: {basic: 'janedoe'},
 | 
				
			||||||
        httpStatus: 400,
 | 
					        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'}]}},
 | 
					        req: {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'}
 | 
					        res: {status: 'Sample reference not available'}
 | 
				
			||||||
      });
 | 
					      });
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
@@ -664,27 +685,17 @@ describe('/sample', () => {
 | 
				
			|||||||
        url: '/sample/new',
 | 
					        url: '/sample/new',
 | 
				
			||||||
        auth: {basic: 'janedoe'},
 | 
					        auth: {basic: 'janedoe'},
 | 
				
			||||||
        httpStatus: 400,
 | 
					        httpStatus: 400,
 | 
				
			||||||
        req: {number: 'Rng172', type: 'granulate', batch: '1560237365', material_id: '100000000000000000000001', notes: {comment: 'Testcomment', sample_references: [{id: '400000000000000000000003', relation: 'part to this sample'}]}},
 | 
					        req: {type: 'granulate', batch: '1560237365', material_id: '100000000000000000000001', notes: {comment: 'Testcomment', sample_references: [{id: '400000000000000000000003', relation: 'part to this sample'}]}},
 | 
				
			||||||
        res: {status: 'Invalid body format', details: '"color" is required'}
 | 
					        res: {status: 'Invalid body format', details: '"color" is required'}
 | 
				
			||||||
      });
 | 
					      });
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
    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', details: '"number" is required'}
 | 
					 | 
				
			||||||
      });
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
    it('rejects a missing type', done => {
 | 
					    it('rejects a missing type', done => {
 | 
				
			||||||
      TestHelper.request(server, done, {
 | 
					      TestHelper.request(server, done, {
 | 
				
			||||||
        method: 'post',
 | 
					        method: 'post',
 | 
				
			||||||
        url: '/sample/new',
 | 
					        url: '/sample/new',
 | 
				
			||||||
        auth: {basic: 'janedoe'},
 | 
					        auth: {basic: 'janedoe'},
 | 
				
			||||||
        httpStatus: 400,
 | 
					        httpStatus: 400,
 | 
				
			||||||
        req: {number: 'Rng172', color: 'black', batch: '1560237365', material_id: '100000000000000000000001', notes: {comment: 'Testcomment', sample_references: [{id: '400000000000000000000003', relation: 'part to this sample'}]}},
 | 
					        req: {color: 'black', batch: '1560237365', material_id: '100000000000000000000001', notes: {comment: 'Testcomment', sample_references: [{id: '400000000000000000000003', relation: 'part to this sample'}]}},
 | 
				
			||||||
        res: {status: 'Invalid body format', details: '"type" is required'}
 | 
					        res: {status: 'Invalid body format', details: '"type" is required'}
 | 
				
			||||||
      });
 | 
					      });
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
@@ -694,7 +705,7 @@ describe('/sample', () => {
 | 
				
			|||||||
        url: '/sample/new',
 | 
					        url: '/sample/new',
 | 
				
			||||||
        auth: {basic: 'janedoe'},
 | 
					        auth: {basic: 'janedoe'},
 | 
				
			||||||
        httpStatus: 400,
 | 
					        httpStatus: 400,
 | 
				
			||||||
        req: {number: 'Rng172', color: 'black', type: 'granulate', material_id: '100000000000000000000001', notes: {comment: 'Testcomment', sample_references: [{id: '400000000000000000000003', relation: 'part to this sample'}]}},
 | 
					        req: {color: 'black', type: 'granulate', material_id: '100000000000000000000001', notes: {comment: 'Testcomment', sample_references: [{id: '400000000000000000000003', relation: 'part to this sample'}]}},
 | 
				
			||||||
        res: {status: 'Invalid body format', details: '"batch" is required'}
 | 
					        res: {status: 'Invalid body format', details: '"batch" is required'}
 | 
				
			||||||
      });
 | 
					      });
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
@@ -704,7 +715,7 @@ describe('/sample', () => {
 | 
				
			|||||||
        url: '/sample/new',
 | 
					        url: '/sample/new',
 | 
				
			||||||
        auth: {basic: 'janedoe'},
 | 
					        auth: {basic: 'janedoe'},
 | 
				
			||||||
        httpStatus: 400,
 | 
					        httpStatus: 400,
 | 
				
			||||||
        req: {number: 'Rng172', color: 'black', type: 'granulate', batch: '1560237365', notes: {comment: 'Testcomment', sample_references: [{id: '400000000000000000000003', relation: 'part to this sample'}]}},
 | 
					        req: {color: 'black', type: 'granulate', batch: '1560237365', notes: {comment: 'Testcomment', sample_references: [{id: '400000000000000000000003', relation: 'part to this sample'}]}},
 | 
				
			||||||
        res: {status: 'Invalid body format', details: '"material_id" is required'}
 | 
					        res: {status: 'Invalid body format', details: '"material_id" is required'}
 | 
				
			||||||
      });
 | 
					      });
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
@@ -714,7 +725,7 @@ describe('/sample', () => {
 | 
				
			|||||||
        url: '/sample/new',
 | 
					        url: '/sample/new',
 | 
				
			||||||
        auth: {basic: 'janedoe'},
 | 
					        auth: {basic: 'janedoe'},
 | 
				
			||||||
        httpStatus: 400,
 | 
					        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'}]}},
 | 
					        req: {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', details: '"material_id" with value "10000000000h000000000001" fails to match the required pattern: /[0-9a-f]{24}/'}
 | 
					        res: {status: 'Invalid body format', details: '"material_id" with value "10000000000h000000000001" fails to match the required pattern: /[0-9a-f]{24}/'}
 | 
				
			||||||
      });
 | 
					      });
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
@@ -724,7 +735,7 @@ describe('/sample', () => {
 | 
				
			|||||||
        url: '/sample/new',
 | 
					        url: '/sample/new',
 | 
				
			||||||
        auth: {key: 'janedoe'},
 | 
					        auth: {key: 'janedoe'},
 | 
				
			||||||
        httpStatus: 401,
 | 
					        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'}]}}
 | 
					        req: {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 => {
 | 
					    it('rejects requests from a read user', done => {
 | 
				
			||||||
@@ -733,7 +744,7 @@ describe('/sample', () => {
 | 
				
			|||||||
        url: '/sample/new',
 | 
					        url: '/sample/new',
 | 
				
			||||||
        auth: {basic: 'user'},
 | 
					        auth: {basic: 'user'},
 | 
				
			||||||
        httpStatus: 403,
 | 
					        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'}]}}
 | 
					        req: {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 => {
 | 
					    it('rejects unauthorized requests', done => {
 | 
				
			||||||
@@ -741,7 +752,7 @@ describe('/sample', () => {
 | 
				
			|||||||
        method: 'post',
 | 
					        method: 'post',
 | 
				
			||||||
        url: '/sample/new',
 | 
					        url: '/sample/new',
 | 
				
			||||||
        httpStatus: 401,
 | 
					        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'}]}}
 | 
					        req: {color: 'black', type: 'granulate', batch: '1560237365', material_id: '100000000000000000000001', notes: {comment: 'Testcomment', sample_references: [{id: '400000000000000000000003', relation: 'part to this sample'}]}}
 | 
				
			||||||
      });
 | 
					      });
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -36,9 +36,6 @@ router.put('/sample/' + IdValidate.parameter(), (req, res, next) => {
 | 
				
			|||||||
    // only maintain and admin are allowed to edit other user's data
 | 
					    // only maintain and admin are allowed to edit other user's data
 | 
				
			||||||
    if (sampleData.user_id.toString() !== req.authDetails.id && !req.auth(res, ['maintain', 'admin'], 'basic')) return;
 | 
					    if (sampleData.user_id.toString() !== req.authDetails.id && !req.auth(res, ['maintain', 'admin'], 'basic')) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (sample.hasOwnProperty('number') && sample.number !== sampleData.number) {
 | 
					 | 
				
			||||||
      if (!await numberCheck(sample, res, next)) return;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    if (sample.hasOwnProperty('material_id')) {
 | 
					    if (sample.hasOwnProperty('material_id')) {
 | 
				
			||||||
      if (!await materialCheck(sample, res, next)) return;
 | 
					      if (!await materialCheck(sample, res, next)) return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -120,7 +117,6 @@ router.post('/sample/new', async (req, res, next) => {
 | 
				
			|||||||
  const {error, value: sample} = SampleValidate.input(req.body, 'new');
 | 
					  const {error, value: sample} = SampleValidate.input(req.body, 'new');
 | 
				
			||||||
  if (error) return res400(error, res);
 | 
					  if (error) return res400(error, res);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (!await numberCheck(sample, res, next)) return;
 | 
					 | 
				
			||||||
  if (!await materialCheck(sample, res, next)) return;
 | 
					  if (!await materialCheck(sample, res, next)) return;
 | 
				
			||||||
  if (!await sampleRefCheck(sample, res, next)) return;
 | 
					  if (!await sampleRefCheck(sample, res, next)) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -129,6 +125,8 @@ router.post('/sample/new', async (req, res, next) => {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  sample.status = 0;
 | 
					  sample.status = 0;
 | 
				
			||||||
 | 
					  sample.number = await numberGenerate(sample, req, res, next);
 | 
				
			||||||
 | 
					  if (!sample.number) return;
 | 
				
			||||||
  new NoteModel(sample.notes).save((err, data) => {
 | 
					  new NoteModel(sample.notes).save((err, data) => {
 | 
				
			||||||
    if (err) return next(err);
 | 
					    if (err) return next(err);
 | 
				
			||||||
    delete sample.notes;
 | 
					    delete sample.notes;
 | 
				
			||||||
@@ -155,17 +153,18 @@ router.get('/sample/notes/fields', (req, res, next) => {
 | 
				
			|||||||
module.exports = router;
 | 
					module.exports = router;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
async function numberCheck (sample, res, next) {  // validate number, returns false if invalid
 | 
					async function numberGenerate (sample, req, res, next) {  // validate number, returns false if invalid
 | 
				
			||||||
  const sampleData = await SampleModel.findOne({number: sample.number}).lean().exec().catch(err => {next(err); return false;});
 | 
					  const sampleData = await SampleModel
 | 
				
			||||||
  if (sampleData) {  // found entry with sample number
 | 
					    .find({number: new RegExp('^' + req.authDetails.location + '[0-9]+$', 'm')})
 | 
				
			||||||
    res.status(400).json({status: 'Sample number already taken'});
 | 
					    .lean()
 | 
				
			||||||
    return false
 | 
					    .exec()
 | 
				
			||||||
  }
 | 
					    .catch(err => next(err));
 | 
				
			||||||
  return true;
 | 
					  if (sampleData instanceof Error) return false;
 | 
				
			||||||
 | 
					  return req.authDetails.location + (sampleData.length > 0 ? Number(sampleData[0].number.replace(/[^0-9]+/g, '')) + 1 : 1);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
async function materialCheck (sample, res, next, id = sample.material_id) {  // validate material_id and color, returns false if invalid
 | 
					async function materialCheck (sample, res, next, id = sample.material_id) {  // validate material_id and color, returns false if invalid
 | 
				
			||||||
  const materialData = await MaterialModel.findById(id).lean().exec().catch(err => {next(err); return false;}) as any;
 | 
					  const materialData = await MaterialModel.findById(id).lean().exec().catch(err => next(err)) as any;
 | 
				
			||||||
  if (materialData instanceof Error) return false;
 | 
					  if (materialData instanceof Error) return false;
 | 
				
			||||||
  if (!materialData) {  // could not find material_id
 | 
					  if (!materialData) {  // could not find material_id
 | 
				
			||||||
    res.status(400).json({status: 'Material not available'});
 | 
					    res.status(400).json({status: 'Material not available'});
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -44,7 +44,6 @@ export default class SampleValidate {
 | 
				
			|||||||
  static input (data, param) {  // validate data, param: new(everything required)/change(available attributes are validated)
 | 
					  static input (data, param) {  // validate data, param: new(everything required)/change(available attributes are validated)
 | 
				
			||||||
    if (param === 'new') {
 | 
					    if (param === 'new') {
 | 
				
			||||||
      return Joi.object({
 | 
					      return Joi.object({
 | 
				
			||||||
        number: this.sample.number.required(),
 | 
					 | 
				
			||||||
        color: this.sample.color.required(),
 | 
					        color: this.sample.color.required(),
 | 
				
			||||||
        type: this.sample.type.required(),
 | 
					        type: this.sample.type.required(),
 | 
				
			||||||
        batch: this.sample.batch.required(),
 | 
					        batch: this.sample.batch.required(),
 | 
				
			||||||
@@ -54,7 +53,6 @@ export default class SampleValidate {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
    else if (param === 'change') {
 | 
					    else if (param === 'change') {
 | 
				
			||||||
      return Joi.object({
 | 
					      return Joi.object({
 | 
				
			||||||
        number: this.sample.number,
 | 
					 | 
				
			||||||
        color: this.sample.color,
 | 
					        color: this.sample.color,
 | 
				
			||||||
        type: this.sample.type,
 | 
					        type: this.sample.type,
 | 
				
			||||||
        batch: this.sample.batch,
 | 
					        batch: this.sample.batch,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -51,7 +51,7 @@
 | 
				
			|||||||
      },
 | 
					      },
 | 
				
			||||||
      {
 | 
					      {
 | 
				
			||||||
        "_id": {"$oid":"400000000000000000000005"},
 | 
					        "_id": {"$oid":"400000000000000000000005"},
 | 
				
			||||||
        "number": "33",
 | 
					        "number": "Rng33",
 | 
				
			||||||
        "type": "granulate",
 | 
					        "type": "granulate",
 | 
				
			||||||
        "color": "black",
 | 
					        "color": "black",
 | 
				
			||||||
        "batch": "1653000308",
 | 
					        "batch": "1653000308",
 | 
				
			||||||
@@ -250,7 +250,7 @@
 | 
				
			|||||||
      {
 | 
					      {
 | 
				
			||||||
        "_id": {"$oid":"700000000000000000000002"},
 | 
					        "_id": {"$oid":"700000000000000000000002"},
 | 
				
			||||||
        "sample_id": {"$oid":"400000000000000000000002"},
 | 
					        "sample_id": {"$oid":"400000000000000000000002"},
 | 
				
			||||||
        "number": "A3",
 | 
					        "number": "A1",
 | 
				
			||||||
        "parameters": {
 | 
					        "parameters": {
 | 
				
			||||||
          "material": "copper",
 | 
					          "material": "copper",
 | 
				
			||||||
          "weeks": 3
 | 
					          "weeks": 3
 | 
				
			||||||
@@ -262,7 +262,7 @@
 | 
				
			|||||||
      {
 | 
					      {
 | 
				
			||||||
        "_id": {"$oid":"700000000000000000000003"},
 | 
					        "_id": {"$oid":"700000000000000000000003"},
 | 
				
			||||||
        "sample_id": {"$oid":"400000000000000000000004"},
 | 
					        "sample_id": {"$oid":"400000000000000000000004"},
 | 
				
			||||||
        "number": "A4",
 | 
					        "number": "A1",
 | 
				
			||||||
        "parameters": {
 | 
					        "parameters": {
 | 
				
			||||||
          "material": "copper",
 | 
					          "material": "copper",
 | 
				
			||||||
          "weeks": 3
 | 
					          "weeks": 3
 | 
				
			||||||
@@ -274,7 +274,7 @@
 | 
				
			|||||||
      {
 | 
					      {
 | 
				
			||||||
        "_id": {"$oid":"700000000000000000000004"},
 | 
					        "_id": {"$oid":"700000000000000000000004"},
 | 
				
			||||||
        "sample_id": {"$oid":"400000000000000000000001"},
 | 
					        "sample_id": {"$oid":"400000000000000000000001"},
 | 
				
			||||||
        "number": "A6",
 | 
					        "number": "A2",
 | 
				
			||||||
        "parameters": {
 | 
					        "parameters": {
 | 
				
			||||||
          "material": "hot air",
 | 
					          "material": "hot air",
 | 
				
			||||||
          "weeks": 5
 | 
					          "weeks": 5
 | 
				
			||||||
@@ -446,6 +446,17 @@
 | 
				
			|||||||
        "device_name": "",
 | 
					        "device_name": "",
 | 
				
			||||||
        "key": "000000000000000000001003",
 | 
					        "key": "000000000000000000001003",
 | 
				
			||||||
        "__v": "0"
 | 
					        "__v": "0"
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        "_id": {"$oid":"000000000000000000000004"},
 | 
				
			||||||
 | 
					        "email": "johnny.doe@bosch.com",
 | 
				
			||||||
 | 
					        "name": "johnnydoe",
 | 
				
			||||||
 | 
					        "pass": "$2a$10$di26XKF63OG0V00PL1kSK.ceCcTxDExBMOg.jkHiCnXcY7cN7DlPi",
 | 
				
			||||||
 | 
					        "level": "write",
 | 
				
			||||||
 | 
					        "location": "Fe",
 | 
				
			||||||
 | 
					        "device_name": "Alpha I",
 | 
				
			||||||
 | 
					        "key": "000000000000000000001004",
 | 
				
			||||||
 | 
					        "__v": 0
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    ]
 | 
					    ]
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,7 +7,8 @@ export default class TestHelper {
 | 
				
			|||||||
  public static auth = {
 | 
					  public static auth = {
 | 
				
			||||||
    admin: {pass: 'Abc123!#', key: '000000000000000000001003'},
 | 
					    admin: {pass: 'Abc123!#', key: '000000000000000000001003'},
 | 
				
			||||||
    janedoe: {pass: 'Xyz890*)', key: '000000000000000000001002'},
 | 
					    janedoe: {pass: 'Xyz890*)', key: '000000000000000000001002'},
 | 
				
			||||||
    user: {pass: 'Xyz890*)', key: '000000000000000000001001'}
 | 
					    user: {pass: 'Xyz890*)', key: '000000000000000000001001'},
 | 
				
			||||||
 | 
					    johnnydoe: {pass: 'Xyz890*)', key: '000000000000000000001004'}
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  public static res = {
 | 
					  public static res = {
 | 
				
			||||||
    400: {status: 'Bad request'},
 | 
					    400: {status: 'Bad request'},
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user