From 349ff16191372d47e625ffdaa3edf214038bcb29 Mon Sep 17 00:00:00 2001 From: VLE2FE Date: Fri, 28 Aug 2020 08:13:19 +0200 Subject: [PATCH 1/2] updated to new model format --- src/routes/model.spec.ts | 52 ++++++++++-------------------------- src/routes/model.ts | 1 - src/routes/validate/model.ts | 5 ---- src/test/db.json | 9 +++---- 4 files changed, 17 insertions(+), 50 deletions(-) diff --git a/src/routes/model.spec.ts b/src/routes/model.spec.ts index dc75f5e..50cb88c 100644 --- a/src/routes/model.spec.ts +++ b/src/routes/model.spec.ts @@ -26,11 +26,10 @@ describe('/model', () => { should(group).have.only.keys('group', 'models'); should(group).have.property('group').be.type('string'); should(group.models).matchEach(model => { - should(model).have.only.keys('_id', 'name', 'url', 'label'); + should(model).have.only.keys('_id', 'name', 'url'); should(model).have.property('_id').be.type('string'); should(model).have.property('name').be.type('string'); should(model).have.property('url').be.type('string'); - should(model).have.property('label').be.type('string'); }); }); done(); @@ -48,7 +47,7 @@ describe('/model', () => { should(res.body).matchEach(group => { should(group).have.only.keys('group', 'models'); should(group).have.property('group').be.type('string'); - should(group).have.property('models', [{_id: '120000000000000000000001', name: 'Model A', url: 'http://model-a.com', label: 'ml/g'}]); + should(group).have.property('models', [{_id: '120000000000000000000001', name: 'Model A', url: 'http://model-a.com'}]); }); done(); }); @@ -77,7 +76,7 @@ describe('/model', () => { url: '/model/VN', auth: {basic: 'admin'}, httpStatus: 200, - req: {name: 'Model C', url: 'http://model-c.com', label: 'ml/g'} + req: {name: 'Model C', url: 'http://model-c.com'} }).end((err, res) => { if (err) return done(err); should(res.body).be.eql({status: 'OK'}); @@ -85,7 +84,6 @@ describe('/model', () => { if (err) return done(err); const model = res.models.find(e => e.name === 'Model C'); should(model).have.property('url', 'http://model-c.com'); - should(model).have.property('label', 'ml/g'); done(); }); }); @@ -96,7 +94,7 @@ describe('/model', () => { url: '/model/classification', auth: {basic: 'admin'}, httpStatus: 200, - req: {name: 'Model 0.1', url: 'http://model-0-1.com', label: 'group'} + req: {name: 'Model 0.1', url: 'http://model-0-1.com'} }).end((err, res) => { if (err) return done(err); should(res.body).be.eql({status: 'OK'}); @@ -104,10 +102,9 @@ describe('/model', () => { if (err) return done(err); should(res).have.only.keys('_id', 'group', 'models', '__v'); should(res).have.property('group', 'classification'); - should(res.models[0]).have.only.keys('_id', 'name', 'url', 'label'); + should(res.models[0]).have.only.keys('_id', 'name', 'url'); should(res.models[0]).have.property('name', 'Model 0.1'); should(res.models[0]).have.property('url', 'http://model-0-1.com'); - should(res.models[0]).have.property('label', 'group'); done(); }); }); @@ -118,7 +115,7 @@ describe('/model', () => { url: '/model/VN', auth: {basic: 'admin'}, httpStatus: 200, - req: {name: 'Model A', url: 'http://model-a-new.com', label: 'ml/cm3'} + req: {name: 'Model A', url: 'http://model-a-new.com'} }).end((err, res) => { if (err) return done(err); should(res.body).be.eql({status: 'OK'}); @@ -126,26 +123,6 @@ describe('/model', () => { if (err) return done(err); const model = res.models.find(e => e.name === 'Model A'); should(model).have.property('url', 'http://model-a-new.com'); - should(model).have.property('label', 'ml/cm3'); - done(); - }); - }); - }); - it('accepts an empty label', done => { - TestHelper.request(server, done, { - method: 'post', - url: '/model/VN', - auth: {basic: 'admin'}, - httpStatus: 200, - req: {name: 'Model C', url: 'http://model-c.com', label: ''} - }).end((err, res) => { - if (err) return done(err); - should(res.body).be.eql({status: 'OK'}); - ModelModel.findOne({group: 'VN'}).lean().exec((err, res) => { - if (err) return done(err); - const model = res.models.find(e => e.name === 'Model C'); - should(model).have.property('url', 'http://model-c.com'); - should(model).have.property('label', ''); done(); }); }); @@ -156,7 +133,7 @@ describe('/model', () => { url: '/model/VN', auth: {basic: 'admin'}, httpStatus: 400, - req: {name: '', url: 'http://model-c.com', label: 'ml/g'}, + req: {name: '', url: 'http://model-c.com'}, res:{status: 'Invalid body format', details: '"name" is not allowed to be empty'} }); }); @@ -166,7 +143,7 @@ describe('/model', () => { url: '/model/VN', auth: {basic: 'admin'}, httpStatus: 400, - req: {url: 'http://model-c.com', label: 'ml/g'}, + req: {url: 'http://model-c.com'}, res:{status: 'Invalid body format', details: '"name" is required'} }); }); @@ -176,7 +153,7 @@ describe('/model', () => { url: '/model/VN', auth: {basic: 'admin'}, httpStatus: 400, - req: {name: 'Model C', url: 'model-c', label: 'ml/g'}, + req: {name: 'Model C', url: 'model-c'}, res:{status: 'Invalid body format', details: '"url" must be a valid uri'} }); }); @@ -186,7 +163,7 @@ describe('/model', () => { url: '/model/VN', auth: {basic: 'admin'}, httpStatus: 400, - req: {name: 'Model C', label: 'ml/g'}, + req: {name: 'Model C'}, res:{status: 'Invalid body format', details: '"url" is required'} }); }); @@ -196,7 +173,7 @@ describe('/model', () => { url: '/model/VN', auth: {basic: 'janedoe'}, httpStatus: 403, - req: {name: 'Model C', url: 'http://model-c.com', label: 'ml/g'} + req: {name: 'Model C', url: 'http://model-c.com'} }); }); it('rejects an API key', done => { @@ -205,7 +182,7 @@ describe('/model', () => { url: '/model/VN', auth: {key: 'admin'}, httpStatus: 401, - req: {name: 'Model C', url: 'http://model-c.com', label: 'ml/g'} + req: {name: 'Model C', url: 'http://model-c.com'} }); }); it('rejects an unauthorized request', done => { @@ -213,7 +190,7 @@ describe('/model', () => { method: 'post', url: '/model/VN', httpStatus: 401, - req: {name: 'Model C', url: 'http://model-c.com', label: 'ml/g'} + req: {name: 'Model C', url: 'http://model-c.com'} }); }); }); @@ -232,10 +209,9 @@ describe('/model', () => { if (err) return done(err); should(res).have.only.keys('_id', 'group', 'models'); should(res).have.property('group', 'VN'); - should(res.models[0]).have.only.keys('_id', 'name', 'url', 'label'); + should(res.models[0]).have.only.keys('_id', 'name', 'url'); should(res.models[0]).have.property('name', 'Model B'); should(res.models[0]).have.property('url', 'http://model-b.com'); - should(res.models[0]).have.property('label', 'ml/g'); done(); }); }); diff --git a/src/routes/model.ts b/src/routes/model.ts index 196d877..cfa757e 100644 --- a/src/routes/model.ts +++ b/src/routes/model.ts @@ -33,7 +33,6 @@ router.post('/model/:group', (req, res, next) => { if (!req.auth(res, ['dev', 'admin'], 'basic')) return; const {error, value: model} = ModelValidate.input(req.body); - console.log(error); if (error) return res400(error, res); ModelModel.findOne({group: req.params.group}).lean().exec((err, data) => { diff --git a/src/routes/validate/model.ts b/src/routes/validate/model.ts index 1a3fb2b..d473872 100644 --- a/src/routes/validate/model.ts +++ b/src/routes/validate/model.ts @@ -16,11 +16,6 @@ export default class ModelValidate { // validate input for model url: Joi.string() .uri() .max(512) - .required(), - - label: Joi.string() - .allow('') - .max(128) .required() }) }; diff --git a/src/test/db.json b/src/test/db.json index 9cd244f..f6118d2 100644 --- a/src/test/db.json +++ b/src/test/db.json @@ -736,14 +736,12 @@ { "_id": {"$oid":"120000000000000000000001"}, "name": "Model A", - "url": "http://model-a.com", - "label": "ml/g" + "url": "http://model-a.com" }, { "_id": {"$oid":"120000000000000000000002"}, "name": "Model B", - "url": "http://model-b.com", - "label": "ml/g" + "url": "http://model-b.com" } ] }, @@ -753,8 +751,7 @@ { "_id": {"$oid":"120000000000000000000003"}, "name": "Model 1", - "url": "http://model-1.com", - "label": "weight %" + "url": "http://model-1.com" } ] } From c891933d11976a6efd2a6593168d58f1933b519e Mon Sep 17 00:00:00 2001 From: VLE2FE Date: Fri, 28 Aug 2020 09:04:05 +0200 Subject: [PATCH 2/2] implemented /model/files --- api/model.yaml | 26 ++++++++++++++++++++++++++ src/routes/model.spec.ts | 26 ++++++++++++++++++++++++++ src/routes/model.ts | 9 +++++++++ src/routes/validate/model.ts | 7 +++++++ 4 files changed, 68 insertions(+) diff --git a/api/model.yaml b/api/model.yaml index 0f45f2b..f3999da 100644 --- a/api/model.yaml +++ b/api/model.yaml @@ -73,6 +73,32 @@ 500: $ref: 'api.yaml#/components/responses/500' +/model/files: + get: + summary: list all stored models + description: 'Auth: basic, levels: dev, admin' + tags: + - /model + responses: + 200: + description: model details list + content: + application/json: + schema: + properties: + name: + type: string + example: model_VN_A3WG6_V1 + size: + type: number + example: 4177449 + 401: + $ref: 'api.yaml#/components/responses/401' + 403: + $ref: 'api.yaml#/components/responses/403' + 500: + $ref: 'api.yaml#/components/responses/500' + /model/file/{name}: parameters: - $ref: 'api.yaml#/components/parameters/Name' diff --git a/src/routes/model.spec.ts b/src/routes/model.spec.ts index 50cb88c..5be66b7 100644 --- a/src/routes/model.spec.ts +++ b/src/routes/model.spec.ts @@ -273,6 +273,32 @@ describe('/model', () => { }); }); + describe('GET /model/files', () => { + it('rejects a write user', done => { + TestHelper.request(server, done, { + method: 'get', + url: '/model/files', + auth: {basic: 'janedoe'}, + httpStatus: 403, + }); + }); + it('rejects an API key', done => { + TestHelper.request(server, done, { + method: 'get', + url: '/model/files', + auth: {key: 'admin'}, + httpStatus: 401, + }); + }); + it('rejects an unauthorized request', done => { + TestHelper.request(server, done, { + method: 'get', + url: '/model/files', + httpStatus: 401, + }); + }); + }); + describe('GET /model/file/{name}', (() => { it('returns the binary data', done => { TestHelper.request(server, done, { diff --git a/src/routes/model.ts b/src/routes/model.ts index cfa757e..c771ff9 100644 --- a/src/routes/model.ts +++ b/src/routes/model.ts @@ -95,6 +95,15 @@ router.delete('/model/:group(((?!file)[^\\/]+?))/:name', (req, res, next) => { }); }); +router.get('/model/files', (req, res, next) => { + if (!req.auth(res, ['dev', 'admin'], 'basic')) return; + + ModelFileModel.find().exec((err, data) => { + if (err) return next(err); + res.json(data.map(e => ModelValidate.fileOutput(e))); + }); +}); + router.get('/model/file/:name', (req, res, next) => { if (!req.auth(res, ['dev', 'admin'], 'all')) return; diff --git a/src/routes/validate/model.ts b/src/routes/validate/model.ts index d473872..971cfd3 100644 --- a/src/routes/validate/model.ts +++ b/src/routes/validate/model.ts @@ -32,4 +32,11 @@ export default class ModelValidate { // validate input for model }).validate(data, {stripUnknown: true}); return error !== undefined? null : value; } + + static fileOutput (data) { + return { + name: data.name, + size: data.data.length + } + } } \ No newline at end of file