model routes
This commit is contained in:
		@@ -111,9 +111,10 @@ if (process.env.NODE_ENV !== 'production') {
 | 
			
		||||
app.use('/', require('./routes/root'));
 | 
			
		||||
app.use('/', require('./routes/sample'));
 | 
			
		||||
app.use('/', require('./routes/material'));
 | 
			
		||||
app.use('/', require('./routes/template'));
 | 
			
		||||
app.use('/', require('./routes/user'));
 | 
			
		||||
app.use('/', require('./routes/measurement'));
 | 
			
		||||
app.use('/', require('./routes/template'));
 | 
			
		||||
app.use('/', require('./routes/model'));
 | 
			
		||||
app.use('/', require('./routes/user'));
 | 
			
		||||
 | 
			
		||||
// static files
 | 
			
		||||
app.use('/static', express.static('static'));
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										8
									
								
								src/models/model.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								src/models/model.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,8 @@
 | 
			
		||||
import mongoose from 'mongoose';
 | 
			
		||||
 | 
			
		||||
const ModelSchema = new mongoose.Schema({
 | 
			
		||||
  name: {type: String, index: {unique: true}},
 | 
			
		||||
  data: Buffer
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
export default mongoose.model<any, mongoose.Model<any, any>>('model', ModelSchema);
 | 
			
		||||
							
								
								
									
										197
									
								
								src/routes/model.spec.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										197
									
								
								src/routes/model.spec.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,197 @@
 | 
			
		||||
import should from 'should/as-function';
 | 
			
		||||
import ModelModel from '../models/model';
 | 
			
		||||
import TestHelper from "../test/helper";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
describe('/model', () => {
 | 
			
		||||
  let server;
 | 
			
		||||
  before(done => TestHelper.before(done));
 | 
			
		||||
  beforeEach(done => server = TestHelper.beforeEach(server, done));
 | 
			
		||||
  afterEach(done => TestHelper.afterEach(server, done));
 | 
			
		||||
  after(done => TestHelper.after(done));
 | 
			
		||||
 | 
			
		||||
  describe('GET /model/{name}', (() => {
 | 
			
		||||
    it('returns the binary data', done => {
 | 
			
		||||
      TestHelper.request(server, done, {
 | 
			
		||||
        method: 'get',
 | 
			
		||||
        url: '/model/modela',
 | 
			
		||||
        auth: {basic: 'admin'},
 | 
			
		||||
        httpStatus: 200,
 | 
			
		||||
        contentType: 'application/octet-stream; charset=utf-8',
 | 
			
		||||
      }).end((err, res) => {
 | 
			
		||||
        if (err) return done (err);
 | 
			
		||||
        should(res.body.toString()).be.eql('binary data');
 | 
			
		||||
        done();
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
    it('returns the binary data for an API key', done => {
 | 
			
		||||
      TestHelper.request(server, done, {
 | 
			
		||||
        method: 'get',
 | 
			
		||||
        url: '/model/modela',
 | 
			
		||||
        auth: {key: 'admin'},
 | 
			
		||||
        httpStatus: 200,
 | 
			
		||||
        contentType: 'application/octet-stream; charset=utf-8',
 | 
			
		||||
      }).end((err, res) => {
 | 
			
		||||
        if (err) return done (err);
 | 
			
		||||
        should(res.body.toString()).be.eql('binary data');
 | 
			
		||||
        done();
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
    it('returns 404 for an unknown name', done => {
 | 
			
		||||
      TestHelper.request(server, done, {
 | 
			
		||||
        method: 'get',
 | 
			
		||||
        url: '/model/modelx',
 | 
			
		||||
        auth: {basic: 'admin'},
 | 
			
		||||
        httpStatus: 404
 | 
			
		||||
      })
 | 
			
		||||
    });
 | 
			
		||||
    it('rejects requests from a write user', done => {
 | 
			
		||||
      TestHelper.request(server, done, {
 | 
			
		||||
        method: 'get',
 | 
			
		||||
        url: '/model/modela',
 | 
			
		||||
        auth: {basic: 'janedoe'},
 | 
			
		||||
        httpStatus: 403
 | 
			
		||||
      })
 | 
			
		||||
    });
 | 
			
		||||
    it('rejects unauthorized requests', done => {
 | 
			
		||||
      TestHelper.request(server, done, {
 | 
			
		||||
        method: 'get',
 | 
			
		||||
        url: '/model/modela',
 | 
			
		||||
        httpStatus: 401
 | 
			
		||||
      })
 | 
			
		||||
    });
 | 
			
		||||
  }));
 | 
			
		||||
 | 
			
		||||
  describe('POST /model/{name}', () => {
 | 
			
		||||
    it('stores the data', done => {
 | 
			
		||||
      TestHelper.request(server, done, {
 | 
			
		||||
        method: 'post',
 | 
			
		||||
        url: '/model/modelb',
 | 
			
		||||
        auth: {basic: 'admin'},
 | 
			
		||||
        httpStatus: 200,
 | 
			
		||||
        reqContentType: 'application/octet-stream',
 | 
			
		||||
        req: 'another binary data'
 | 
			
		||||
      }).end((err, res) => {
 | 
			
		||||
        if (err) return done (err);
 | 
			
		||||
        should(res.body).be.eql({status: 'OK'});
 | 
			
		||||
        ModelModel.find({name: 'modelb'}).lean().exec((err, data) => {
 | 
			
		||||
          if (err) return done (err);
 | 
			
		||||
          should(data).have.lengthOf(1);
 | 
			
		||||
          should(data[0]).have.only.keys('_id', 'name', 'data', '__v');
 | 
			
		||||
          should(data[0]).have.property('name', 'modelb');
 | 
			
		||||
          should(data[0].data.buffer.toString()).be.eql('another binary data');
 | 
			
		||||
          done();
 | 
			
		||||
        });
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
    it('stores the data with an API key', done => {
 | 
			
		||||
      TestHelper.request(server, done, {
 | 
			
		||||
        method: 'post',
 | 
			
		||||
        url: '/model/modelb',
 | 
			
		||||
        auth: {key: 'admin'},
 | 
			
		||||
        httpStatus: 200,
 | 
			
		||||
        reqContentType: 'application/octet-stream',
 | 
			
		||||
        req: 'another binary data'
 | 
			
		||||
      }).end((err, res) => {
 | 
			
		||||
        if (err) return done (err);
 | 
			
		||||
        should(res.body).be.eql({status: 'OK'});
 | 
			
		||||
        ModelModel.find({name: 'modelb'}).lean().exec((err, data) => {
 | 
			
		||||
          if (err) return done (err);
 | 
			
		||||
          should(data).have.lengthOf(1);
 | 
			
		||||
          should(data[0]).have.only.keys('_id', 'name', 'data', '__v');
 | 
			
		||||
          should(data[0]).have.property('name', 'modelb');
 | 
			
		||||
          should(data[0].data.buffer.toString()).be.eql('another binary data');
 | 
			
		||||
          done();
 | 
			
		||||
        });
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
    it('overwrites existing data', done => {
 | 
			
		||||
      TestHelper.request(server, done, {
 | 
			
		||||
        method: 'post',
 | 
			
		||||
        url: '/model/modela',
 | 
			
		||||
        auth: {basic: 'admin'},
 | 
			
		||||
        httpStatus: 200,
 | 
			
		||||
        reqContentType: 'application/octet-stream',
 | 
			
		||||
        req: 'another binary data'
 | 
			
		||||
      }).end((err, res) => {
 | 
			
		||||
        if (err) return done (err);
 | 
			
		||||
        should(res.body).be.eql({status: 'OK'});
 | 
			
		||||
        ModelModel.find({name: 'modela'}).lean().exec((err, data) => {
 | 
			
		||||
          if (err) return done (err);
 | 
			
		||||
          should(data).have.lengthOf(1);
 | 
			
		||||
          should(data[0]).have.only.keys('_id', 'name', 'data', '__v');
 | 
			
		||||
          should(data[0]).have.property('name', 'modela');
 | 
			
		||||
          should(data[0].data.buffer.toString()).be.eql('another binary data');
 | 
			
		||||
          done();
 | 
			
		||||
        });
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
    it('rejects requests from a write user', done => {
 | 
			
		||||
      TestHelper.request(server, done, {
 | 
			
		||||
        method: 'post',
 | 
			
		||||
        url: '/model/modelb',
 | 
			
		||||
        auth: {basic: 'janedoe'},
 | 
			
		||||
        httpStatus: 403,
 | 
			
		||||
        req: 'another binary data'
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
    it('rejects unauthorized requests', done => {
 | 
			
		||||
      TestHelper.request(server, done, {
 | 
			
		||||
        method: 'post',
 | 
			
		||||
        url: '/model/modelb',
 | 
			
		||||
        httpStatus: 401,
 | 
			
		||||
        req: 'another binary data'
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  describe('DELETE /model/{name}', () => {
 | 
			
		||||
    it('deletes the data', done => {
 | 
			
		||||
      TestHelper.request(server, done, {
 | 
			
		||||
        method: 'delete',
 | 
			
		||||
        url: '/model/modela',
 | 
			
		||||
        auth: {basic: 'admin'},
 | 
			
		||||
        httpStatus: 200
 | 
			
		||||
      }).end((err, res) => {
 | 
			
		||||
        if (err) return done(err);
 | 
			
		||||
        should(res.body).be.eql({status: 'OK'});
 | 
			
		||||
        ModelModel.find({name: 'modela'}).lean().exec((err, data) => {
 | 
			
		||||
          if (err) return done(err);
 | 
			
		||||
          should(data).have.lengthOf(0);
 | 
			
		||||
          done();
 | 
			
		||||
        });
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
    it('returns 404 for an unknown name', done => {
 | 
			
		||||
      TestHelper.request(server, done, {
 | 
			
		||||
        method: 'delete',
 | 
			
		||||
        url: '/model/modelx',
 | 
			
		||||
        auth: {basic: 'admin'},
 | 
			
		||||
        httpStatus: 404
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
    it('rejects an API key', done => {
 | 
			
		||||
      TestHelper.request(server, done, {
 | 
			
		||||
        method: 'delete',
 | 
			
		||||
        url: '/model/modela',
 | 
			
		||||
        auth: {key: 'admin'},
 | 
			
		||||
        httpStatus: 401
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
    it('rejects a write user', done => {
 | 
			
		||||
      TestHelper.request(server, done, {
 | 
			
		||||
        method: 'delete',
 | 
			
		||||
        url: '/model/modela',
 | 
			
		||||
        auth: {basic: 'janedoe'},
 | 
			
		||||
        httpStatus: 403
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
    it('rejects an unauthorized request', done => {
 | 
			
		||||
      TestHelper.request(server, done, {
 | 
			
		||||
        method: 'delete',
 | 
			
		||||
        url: '/model/modela',
 | 
			
		||||
        httpStatus: 401
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
});
 | 
			
		||||
							
								
								
									
										47
									
								
								src/routes/model.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								src/routes/model.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,47 @@
 | 
			
		||||
import express from 'express';
 | 
			
		||||
import bodyParser from 'body-parser';
 | 
			
		||||
 | 
			
		||||
import ModelModel from '../models/model';
 | 
			
		||||
 | 
			
		||||
const router = express.Router();
 | 
			
		||||
 | 
			
		||||
router.get('/model/:name', (req, res, next) => {
 | 
			
		||||
  if (!req.auth(res, ['dev', 'admin'], 'all')) return;
 | 
			
		||||
 | 
			
		||||
  ModelModel.findOne({name: req.params.name}).lean().exec((err, data) => {
 | 
			
		||||
    if (err) return next(err);
 | 
			
		||||
    if (data) {
 | 
			
		||||
      res.set('Content-Type', 'application/octet-stream');
 | 
			
		||||
      res.send(data.data.buffer);
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
      res.status(404).json({status: 'Not found'});
 | 
			
		||||
    }
 | 
			
		||||
  });
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
router.post('/model/:name', bodyParser.raw({limit: '500kb'}), (req, res, next) => {
 | 
			
		||||
  if (!req.auth(res, ['dev', 'admin'], 'all')) return;
 | 
			
		||||
 | 
			
		||||
  ModelModel.replaceOne({name: req.params.name}, {name: req.params.name, data: req.body}).setOptions({upsert: true})
 | 
			
		||||
    .lean().exec(err => {
 | 
			
		||||
    if (err) return next(err);
 | 
			
		||||
    res.json({status: 'OK'});
 | 
			
		||||
  });
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
router.delete('/model/:name', (req, res, next) => {
 | 
			
		||||
  if (!req.auth(res, ['dev', 'admin'], 'basic')) return;
 | 
			
		||||
 | 
			
		||||
  ModelModel.findOneAndDelete({name: req.params.name}).lean().exec((err, data) => {
 | 
			
		||||
    if (err) return next(err);
 | 
			
		||||
    if (data) {
 | 
			
		||||
      res.json({status: 'OK'});
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
      res.status(404).json({status: 'Not found'});
 | 
			
		||||
    }
 | 
			
		||||
  });
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
module.exports = router;
 | 
			
		||||
@@ -678,6 +678,13 @@
 | 
			
		||||
        "__v": 0
 | 
			
		||||
      }
 | 
			
		||||
    ],
 | 
			
		||||
    "models": [
 | 
			
		||||
      {
 | 
			
		||||
        "_id": {"$oid":"140000000000000000000001"},
 | 
			
		||||
        "name": "modela",
 | 
			
		||||
        "data": {"buffer": "binary data"}
 | 
			
		||||
      }
 | 
			
		||||
    ],
 | 
			
		||||
    "users": [
 | 
			
		||||
      {
 | 
			
		||||
        "_id": {"$oid":"000000000000000000000001"},
 | 
			
		||||
 
 | 
			
		||||
@@ -69,6 +69,9 @@ export default class TestHelper {
 | 
			
		||||
    if (options.hasOwnProperty('req')) {  // request body
 | 
			
		||||
      st = st.send(options.req);
 | 
			
		||||
    }
 | 
			
		||||
    if (options.hasOwnProperty('reqContentType')) {  // request body
 | 
			
		||||
      st = st.set('Content-Type', options.reqContentType);
 | 
			
		||||
    }
 | 
			
		||||
    if (options.hasOwnProperty('auth') && options.auth.hasOwnProperty('basic')) {  // resolve basic auth
 | 
			
		||||
      if (this.auth.hasOwnProperty(options.auth.basic)) {
 | 
			
		||||
        st = st.auth(options.auth.basic, this.auth[options.auth.basic].pass)
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user