Archived
2

adapted api doc

This commit is contained in:
VLE2FE 2020-05-13 17:28:18 +02:00
parent c84d0ebf0c
commit 649a0b166e
10 changed files with 269 additions and 281 deletions

View File

@ -145,6 +145,11 @@ Template:
properties: properties:
name: name:
type: string type: string
example: humidity
version:
type: number
readOnly: true
example: 1
parameters: parameters:
type: array type: array
items: items:
@ -152,8 +157,20 @@ Template:
properties: properties:
name: name:
type: string type: string
example: kf
range: range:
type: object type: object
example:
min: 0
max: 2
TreatmentTemplate:
allOf:
- $ref: 'api.yaml#/components/schemas/Template'
properties:
number_prefix:
type: string
example: B
Email: Email:
properties: properties:

View File

@ -14,23 +14,15 @@
schema: schema:
type: array type: array
items: items:
$ref: 'api.yaml#/components/schemas/Template' $ref: 'api.yaml#/components/schemas/TreatmentTemplate'
example:
_id: 5ea0450ed851c30a90e70894
name: heat aging
parameters:
- name: method
range:
values:
- copper
- hot air
401: 401:
$ref: 'api.yaml#/components/responses/401' $ref: 'api.yaml#/components/responses/401'
500: 500:
$ref: 'api.yaml#/components/responses/500' $ref: 'api.yaml#/components/responses/500'
/template/treatment/{name}:
/template/treatment/{id}:
parameters: parameters:
- $ref: 'api.yaml#/components/parameters/Name' - $ref: 'api.yaml#/components/parameters/Id'
get: get:
summary: treatment method details summary: treatment method details
description: 'Auth: basic, levels: read, write, maintain, admin' description: 'Auth: basic, levels: read, write, maintain, admin'
@ -44,17 +36,7 @@
content: content:
application/json: application/json:
schema: schema:
allOf: $ref: 'api.yaml#/components/schemas/TreatmentTemplate'
- $ref: 'api.yaml#/components/schemas/Template'
example:
_id: 5ea0450ed851c30a90e70894
name: heat aging
parameters:
- name: method
range:
values:
- copper
- hot air
401: 401:
$ref: 'api.yaml#/components/responses/401' $ref: 'api.yaml#/components/responses/401'
404: 404:
@ -62,7 +44,40 @@
500: 500:
$ref: 'api.yaml#/components/responses/500' $ref: 'api.yaml#/components/responses/500'
put: put:
summary: add/change treatment method summary: change treatment method
description: 'Auth: basic, levels: maintain, admin'
x-doc: With a change a new version is set, resulting in a new template with a new id
tags:
- /template
security:
- BasicAuth: []
requestBody:
required: true
content:
application/json:
schema:
$ref: 'api.yaml#/components/schemas/TreatmentTemplate'
responses:
200:
description: treatment details
content:
application/json:
schema:
$ref: 'api.yaml#/components/schemas/TreatmentTemplate'
400:
$ref: 'api.yaml#/components/responses/400'
401:
$ref: 'api.yaml#/components/responses/401'
403:
$ref: 'api.yaml#/components/responses/403'
404:
$ref: 'api.yaml#/components/responses/404'
500:
$ref: 'api.yaml#/components/responses/500'
/template/treatment/new:
post:
summary: add treatment method
description: 'Auth: basic, levels: maintain, admin' description: 'Auth: basic, levels: maintain, admin'
tags: tags:
- /template - /template
@ -73,63 +88,23 @@
content: content:
application/json: application/json:
schema: schema:
allOf: $ref: 'api.yaml#/components/schemas/TreatmentTemplate'
- $ref: 'api.yaml#/components/schemas/Template'
example:
name: heat aging
parameters:
- name: method
range:
values:
- copper
- hot air
responses: responses:
200: 200:
description: treatment details description: treatment details
content: content:
application/json: application/json:
schema: schema:
allOf: $ref: 'api.yaml#/components/schemas/TreatmentTemplate'
- $ref: 'api.yaml#/components/schemas/Template'
example:
_id: 5ea0450ed851c30a90e70894
name: heat aging
parameters:
- name: method
range:
values:
- copper
- hot air
400: 400:
$ref: 'api.yaml#/components/responses/400' $ref: 'api.yaml#/components/responses/400'
401: 401:
$ref: 'api.yaml#/components/responses/401' $ref: 'api.yaml#/components/responses/401'
403: 403:
$ref: 'api.yaml#/components/responses/403' $ref: 'api.yaml#/components/responses/403'
404:
$ref: 'api.yaml#/components/responses/404'
500:
$ref: 'api.yaml#/components/responses/500'
delete:
summary: delete treatment method
description: 'Auth: basic, levels: maintain, admin'
tags:
- /template
security:
- BasicAuth: []
responses:
200:
$ref: 'api.yaml#/components/responses/Ok'
400:
$ref: 'api.yaml#/components/responses/400'
401:
$ref: 'api.yaml#/components/responses/401'
403:
$ref: 'api.yaml#/components/responses/403'
404:
$ref: 'api.yaml#/components/responses/404'
500: 500:
$ref: 'api.yaml#/components/responses/500' $ref: 'api.yaml#/components/responses/500'
/template/measurements: /template/measurements:
get: get:
summary: all available measurement methods summary: all available measurement methods
@ -147,21 +122,13 @@
type: array type: array
items: items:
$ref: 'api.yaml#/components/schemas/Template' $ref: 'api.yaml#/components/schemas/Template'
example:
_id: 5ea0450ed851c30a90e70894
name: humidity
parameters:
- name: kf
range:
min: 0
max: 2
401: 401:
$ref: 'api.yaml#/components/responses/401' $ref: 'api.yaml#/components/responses/401'
500: 500:
$ref: 'api.yaml#/components/responses/500' $ref: 'api.yaml#/components/responses/500'
/template/measurement/{name}: /template/measurement/{id}:
parameters: parameters:
- $ref: 'api.yaml#/components/parameters/Name' - $ref: 'api.yaml#/components/parameters/Id'
get: get:
summary: measurement method details summary: measurement method details
description: 'Auth: basic, levels: read, write, maintain, admin' description: 'Auth: basic, levels: read, write, maintain, admin'
@ -175,16 +142,7 @@
content: content:
application/json: application/json:
schema: schema:
allOf: $ref: 'api.yaml#/components/schemas/Template'
- $ref: 'api.yaml#/components/schemas/Template'
example:
_id: 5ea0450ed851c30a90e70894
name: humidity
parameters:
- name: kf
range:
min: 0
max: 2
400: 400:
$ref: 'api.yaml#/components/responses/400' $ref: 'api.yaml#/components/responses/400'
401: 401:
@ -194,7 +152,7 @@
500: 500:
$ref: 'api.yaml#/components/responses/500' $ref: 'api.yaml#/components/responses/500'
put: put:
summary: add/change measurement method summary: change measurement method
description: 'Auth: basic, levels: maintain, admin' description: 'Auth: basic, levels: maintain, admin'
tags: tags:
- /template - /template
@ -205,32 +163,14 @@
content: content:
application/json: application/json:
schema: schema:
allOf: $ref: 'api.yaml#/components/schemas/Template'
- $ref: 'api.yaml#/components/schemas/Template'
example:
_id: 5ea0450ed851c30a90e70894
name: humidity
parameters:
- name: kf
range:
min: 0
max: 2
responses: responses:
200: 200:
description: measurement details description: measurement details
content: content:
application/json: application/json:
schema: schema:
allOf: $ref: 'api.yaml#/components/schemas/Template'
- $ref: 'api.yaml#/components/schemas/Template'
example:
_id: 5ea0450ed851c30a90e70894
name: humidity
parameters:
- name: kf
range:
min: 0
max: 2
400: 400:
$ref: 'api.yaml#/components/responses/400' $ref: 'api.yaml#/components/responses/400'
401: 401:
@ -241,23 +181,33 @@
$ref: 'api.yaml#/components/responses/404' $ref: 'api.yaml#/components/responses/404'
500: 500:
$ref: 'api.yaml#/components/responses/500' $ref: 'api.yaml#/components/responses/500'
delete:
summary: delete measurement method /template/measurement/new:
post:
summary: add measurement method
description: 'Auth: basic, levels: maintain, admin' description: 'Auth: basic, levels: maintain, admin'
tags: tags:
- /template - /template
security: security:
- BasicAuth: [] - BasicAuth: []
requestBody:
required: true
content:
application/json:
schema:
$ref: 'api.yaml#/components/schemas/Template'
responses: responses:
200: 200:
$ref: 'api.yaml#/components/responses/Ok' description: measurement details
content:
application/json:
schema:
$ref: 'api.yaml#/components/schemas/Template'
400: 400:
$ref: 'api.yaml#/components/responses/400' $ref: 'api.yaml#/components/responses/400'
401: 401:
$ref: 'api.yaml#/components/responses/401' $ref: 'api.yaml#/components/responses/401'
403: 403:
$ref: 'api.yaml#/components/responses/403' $ref: 'api.yaml#/components/responses/403'
404:
$ref: 'api.yaml#/components/responses/404'
500: 500:
$ref: 'api.yaml#/components/responses/500' $ref: 'api.yaml#/components/responses/500'

55
package-lock.json generated
View File

@ -14,6 +14,30 @@
"js-yaml": "^3.13.1" "js-yaml": "^3.13.1"
} }
}, },
"@apidevtools/openapi-schemas": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/@apidevtools/openapi-schemas/-/openapi-schemas-2.0.3.tgz",
"integrity": "sha512-QoPaxGXfgqgGpK1p21FJ400z56hV681a8DOcZt3J5z0WIHgFeaIZ4+6bX5ATqmOoCpRCsH4ITEwKaOyFMz7wOA=="
},
"@apidevtools/swagger-methods": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/@apidevtools/swagger-methods/-/swagger-methods-3.0.1.tgz",
"integrity": "sha512-1Vlm18XYW6Yg7uHunroXeunWz5FShPFAdxBbPy8H6niB2Elz9QQsCoYHMbcc11EL1pTxaIr9HXz2An/mHXlX1Q=="
},
"@apidevtools/swagger-parser": {
"version": "9.0.1",
"resolved": "https://registry.npmjs.org/@apidevtools/swagger-parser/-/swagger-parser-9.0.1.tgz",
"integrity": "sha512-Irqybg4dQrcHhZcxJc/UM4vO7Ksoj1Id5e+K94XUOzllqX1n47HEA50EKiXTCQbykxuJ4cYGIivjx/MRSTC5OA==",
"requires": {
"@apidevtools/json-schema-ref-parser": "^8.0.0",
"@apidevtools/openapi-schemas": "^2.0.2",
"@apidevtools/swagger-methods": "^3.0.0",
"@jsdevtools/ono": "^7.1.0",
"call-me-maybe": "^1.0.1",
"openapi-types": "^1.3.5",
"z-schema": "^4.2.2"
}
},
"@babel/code-frame": { "@babel/code-frame": {
"version": "7.8.3", "version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.8.3.tgz", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.8.3.tgz",
@ -1353,6 +1377,16 @@
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
"integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==" "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A=="
}, },
"lodash.get": {
"version": "4.4.2",
"resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz",
"integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk="
},
"lodash.isequal": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz",
"integrity": "sha1-QVxEePK8wwEgwizhDtMib30+GOA="
},
"log-symbols": { "log-symbols": {
"version": "3.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-3.0.0.tgz", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-3.0.0.tgz",
@ -1743,6 +1777,11 @@
"wrappy": "1" "wrappy": "1"
} }
}, },
"openapi-types": {
"version": "1.3.5",
"resolved": "https://registry.npmjs.org/openapi-types/-/openapi-types-1.3.5.tgz",
"integrity": "sha512-11oi4zYorsgvg5yBarZplAqbpev5HkuVNPlZaPTknPDzAynq+lnJdXAmruGWP0s+dNYZS7bjM+xrTpJw7184Fg=="
},
"p-cancelable": { "p-cancelable": {
"version": "1.1.0", "version": "1.1.0",
"resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz", "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz",
@ -2505,6 +2544,11 @@
"resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
"integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM="
}, },
"validator": {
"version": "12.2.0",
"resolved": "https://registry.npmjs.org/validator/-/validator-12.2.0.tgz",
"integrity": "sha512-jJfE/DW6tIK1Ek8nCfNFqt8Wb3nzMoAbocBF6/Icgg1ZFSBpObdnwVY2jQj6qUqzhx5jc71fpvBWyLGO7Xl+nQ=="
},
"vary": { "vary": {
"version": "1.1.2", "version": "1.1.2",
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
@ -2709,6 +2753,17 @@
"lodash": "^4.17.15", "lodash": "^4.17.15",
"yargs": "^13.3.0" "yargs": "^13.3.0"
} }
},
"z-schema": {
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/z-schema/-/z-schema-4.2.3.tgz",
"integrity": "sha512-zkvK/9TC6p38IwcrbnT3ul9in1UX4cm1y/VZSs4GHKIiDCrlafc+YQBgQBUdDXLAoZHf2qvQ7gJJOo6yT1LH6A==",
"requires": {
"commander": "^2.7.1",
"lodash.get": "^4.4.2",
"lodash.isequal": "^4.5.0",
"validator": "^12.0.0"
}
} }
} }
} }

View File

@ -15,6 +15,7 @@
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
"@apidevtools/json-schema-ref-parser": "^8.0.0", "@apidevtools/json-schema-ref-parser": "^8.0.0",
"@apidevtools/swagger-parser": "^9.0.1",
"@hapi/joi": "^17.1.1", "@hapi/joi": "^17.1.1",
"@types/bcrypt": "^3.0.0", "@types/bcrypt": "^3.0.0",
"@types/body-parser": "^1.19.0", "@types/body-parser": "^1.19.0",

View File

@ -1,5 +1,6 @@
import swagger from 'swagger-ui-express'; import swagger from 'swagger-ui-express';
import jsonRefParser, {JSONSchema} from '@apidevtools/json-schema-ref-parser'; import jsonRefParser, {JSONSchema} from '@apidevtools/json-schema-ref-parser';
import oasParser from '@apidevtools/swagger-parser';
// modifies the normal swagger-ui-express package // modifies the normal swagger-ui-express package
@ -19,7 +20,15 @@ export default class api {
apiDoc = doc; apiDoc = doc;
apiDoc.paths = apiDoc.paths.allOf.reduce((s, e) => Object.assign(s, e)); // bundle routes apiDoc.paths = apiDoc.paths.allOf.reduce((s, e) => Object.assign(s, e)); // bundle routes
apiDoc = this.resolveXDoc(apiDoc); apiDoc = this.resolveXDoc(apiDoc);
oasParser.validate(apiDoc, (err, api) => {
if (err) {
console.error(err);
}
else {
console.info('API ok, version ' + api.info.version);
swagger.setup(apiDoc); swagger.setup(apiDoc);
}
});
}); });
return swagger.setup(apiDoc, {customCssUrl: '/static/styles/swagger.css'}) return swagger.setup(apiDoc, {customCssUrl: '/static/styles/swagger.css'})
} }

View File

@ -1,7 +1,7 @@
import should from 'should/as-function'; import should from 'should/as-function';
import MaterialModel from '../models/material'; import MaterialModel from '../models/material';
import TestHelper from "../test/helper"; import TestHelper from "../test/helper";
// TODO: status
// TODO: numbers with color only (no number) // TODO: numbers with color only (no number)
// TODO: deal with numbers with leading zeros // TODO: deal with numbers with leading zeros

View File

@ -8,7 +8,7 @@ import IdValidate from './validate/id';
import res400 from './validate/res400'; import res400 from './validate/res400';
import mongoose from 'mongoose'; import mongoose from 'mongoose';
// TODO: remove f() for await
const router = express.Router(); const router = express.Router();

View File

@ -3,7 +3,8 @@ import TemplateTreatmentModel from '../models/treatment_template';
import TemplateMeasurementModel from '../models/measurement_template'; import TemplateMeasurementModel from '../models/measurement_template';
import TestHelper from "../test/helper"; import TestHelper from "../test/helper";
// TODO: remove DELETE methods, only updates possible // TODO: convert name to id, criteria for new name, criteria for new version, criteria for prefix
describe('/template', () => { describe('/template', () => {
let server; let server;
before(done => TestHelper.before(done)); before(done => TestHelper.before(done));
@ -26,6 +27,8 @@ describe('/template', () => {
should(treatment).have.only.keys('_id', 'name', 'parameters'); should(treatment).have.only.keys('_id', 'name', 'parameters');
should(treatment).have.property('_id').be.type('string'); should(treatment).have.property('_id').be.type('string');
should(treatment).have.property('name').be.type('string'); should(treatment).have.property('name').be.type('string');
should(treatment).have.property('version').be.type('number');
should(treatment).have.property('number_prefix').be.type('string');
should(treatment.parameters).matchEach(number => { should(treatment.parameters).matchEach(number => {
should(number).have.only.keys('name', 'range'); should(number).have.only.keys('name', 'range');
should(number).have.property('name').be.type('string'); should(number).have.property('name').be.type('string');
@ -52,28 +55,28 @@ describe('/template', () => {
}); });
}); });
describe('GET /template/treatment/{name}', () => { describe('GET /template/treatment/{id}', () => {
it('returns the right treatment template', done => { it('returns the right treatment template', done => {
TestHelper.request(server, done, { TestHelper.request(server, done, {
method: 'get', method: 'get',
url: '/template/treatment/heat%20treatment', url: '/template/treatment/200000000000000000000001',
auth: {basic: 'janedoe'}, auth: {basic: 'janedoe'},
httpStatus: 200, httpStatus: 200,
res: {_id: '200000000000000000000001', name: 'heat treatment', parameters: [{name: 'material', range: {values: ['copper', 'hot air']}}, {name: 'weeks', range: {min: 1, max: 10}}]} res: {_id: '200000000000000000000001', name: 'heat treatment', version: 1, number_prefix: 'A', parameters: [{name: 'material', range: {values: ['copper', 'hot air']}}, {name: 'weeks', range: {min: 1, max: 10}}]}
}); });
}); });
it('rejects an API key', done => { it('rejects an API key', done => {
TestHelper.request(server, done, { TestHelper.request(server, done, {
method: 'get', method: 'get',
url: '/template/treatment/heat%20treatment', url: '/template/treatment/200000000000000000000001',
auth: {key: 'janedoe'}, auth: {key: 'janedoe'},
httpStatus: 401 httpStatus: 401
}); });
}); });
it('rejects an unknown name', done => { it('rejects an unknown id', done => {
TestHelper.request(server, done, { TestHelper.request(server, done, {
method: 'get', method: 'get',
url: '/template/treatment/xxx', url: '/template/treatment/000000000000000000000001',
auth: {basic: 'janedoe'}, auth: {basic: 'janedoe'},
httpStatus: 404 httpStatus: 404
}); });
@ -81,7 +84,7 @@ describe('/template', () => {
it('rejects unauthorized requests', done => { it('rejects unauthorized requests', done => {
TestHelper.request(server, done, { TestHelper.request(server, done, {
method: 'get', method: 'get',
url: '/template/treatment/heat%20treatment', url: '/template/treatment/200000000000000000000001',
httpStatus: 401 httpStatus: 401
}); });
}); });
@ -91,38 +94,50 @@ describe('/template', () => {
it('returns the right treatment template', done => { it('returns the right treatment template', done => {
TestHelper.request(server, done, { TestHelper.request(server, done, {
method: 'put', method: 'put',
url: '/template/treatment/heat%20treatment', url: '/template/treatment/200000000000000000000001',
auth: {basic: 'admin'}, auth: {basic: 'admin'},
httpStatus: 200, httpStatus: 200,
req: {}, req: {},
res: {_id: '200000000000000000000001', name: 'heat treatment', parameters: [{name: 'material', range: {values: ['copper', 'hot air']}}, {name: 'weeks', range: {min: 1, max: 10}}]} res: {_id: '200000000000000000000001', name: 'heat treatment', version: 1, number_prefix: 'A', parameters: [{name: 'material', range: {values: ['copper', 'hot air']}}, {name: 'weeks', range: {min: 1, max: 10}}]}
}); });
}); });
it('keeps unchanged properties', done => { it('keeps unchanged properties', done => {
TestHelper.request(server, done, { TestHelper.request(server, done, {
method: 'put', method: 'put',
url: '/template/treatment/heat%20treatment', url: '/template/treatment/200000000000000000000001',
auth: {basic: 'admin'}, auth: {basic: 'admin'},
httpStatus: 200, httpStatus: 200,
req: {name: 'heat treatment', parameters: [{name: 'material', range: {values: ['copper', 'hot air']}}, {name: 'weeks', range: {min: 1, max: 10}}]}, req: {name: 'heat treatment', parameters: [{name: 'material', range: {values: ['copper', 'hot air']}}, {name: 'weeks', range: {min: 1, max: 10}}]},
res: {_id: '200000000000000000000001', name: 'heat treatment', parameters: [{name: 'material', range: {values: ['copper', 'hot air']}}, {name: 'weeks', range: {min: 1, max: 10}}]} res: {_id: '200000000000000000000001', name: 'heat treatment', version: 1, number_prefix: 'A', parameters: [{name: 'material', range: {values: ['copper', 'hot air']}}, {name: 'weeks', range: {min: 1, max: 10}}]}
});
});
it('keeps only one unchanged property', done => {
TestHelper.request(server, done, {
method: 'put',
url: '/template/treatment/200000000000000000000001',
auth: {basic: 'admin'},
httpStatus: 200,
req: {name: 'heat treatment'},
res: {_id: '200000000000000000000001', name: 'heat treatment', version: 1, number_prefix: 'A', parameters: [{name: 'material', range: {values: ['copper', 'hot air']}}, {name: 'weeks', range: {min: 1, max: 10}}]}
}); });
}); });
it('changes the given properties', done => { it('changes the given properties', done => {
TestHelper.request(server, done, { TestHelper.request(server, done, {
method: 'put', method: 'put',
url: '/template/treatment/heat%20treatment', url: '/template/treatment/200000000000000000000001',
auth: {basic: 'admin'}, auth: {basic: 'admin'},
httpStatus: 200, httpStatus: 200,
req: {name: 'heat aging', parameters: [{name: 'time', range: {min: 1}}]} req: {name: 'heat aging', parameters: [{name: 'time', range: {min: 1}}]}
}).end((err, res) => { }).end((err, res) => {
if (err) return done(err); if (err) return done(err);
should(res.body).be.eql({_id: '200000000000000000000001', name: 'heat aging', parameters: [{name: 'time', range: {min: 1}}]}); should(res.body).be.eql({_id: '200000000000000000000001', name: 'heat aging', version: 2, number_prefix: 'A', parameters: [{name: 'time', range: {min: 1}}]});
TemplateTreatmentModel.find({name: 'heat aging'}).lean().exec((err, data:any) => { TemplateTreatmentModel.find({name: 'heat aging'}).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', 'name', 'parameters', '__v'); should(data[0]).have.only.keys('_id', 'name', 'version', 'number_prefix', 'parameters', '__v');
should(data[0]).have.property('name', 'heat aging'); should(data[0]).have.property('name', 'heat aging');
should(data[0]).have.property('version', 2);
should(data[0]).have.property('number_prefix', 'A');
should(data[0]).have.property('parameters').have.lengthOf(1); should(data[0]).have.property('parameters').have.lengthOf(1);
should(data[0].parameters[0]).have.property('name', 'time'); should(data[0].parameters[0]).have.property('name', 'time');
should(data[0].parameters[0]).have.property('range'); should(data[0].parameters[0]).have.property('range');
@ -131,50 +146,122 @@ describe('/template', () => {
}); });
}); });
}); });
it('allows changing only one property'); // TODO: adapt PUT to other PUTs and do POST, everything for measurement too
it('supports values ranges', done => { it('supports values ranges', done => {
TestHelper.request(server, done, { TestHelper.request(server, done, {
method: 'put', method: 'put',
url: '/template/treatment/heat%20treatment', url: '/template/treatment/200000000000000000000001',
auth: {basic: 'admin'}, auth: {basic: 'admin'},
httpStatus: 200, httpStatus: 200,
req: {parameters: [{name: 'time', range: {values: [1, 2, 5]}}]}, req: {parameters: [{name: 'time', range: {values: [1, 2, 5]}}]},
res: {_id: '200000000000000000000001', name: 'heat treatment', parameters: [{name: 'time', range: {values: [1, 2, 5]}}]} res: {_id: '200000000000000000000001', name: 'heat treatment', version: 2, number_prefix: 'A', parameters: [{name: 'time', range: {values: [1, 2, 5]}}]}
}); });
}); });
it('supports min max ranges', done => { it('supports min max ranges', done => {
TestHelper.request(server, done, { TestHelper.request(server, done, {
method: 'put', method: 'put',
url: '/template/treatment/heat%20treatment', url: '/template/treatment/200000000000000000000001',
auth: {basic: 'admin'}, auth: {basic: 'admin'},
httpStatus: 200, httpStatus: 200,
req: {parameters: [{name: 'time', range: {min: 1, max: 11}}]}, req: {parameters: [{name: 'time', range: {min: 1, max: 11}}]},
res: {_id: '200000000000000000000001', name: 'heat treatment', parameters: [{name: 'time', range: {min: 1, max: 11}}]} res: {_id: '200000000000000000000001', name: 'heat treatment', version: 2, number_prefix: 'A', parameters: [{name: 'time', range: {min: 1, max: 11}}]}
}); });
}); });
it('supports empty ranges', done => { it('supports empty ranges', done => {
TestHelper.request(server, done, { TestHelper.request(server, done, {
method: 'put', method: 'put',
url: '/template/treatment/heat%20treatment', url: '/template/treatment/200000000000000000000001',
auth: {basic: 'admin'}, auth: {basic: 'admin'},
httpStatus: 200, httpStatus: 200,
req: {parameters: [{name: 'time', range: {}}]}, req: {parameters: [{name: 'time', range: {}}]},
res: {_id: '200000000000000000000001', name: 'heat treatment', parameters: [{name: 'time', range: {}}]} res: {_id: '200000000000000000000001', name: 'heat treatment', version: 2, number_prefix: 'A', parameters: [{name: 'time', range: {}}]}
}); });
}); });
it('adds a new template for an unknown name', done => { it('rejects an invalid id', done => {
TestHelper.request(server, done, { TestHelper.request(server, done, {
method: 'put', method: 'put',
url: '/template/treatment/heat%20aging', url: '/template/treatment/2000000000h0000000000001',
auth: {basic: 'admin'},
httpStatus: 404,
req: {name: 'heat aging', parameters: [{name: 'time', range: {min: 1}}]}
});
});
it('rejects an unknown id', done => {
TestHelper.request(server, done, {
method: 'put',
url: '/template/treatment/000000000000000000000001',
auth: {basic: 'admin'},
httpStatus: 404,
req: {name: 'heat aging', parameters: [{name: 'time', range: {min: 1}}]}
});
});
it('rejects already existing number prefixes', done => {
TestHelper.request(server, done, {
method: 'put',
url: '/template/treatment/200000000000000000000001',
auth: {basic: 'admin'},
httpStatus: 400,
req: {number_prefix: 'B', parameters: [{name: 'time', range: {min: 1}}]},
res: {status: 'Number prefix already taken'}
});
});
it('rejects an API key', done => {
TestHelper.request(server, done, {
method: 'put',
url: '/template/treatment/200000000000000000000001',
auth: {key: 'admin'},
httpStatus: 401,
req: {}
});
});
it('rejects requests from a write user', done => {
TestHelper.request(server, done, {
method: 'put',
url: '/template/treatment/200000000000000000000001',
auth: {basic: 'janedoe'},
httpStatus: 403,
req: {}
});
});
it('rejects unauthorized requests', done => {
TestHelper.request(server, done, {
method: 'put',
url: '/template/treatment/200000000000000000000001',
httpStatus: 401,
req: {}
});
});
});
describe('POST /template/treatment/new', () => {
it('returns the right treatment template', done => {
TestHelper.request(server, done, {
method: 'put',
url: '/template/treatment/200000000000000000000001',
auth: {basic: 'admin'},
httpStatus: 200,
req: {},
res: {_id: '200000000000000000000001', name: 'heat treatment', version: 1, number_prefix: 'A', parameters: [{name: 'material', range: {values: ['copper', 'hot air']}}, {name: 'weeks', range: {min: 1, max: 10}}]}
});
});
it('stores the template', done => {
TestHelper.request(server, done, {
method: 'put',
url: '/template/treatment/200000000000000000000001',
auth: {basic: 'admin'}, auth: {basic: 'admin'},
httpStatus: 200, httpStatus: 200,
req: {name: 'heat aging', parameters: [{name: 'time', range: {min: 1}}]} req: {name: 'heat aging', parameters: [{name: 'time', range: {min: 1}}]}
}).end(err => { }).end((err, res) => {
if (err) return done(err); if (err) return done(err);
should(res.body).be.eql({_id: '200000000000000000000001', name: 'heat aging', version: 2, number_prefix: 'A', parameters: [{name: 'time', range: {min: 1}}]});
TemplateTreatmentModel.find({name: 'heat aging'}).lean().exec((err, data:any) => { TemplateTreatmentModel.find({name: 'heat aging'}).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', 'name', 'parameters', '__v'); should(data[0]).have.only.keys('_id', 'name', 'version', 'number_prefix', 'parameters', '__v');
should(data[0]).have.property('name', 'heat aging'); should(data[0]).have.property('name', 'heat aging');
should(data[0]).have.property('version', 2);
should(data[0]).have.property('number_prefix', 'A');
should(data[0]).have.property('parameters').have.lengthOf(1);
should(data[0].parameters[0]).have.property('name', 'time'); should(data[0].parameters[0]).have.property('name', 'time');
should(data[0].parameters[0]).have.property('range'); should(data[0].parameters[0]).have.property('range');
should(data[0].parameters[0].range).have.property('min', 1); should(data[0].parameters[0].range).have.property('min', 1);
@ -182,7 +269,7 @@ describe('/template', () => {
}); });
}); });
}); });
it('rejects a missing name for a new name', done => { it('rejects a missing name', done => {
TestHelper.request(server, done, { TestHelper.request(server, done, {
method: 'put', method: 'put',
url: '/template/treatment/heat%20aging', url: '/template/treatment/heat%20aging',
@ -192,7 +279,7 @@ describe('/template', () => {
res: {status: 'Invalid body format', details: '"name" is required'} res: {status: 'Invalid body format', details: '"name" is required'}
}); });
}); });
it('rejects missing parameters for a new name', done => { it('rejects missing parameters', done => {
TestHelper.request(server, done, { TestHelper.request(server, done, {
method: 'put', method: 'put',
url: '/template/treatment/heat%20aging', url: '/template/treatment/heat%20aging',
@ -202,7 +289,7 @@ describe('/template', () => {
res: {status: 'Invalid body format', details: '"parameters" is required'} res: {status: 'Invalid body format', details: '"parameters" is required'}
}); });
}); });
it('rejects a missing parameter name for a new name', done => { it('rejects a missing parameter name', done => {
TestHelper.request(server, done, { TestHelper.request(server, done, {
method: 'put', method: 'put',
url: '/template/treatment/heat%20aging', url: '/template/treatment/heat%20aging',
@ -212,7 +299,7 @@ describe('/template', () => {
res: {status: 'Invalid body format', details: '"parameters[0].name" is required'} res: {status: 'Invalid body format', details: '"parameters[0].name" is required'}
}); });
}); });
it('rejects a missing parameter range for a new name', done => { it('rejects a missing parameter range', done => {
TestHelper.request(server, done, { TestHelper.request(server, done, {
method: 'put', method: 'put',
url: '/template/treatment/heat%20aging', url: '/template/treatment/heat%20aging',
@ -222,7 +309,7 @@ describe('/template', () => {
res: {status: 'Invalid body format', details: '"parameters[0].range" is required'} res: {status: 'Invalid body format', details: '"parameters[0].range" is required'}
}); });
}); });
it('rejects a an invalid parameter range property for a new name', done => { it('rejects a an invalid parameter range property', done => {
TestHelper.request(server, done, { TestHelper.request(server, done, {
method: 'put', method: 'put',
url: '/template/treatment/heat%20aging', url: '/template/treatment/heat%20aging',
@ -232,16 +319,6 @@ describe('/template', () => {
res: {status: 'Invalid body format', details: '"parameters[0].range.xx" is not allowed'} res: {status: 'Invalid body format', details: '"parameters[0].range.xx" is not allowed'}
}); });
}); });
it('rejects already existing names', done => {
TestHelper.request(server, done, {
method: 'put',
url: '/template/treatment/heat%20treatment',
auth: {basic: 'admin'},
httpStatus: 400,
req: {name: 'heat treatment 2', parameters: [{name: 'time', range: {min: 1}}]},
res: {status: 'Template name already taken'}
});
});
it('rejects wrong properties', done => { it('rejects wrong properties', done => {
TestHelper.request(server, done, { TestHelper.request(server, done, {
method: 'put', method: 'put',
@ -252,83 +329,6 @@ describe('/template', () => {
res: {status: 'Invalid body format', details: '"name" is required'} res: {status: 'Invalid body format', details: '"name" is required'}
}); });
}); });
it('rejects an API key', done => {
TestHelper.request(server, done, {
method: 'put',
url: '/template/treatment/heat%20treatment',
auth: {key: 'admin'},
httpStatus: 401,
req: {}
});
});
it('rejects requests from a write user', done => {
TestHelper.request(server, done, {
method: 'put',
url: '/template/treatment/heat%20treatment',
auth: {basic: 'janedoe'},
httpStatus: 403,
req: {}
});
});
it('rejects unauthorized requests', done => {
TestHelper.request(server, done, {
method: 'put',
url: '/template/treatment/heat%20treatment',
httpStatus: 401,
req: {}
});
});
});
describe('DELETE /template/treatment/{name}', () => {
it('deletes the template', done => {
TestHelper.request(server, done, {
method: 'delete',
url: '/template/treatment/heat%20treatment',
auth: {basic: 'admin'},
httpStatus: 200
}).end((err, res) => {
if (err) return done(err);
should(res.body).be.eql({status: 'OK'});
TemplateTreatmentModel.find({name: 'heat treatment'}).lean().exec((err, data:any) => {
if (err) return done(err);
should(data).have.lengthOf(0);
done();
});
});
});
it('rejects deleting a template still in use');
it('rejects an API key', done => {
TestHelper.request(server, done, {
method: 'delete',
url: '/template/treatment/heat%20treatment',
auth: {key: 'admin'},
httpStatus: 401
});
});
it('rejects requests from a write user', done => {
TestHelper.request(server, done, {
method: 'delete',
url: '/template/treatment/heat%20treatment',
auth: {basic: 'janedoe'},
httpStatus: 403
})
});
it('returns 404 for an unknown name', done => {
TestHelper.request(server, done, {
method: 'delete',
url: '/template/treatment/xxx',
auth: {basic: 'admin'},
httpStatus: 404
})
});
it('rejects unauthorized requests', done => {
TestHelper.request(server, done, {
method: 'delete',
url: '/template/treatment/heat%20treatment',
httpStatus: 401
})
});
}); });
}); });
@ -603,56 +603,5 @@ describe('/template', () => {
}); });
}); });
}); });
describe('DELETE /template/measurement/{name}', () => {
it('deletes the template', done => {
TestHelper.request(server, done, {
method: 'delete',
url: '/template/measurement/spectrum',
auth: {basic: 'admin'},
httpStatus: 200
}).end((err, res) => {
if (err) return done(err);
should(res.body).be.eql({status: 'OK'});
TemplateMeasurementModel.find({name: 'spectrum'}).lean().exec((err, data:any) => {
if (err) return done(err);
should(data).have.lengthOf(0);
done();
});
});
});
it('rejects deleting a template still in use');
it('rejects an API key', done => {
TestHelper.request(server, done, {
method: 'delete',
url: '/template/measurement/spectrum',
auth: {key: 'admin'},
httpStatus: 401
});
});
it('rejects requests from a write user', done => {
TestHelper.request(server, done, {
method: 'delete',
url: '/template/measurement/spectrum',
auth: {basic: 'janedoe'},
httpStatus: 403
})
});
it('returns 404 for an unknown name', done => {
TestHelper.request(server, done, {
method: 'delete',
url: '/template/measurement/xxx',
auth: {basic: 'admin'},
httpStatus: 404
})
});
it('rejects unauthorized requests', done => {
TestHelper.request(server, done, {
method: 'delete',
url: '/template/measurement/spectrum',
httpStatus: 401
})
});
});
}); });
}); });

View File

@ -71,20 +71,20 @@ router.put('/template/:collection(measurement|treatment)/:name', (req, res, next
}); });
}); });
router.delete('/template/:collection(measurement|treatment)/:name', (req, res, next) => { // router.delete('/template/:collection(measurement|treatment)/:name', (req, res, next) => {
if (!req.auth(res, ['maintain', 'admin'], 'basic')) return; // if (!req.auth(res, ['maintain', 'admin'], 'basic')) return;
//
(req.params.collection === 'treatment' ? TemplateTreatmentModel : TemplateMeasurementModel) // (req.params.collection === 'treatment' ? TemplateTreatmentModel : TemplateMeasurementModel)
.findOneAndDelete({name: req.params.name}).lean().exec((err, data) => { // .findOneAndDelete({name: req.params.name}).lean().exec((err, data) => {
if (err) return next(err); // if (err) return next(err);
if (data) { // if (data) {
res.json({status: 'OK'}) // res.json({status: 'OK'})
} // }
else { // else {
res.status(404).json({status: 'Not found'}); // res.status(404).json({status: 'Not found'});
} // }
}); // });
}); // });
module.exports = router; module.exports = router;

View File

@ -308,6 +308,8 @@
{ {
"_id": {"$oid":"200000000000000000000001"}, "_id": {"$oid":"200000000000000000000001"},
"name": "heat treatment", "name": "heat treatment",
"version": 1,
"number_prefix": "A",
"parameters": [ "parameters": [
{ {
"name": "material", "name": "material",
@ -331,6 +333,8 @@
{ {
"_id": {"$oid":"200000000000000000000002"}, "_id": {"$oid":"200000000000000000000002"},
"name": "heat treatment 2", "name": "heat treatment 2",
"version": 2,
"number_prefix": "B",
"parameters": [ "parameters": [
{ {
"name": "material", "name": "material",
@ -344,6 +348,7 @@
{ {
"_id": {"$oid":"300000000000000000000001"}, "_id": {"$oid":"300000000000000000000001"},
"name": "spectrum", "name": "spectrum",
"version": 1,
"parameters": [ "parameters": [
{ {
"name": "dpt", "name": "dpt",
@ -357,6 +362,7 @@
{ {
"_id": {"$oid":"300000000000000000000002"}, "_id": {"$oid":"300000000000000000000002"},
"name": "kf", "name": "kf",
"version": 2,
"parameters": [ "parameters": [
{ {
"name": "weight %", "name": "weight %",
@ -378,6 +384,7 @@
{ {
"_id": {"$oid":"300000000000000000000003"}, "_id": {"$oid":"300000000000000000000003"},
"name": "mt 3", "name": "mt 3",
"version": 1,
"parameters": [ "parameters": [
{ {
"name": "val1", "name": "val1",