Merge pull request #11 in ~VLE2FE/dfop-api from condition-merge to develop
* commit '8276e5108c86e92739ffd830b056a3884ce35cf3': /api/ subroutes only available in dev/test implemented code coverage adapted /measurements to use sample_id adapted existing /sample methods to condition, removed /condition route
This commit is contained in:
commit
dc8828dbeb
@ -4,6 +4,8 @@
|
|||||||
<w>bcrypt</w>
|
<w>bcrypt</w>
|
||||||
<w>cfenv</w>
|
<w>cfenv</w>
|
||||||
<w>dfopdb</w>
|
<w>dfopdb</w>
|
||||||
|
<w>janedoe</w>
|
||||||
|
<w>testcomment</w>
|
||||||
</words>
|
</words>
|
||||||
</dictionary>
|
</dictionary>
|
||||||
</component>
|
</component>
|
@ -1,13 +0,0 @@
|
|||||||
<component name="libraryTable">
|
|
||||||
<library name="dist" type="javaScript">
|
|
||||||
<properties>
|
|
||||||
<sourceFilesUrls>
|
|
||||||
<item url="file://$PROJECT_DIR$/dist" />
|
|
||||||
</sourceFilesUrls>
|
|
||||||
</properties>
|
|
||||||
<CLASSES>
|
|
||||||
<root url="file://$PROJECT_DIR$/dist" />
|
|
||||||
</CLASSES>
|
|
||||||
<SOURCES />
|
|
||||||
</library>
|
|
||||||
</component>
|
|
@ -54,7 +54,6 @@ tags:
|
|||||||
- name: /
|
- name: /
|
||||||
- name: /sample
|
- name: /sample
|
||||||
- name: /material
|
- name: /material
|
||||||
- name: /condition
|
|
||||||
- name: /measurement
|
- name: /measurement
|
||||||
- name: /template
|
- name: /template
|
||||||
- name: /model
|
- name: /model
|
||||||
@ -66,7 +65,6 @@ paths:
|
|||||||
- $ref: 'others.yaml'
|
- $ref: 'others.yaml'
|
||||||
- $ref: 'sample.yaml'
|
- $ref: 'sample.yaml'
|
||||||
- $ref: 'material.yaml'
|
- $ref: 'material.yaml'
|
||||||
- $ref: 'condition.yaml'
|
|
||||||
- $ref: 'measurement.yaml'
|
- $ref: 'measurement.yaml'
|
||||||
- $ref: 'template.yaml'
|
- $ref: 'template.yaml'
|
||||||
- $ref: 'model.yaml'
|
- $ref: 'model.yaml'
|
||||||
|
@ -1,111 +0,0 @@
|
|||||||
/condition/{id}:
|
|
||||||
parameters:
|
|
||||||
- $ref: 'api.yaml#/components/parameters/Id'
|
|
||||||
get:
|
|
||||||
summary: condition by id
|
|
||||||
description: 'Auth: all, levels: read, write, maintain, dev, admin'
|
|
||||||
x-doc: status handling (accessible (only for maintain/admin))? # TODO after decision
|
|
||||||
tags:
|
|
||||||
- /condition
|
|
||||||
responses:
|
|
||||||
200:
|
|
||||||
description: condition details
|
|
||||||
content:
|
|
||||||
application/json:
|
|
||||||
schema:
|
|
||||||
$ref: 'api.yaml#/components/schemas/Condition'
|
|
||||||
400:
|
|
||||||
$ref: 'api.yaml#/components/responses/400'
|
|
||||||
401:
|
|
||||||
$ref: 'api.yaml#/components/responses/401'
|
|
||||||
404:
|
|
||||||
$ref: 'api.yaml#/components/responses/404'
|
|
||||||
500:
|
|
||||||
$ref: 'api.yaml#/components/responses/500'
|
|
||||||
put:
|
|
||||||
summary: change condition
|
|
||||||
description: 'Auth: basic, levels: write, maintain, dev, admin <br>Only maintain and admin are allowed to reference samples created by another user'
|
|
||||||
x-doc: status is reset to 0 on any changes
|
|
||||||
tags:
|
|
||||||
- /condition
|
|
||||||
security:
|
|
||||||
- BasicAuth: []
|
|
||||||
requestBody:
|
|
||||||
required: true
|
|
||||||
content:
|
|
||||||
application/json:
|
|
||||||
schema:
|
|
||||||
allOf:
|
|
||||||
- $ref: 'api.yaml#/components/schemas/_Id'
|
|
||||||
properties:
|
|
||||||
parameters:
|
|
||||||
type: object
|
|
||||||
responses:
|
|
||||||
200:
|
|
||||||
description: condition details
|
|
||||||
content:
|
|
||||||
application/json:
|
|
||||||
schema:
|
|
||||||
$ref: 'api.yaml#/components/schemas/Condition'
|
|
||||||
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'
|
|
||||||
delete:
|
|
||||||
summary: delete condition
|
|
||||||
description: 'Auth: basic, levels: write, maintain, dev, admin'
|
|
||||||
x-doc: sets status to -1
|
|
||||||
tags:
|
|
||||||
- /condition
|
|
||||||
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:
|
|
||||||
$ref: 'api.yaml#/components/responses/500'
|
|
||||||
|
|
||||||
/condition/new:
|
|
||||||
post:
|
|
||||||
summary: add condition
|
|
||||||
description: 'Auth: basic, levels: write, maintain, dev, admin <br>Only maintain and admin are allowed to reference samples created by another user'
|
|
||||||
x-doc: 'Adds status: 0 automatically'
|
|
||||||
tags:
|
|
||||||
- /condition
|
|
||||||
security:
|
|
||||||
- BasicAuth: []
|
|
||||||
requestBody:
|
|
||||||
required: true
|
|
||||||
content:
|
|
||||||
application/json:
|
|
||||||
schema:
|
|
||||||
$ref: 'api.yaml#/components/schemas/Condition'
|
|
||||||
responses:
|
|
||||||
200:
|
|
||||||
description: condition details
|
|
||||||
content:
|
|
||||||
application/json:
|
|
||||||
schema:
|
|
||||||
$ref: 'api.yaml#/components/schemas/Condition'
|
|
||||||
400:
|
|
||||||
$ref: 'api.yaml#/components/responses/400'
|
|
||||||
401:
|
|
||||||
$ref: 'api.yaml#/components/responses/401'
|
|
||||||
403:
|
|
||||||
$ref: 'api.yaml#/components/responses/403'
|
|
||||||
500:
|
|
||||||
$ref: 'api.yaml#/components/responses/500'
|
|
@ -19,7 +19,7 @@
|
|||||||
500:
|
500:
|
||||||
$ref: 'api.yaml#/components/responses/500'
|
$ref: 'api.yaml#/components/responses/500'
|
||||||
|
|
||||||
/samples{group}:
|
/samples/{group}:
|
||||||
parameters:
|
parameters:
|
||||||
- $ref: 'api.yaml#/components/parameters/Group'
|
- $ref: 'api.yaml#/components/parameters/Group'
|
||||||
get:
|
get:
|
||||||
@ -48,7 +48,7 @@
|
|||||||
get:
|
get:
|
||||||
summary: TODO sample details
|
summary: TODO sample details
|
||||||
description: 'Auth: all, levels: read, write, maintain, dev, admin'
|
description: 'Auth: all, levels: read, write, maintain, dev, admin'
|
||||||
x-doc: status handling (accessible (only for maintain/admin))? # TODO after decision
|
x-doc: deleted samples are available only for maintain/admin
|
||||||
tags:
|
tags:
|
||||||
- /sample
|
- /sample
|
||||||
responses:
|
responses:
|
||||||
|
@ -24,6 +24,15 @@ SampleProperties:
|
|||||||
batch:
|
batch:
|
||||||
type: string
|
type: string
|
||||||
example: 1560237365
|
example: 1560237365
|
||||||
|
condition:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
condition_template:
|
||||||
|
$ref: 'api.yaml#/components/schemas/Id'
|
||||||
|
example:
|
||||||
|
condition_template: 5ea0450ed851c30a90e70894
|
||||||
|
material: hot air
|
||||||
|
weeks: 5
|
||||||
|
|
||||||
SampleRefs:
|
SampleRefs:
|
||||||
allOf:
|
allOf:
|
||||||
@ -55,7 +64,7 @@ Sample:
|
|||||||
type: array
|
type: array
|
||||||
items:
|
items:
|
||||||
properties:
|
properties:
|
||||||
id:
|
sample_id:
|
||||||
$ref: 'api.yaml#/components/schemas/Id'
|
$ref: 'api.yaml#/components/schemas/Id'
|
||||||
relation:
|
relation:
|
||||||
type: string
|
type: string
|
||||||
@ -67,7 +76,8 @@ SampleDetail:
|
|||||||
- $ref: 'api.yaml#/components/schemas/SampleProperties'
|
- $ref: 'api.yaml#/components/schemas/SampleProperties'
|
||||||
properties:
|
properties:
|
||||||
material:
|
material:
|
||||||
$ref: 'api.yaml#/components/schemas/Material'
|
allOf:
|
||||||
|
- $ref: 'api.yaml#/components/schemas/Material'
|
||||||
notes:
|
notes:
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
@ -77,10 +87,14 @@ SampleDetail:
|
|||||||
type: array
|
type: array
|
||||||
items:
|
items:
|
||||||
$ref: 'api.yaml#/components/schemas/Id'
|
$ref: 'api.yaml#/components/schemas/Id'
|
||||||
conditions:
|
measurements:
|
||||||
type: array
|
type: array
|
||||||
items:
|
items:
|
||||||
$ref: 'api.yaml#/components/schemas/Condition'
|
allOf:
|
||||||
|
- $ref: 'api.yaml#/components/schemas/Measurement'
|
||||||
|
user:
|
||||||
|
type: string
|
||||||
|
example: admin
|
||||||
|
|
||||||
Material:
|
Material:
|
||||||
allOf:
|
allOf:
|
||||||
@ -115,26 +129,11 @@ Material:
|
|||||||
type: string
|
type: string
|
||||||
example: 5514263423
|
example: 5514263423
|
||||||
|
|
||||||
Condition:
|
|
||||||
allOf:
|
|
||||||
- $ref: 'api.yaml#/components/schemas/_Id'
|
|
||||||
properties:
|
|
||||||
sample_id:
|
|
||||||
$ref: 'api.yaml#/components/schemas/Id'
|
|
||||||
number:
|
|
||||||
type: string
|
|
||||||
readOnly: true
|
|
||||||
example: B1
|
|
||||||
parameters:
|
|
||||||
type: object
|
|
||||||
treatment_template:
|
|
||||||
$ref: 'api.yaml#/components/schemas/Id'
|
|
||||||
|
|
||||||
Measurement:
|
Measurement:
|
||||||
allOf:
|
allOf:
|
||||||
- $ref: 'api.yaml#/components/schemas/_Id'
|
- $ref: 'api.yaml#/components/schemas/_Id'
|
||||||
properties:
|
properties:
|
||||||
condition_id:
|
sample_id:
|
||||||
$ref: 'api.yaml#/components/schemas/Id'
|
$ref: 'api.yaml#/components/schemas/Id'
|
||||||
values:
|
values:
|
||||||
type: object
|
type: object
|
||||||
@ -166,7 +165,7 @@ Template:
|
|||||||
min: 0
|
min: 0
|
||||||
max: 2
|
max: 2
|
||||||
|
|
||||||
TreatmentTemplate:
|
ConditionTemplate:
|
||||||
allOf:
|
allOf:
|
||||||
- $ref: 'api.yaml#/components/schemas/Template'
|
- $ref: 'api.yaml#/components/schemas/Template'
|
||||||
properties:
|
properties:
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/template/treatments:
|
/template/conditions:
|
||||||
get:
|
get:
|
||||||
summary: all available treatment methods
|
summary: all available condition methods
|
||||||
description: 'Auth: basic, levels: read, write, maintain, dev, admin'
|
description: 'Auth: basic, levels: read, write, maintain, dev, admin'
|
||||||
tags:
|
tags:
|
||||||
- /template
|
- /template
|
||||||
@ -8,23 +8,23 @@
|
|||||||
- BasicAuth: []
|
- BasicAuth: []
|
||||||
responses:
|
responses:
|
||||||
200:
|
200:
|
||||||
description: list of treatments
|
description: list of conditions
|
||||||
content:
|
content:
|
||||||
application/json:
|
application/json:
|
||||||
schema:
|
schema:
|
||||||
type: array
|
type: array
|
||||||
items:
|
items:
|
||||||
$ref: 'api.yaml#/components/schemas/TreatmentTemplate'
|
$ref: 'api.yaml#/components/schemas/ConditionTemplate'
|
||||||
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/{id}:
|
/template/condition/{id}:
|
||||||
parameters:
|
parameters:
|
||||||
- $ref: 'api.yaml#/components/parameters/Id'
|
- $ref: 'api.yaml#/components/parameters/Id'
|
||||||
get:
|
get:
|
||||||
summary: treatment method details
|
summary: condition method details
|
||||||
description: 'Auth: basic, levels: read, write, maintain, admin'
|
description: 'Auth: basic, levels: read, write, maintain, admin'
|
||||||
tags:
|
tags:
|
||||||
- /template
|
- /template
|
||||||
@ -32,11 +32,11 @@
|
|||||||
- BasicAuth: []
|
- BasicAuth: []
|
||||||
responses:
|
responses:
|
||||||
200:
|
200:
|
||||||
description: treatment details
|
description: condition details
|
||||||
content:
|
content:
|
||||||
application/json:
|
application/json:
|
||||||
schema:
|
schema:
|
||||||
$ref: 'api.yaml#/components/schemas/TreatmentTemplate'
|
$ref: 'api.yaml#/components/schemas/ConditionTemplate'
|
||||||
401:
|
401:
|
||||||
$ref: 'api.yaml#/components/responses/401'
|
$ref: 'api.yaml#/components/responses/401'
|
||||||
404:
|
404:
|
||||||
@ -44,7 +44,7 @@
|
|||||||
500:
|
500:
|
||||||
$ref: 'api.yaml#/components/responses/500'
|
$ref: 'api.yaml#/components/responses/500'
|
||||||
put:
|
put:
|
||||||
summary: change treatment method
|
summary: change condition method
|
||||||
description: 'Auth: basic, levels: maintain, admin'
|
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
|
x-doc: With a change a new version is set, resulting in a new template with a new id
|
||||||
tags:
|
tags:
|
||||||
@ -56,14 +56,14 @@
|
|||||||
content:
|
content:
|
||||||
application/json:
|
application/json:
|
||||||
schema:
|
schema:
|
||||||
$ref: 'api.yaml#/components/schemas/TreatmentTemplate'
|
$ref: 'api.yaml#/components/schemas/ConditionTemplate'
|
||||||
responses:
|
responses:
|
||||||
200:
|
200:
|
||||||
description: treatment details
|
description: condition details
|
||||||
content:
|
content:
|
||||||
application/json:
|
application/json:
|
||||||
schema:
|
schema:
|
||||||
$ref: 'api.yaml#/components/schemas/TreatmentTemplate'
|
$ref: 'api.yaml#/components/schemas/ConditionTemplate'
|
||||||
400:
|
400:
|
||||||
$ref: 'api.yaml#/components/responses/400'
|
$ref: 'api.yaml#/components/responses/400'
|
||||||
401:
|
401:
|
||||||
@ -75,9 +75,9 @@
|
|||||||
500:
|
500:
|
||||||
$ref: 'api.yaml#/components/responses/500'
|
$ref: 'api.yaml#/components/responses/500'
|
||||||
|
|
||||||
/template/treatment/new:
|
/template/condition/new:
|
||||||
post:
|
post:
|
||||||
summary: add treatment method
|
summary: add condition method
|
||||||
description: 'Auth: basic, levels: maintain, admin'
|
description: 'Auth: basic, levels: maintain, admin'
|
||||||
tags:
|
tags:
|
||||||
- /template
|
- /template
|
||||||
@ -88,14 +88,14 @@
|
|||||||
content:
|
content:
|
||||||
application/json:
|
application/json:
|
||||||
schema:
|
schema:
|
||||||
$ref: 'api.yaml#/components/schemas/TreatmentTemplate'
|
$ref: 'api.yaml#/components/schemas/ConditionTemplate'
|
||||||
responses:
|
responses:
|
||||||
200:
|
200:
|
||||||
description: treatment details
|
description: condition details
|
||||||
content:
|
content:
|
||||||
application/json:
|
application/json:
|
||||||
schema:
|
schema:
|
||||||
$ref: 'api.yaml#/components/schemas/TreatmentTemplate'
|
$ref: 'api.yaml#/components/schemas/ConditionTemplate'
|
||||||
400:
|
400:
|
||||||
$ref: 'api.yaml#/components/responses/400'
|
$ref: 'api.yaml#/components/responses/400'
|
||||||
401:
|
401:
|
||||||
|
976
package-lock.json
generated
976
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -5,10 +5,12 @@
|
|||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"tsc": "tsc",
|
"tsc": "tsc",
|
||||||
|
"tsc-full": "del /q dist\\* & (for /d %x in (dist\\*) do @rd /s /q \"%x\") & tsc",
|
||||||
"test": "mocha dist/**/**.spec.js",
|
"test": "mocha dist/**/**.spec.js",
|
||||||
"start": "tsc && node dist/index.js || exit 1",
|
"start": "tsc && node dist/index.js || exit 1",
|
||||||
"dev": "nodemon -e ts,yaml --exec \"npm run start\"",
|
"dev": "nodemon -e ts,yaml --exec \"npm run start\"",
|
||||||
"loadDev": "node dist/test/loadDev.js"
|
"loadDev": "node dist/test/loadDev.js",
|
||||||
|
"coverage": "tsc && nyc --reporter=html --reporter=text mocha dist/**/**.spec.js --timeout 5000"
|
||||||
},
|
},
|
||||||
"keywords": [],
|
"keywords": [],
|
||||||
"author": "",
|
"author": "",
|
||||||
@ -44,6 +46,7 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/lodash": "^4.14.150",
|
"@types/lodash": "^4.14.150",
|
||||||
"mocha": "^7.1.2",
|
"mocha": "^7.1.2",
|
||||||
|
"nyc": "^15.0.1",
|
||||||
"should": "^13.2.3",
|
"should": "^13.2.3",
|
||||||
"supertest": "^4.0.2"
|
"supertest": "^4.0.2"
|
||||||
}
|
}
|
||||||
|
13
src/db.ts
13
src/db.ts
@ -42,15 +42,18 @@ export default class db {
|
|||||||
});
|
});
|
||||||
mongoose.connection.on('error', console.error.bind(console, 'connection error:'));
|
mongoose.connection.on('error', console.error.bind(console, 'connection error:'));
|
||||||
mongoose.connection.on('disconnected', () => { // reset state on disconnect
|
mongoose.connection.on('disconnected', () => { // reset state on disconnect
|
||||||
|
if (process.env.NODE_ENV !== 'test') { // Do not interfere with testing
|
||||||
console.info('Database disconnected');
|
console.info('Database disconnected');
|
||||||
this.state.db = 0;
|
this.state.db = 0;
|
||||||
done();
|
}
|
||||||
});
|
});
|
||||||
process.on('SIGINT', () => { // close connection when app is terminated
|
process.on('SIGINT', () => { // close connection when app is terminated
|
||||||
|
if (!this.state.db) { // database still connected
|
||||||
mongoose.connection.close(() => {
|
mongoose.connection.close(() => {
|
||||||
console.info('Mongoose default connection disconnected through app termination');
|
console.info('Mongoose default connection disconnected through app termination');
|
||||||
process.exit(0);
|
process.exit(0);
|
||||||
});
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
mongoose.connection.once('open', () => {
|
mongoose.connection.once('open', () => {
|
||||||
mongoose.set('useFindAndModify', false);
|
mongoose.set('useFindAndModify', false);
|
||||||
@ -60,6 +63,14 @@ export default class db {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static disconnect (done) {
|
||||||
|
mongoose.connection.close(() => {
|
||||||
|
console.info(process.env.NODE_ENV === 'test' ? '' : `Disconnected from database`);
|
||||||
|
this.state.db = 0;
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
static getState () {
|
static getState () {
|
||||||
return this.state;
|
return this.state;
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,13 @@ const globals = {
|
|||||||
'maintain',
|
'maintain',
|
||||||
'dev',
|
'dev',
|
||||||
'admin'
|
'admin'
|
||||||
]
|
],
|
||||||
|
|
||||||
|
status: { // document statuses
|
||||||
|
deleted: -1,
|
||||||
|
new: 0,
|
||||||
|
validated: 10,
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export default globals;
|
export default globals;
|
25
src/index.ts
25
src/index.ts
@ -11,6 +11,9 @@ import db from './db';
|
|||||||
// TODO: validation: VZ, Humidity: min/max value, DPT: filename
|
// TODO: validation: VZ, Humidity: min/max value, DPT: filename
|
||||||
// TODO: condition values not needed on initial add
|
// TODO: condition values not needed on initial add
|
||||||
// TODO: add multiple samples at once
|
// TODO: add multiple samples at once
|
||||||
|
// TODO: coverage
|
||||||
|
// TODO: think about the display of deleted/new samples and validation in data and UI
|
||||||
|
// TODO: improve error coverage
|
||||||
|
|
||||||
// tell if server is running in debug or production environment
|
// tell if server is running in debug or production environment
|
||||||
console.info(process.env.NODE_ENV === 'production' ? '===== PRODUCTION =====' : process.env.NODE_ENV === 'test' ? '' :'===== DEVELOPMENT =====');
|
console.info(process.env.NODE_ENV === 'production' ? '===== PRODUCTION =====' : process.env.NODE_ENV === 'test' ? '' :'===== DEVELOPMENT =====');
|
||||||
@ -48,14 +51,22 @@ app.use((req, res, next) => { // no database connection error
|
|||||||
});
|
});
|
||||||
app.use(require('./helpers/authorize')); // handle authentication
|
app.use(require('./helpers/authorize')); // handle authentication
|
||||||
|
|
||||||
|
// redirect /api routes for Angular proxy in development
|
||||||
|
if (process.env.NODE_ENV !== 'production') {
|
||||||
|
app.use('/api/:url', (req, res) => {
|
||||||
|
req.url = '/' + req.params.url;
|
||||||
|
app.handle(req, res);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// require routes
|
// require routes
|
||||||
app.use('/api', require('./routes/root'));
|
app.use('/', require('./routes/root'));
|
||||||
app.use('/api', require('./routes/sample'));
|
app.use('/', require('./routes/sample'));
|
||||||
app.use('/api', require('./routes/material'));
|
app.use('/', require('./routes/material'));
|
||||||
app.use('/api', require('./routes/template'));
|
app.use('/', require('./routes/template'));
|
||||||
app.use('/api', require('./routes/user'));
|
app.use('/', require('./routes/user'));
|
||||||
app.use('/api', require('./routes/condition'));
|
app.use('/', require('./routes/measurement'));
|
||||||
app.use('/api', require('./routes/measurement'));
|
|
||||||
|
|
||||||
// static files
|
// static files
|
||||||
app.use('/static', express.static('static'));
|
app.use('/static', express.static('static'));
|
||||||
|
@ -1,13 +0,0 @@
|
|||||||
import mongoose from 'mongoose';
|
|
||||||
import SampleModel from './sample';
|
|
||||||
import TreatmentTemplateModel from './treatment_template';
|
|
||||||
|
|
||||||
const ConditionSchema = new mongoose.Schema({
|
|
||||||
sample_id: {type: mongoose.Schema.Types.ObjectId, ref: SampleModel},
|
|
||||||
number: String,
|
|
||||||
parameters: mongoose.Schema.Types.Mixed,
|
|
||||||
treatment_template: {type: mongoose.Schema.Types.ObjectId, ref: TreatmentTemplateModel},
|
|
||||||
status: Number
|
|
||||||
});
|
|
||||||
|
|
||||||
export default mongoose.model('condition', ConditionSchema);
|
|
@ -1,13 +1,12 @@
|
|||||||
import mongoose from 'mongoose';
|
import mongoose from 'mongoose';
|
||||||
|
|
||||||
const TreatmentTemplateSchema = new mongoose.Schema({
|
const ConditionTemplateSchema = new mongoose.Schema({
|
||||||
name: String,
|
name: String,
|
||||||
version: Number,
|
version: Number,
|
||||||
number_prefix: String,
|
|
||||||
parameters: [{
|
parameters: [{
|
||||||
name: String,
|
name: String,
|
||||||
range: mongoose.Schema.Types.Mixed
|
range: mongoose.Schema.Types.Mixed
|
||||||
}]
|
}]
|
||||||
}, {minimize: false}); // to allow empty objects
|
}, {minimize: false}); // to allow empty objects
|
||||||
|
|
||||||
export default mongoose.model('treatment_template', TreatmentTemplateSchema);
|
export default mongoose.model('condition_template', ConditionTemplateSchema);
|
@ -1,12 +1,14 @@
|
|||||||
import mongoose from 'mongoose';
|
import mongoose from 'mongoose';
|
||||||
import ConditionModel from './condition';
|
import SampleModel from './sample';
|
||||||
import MeasurementTemplateModel from './measurement_template';
|
import MeasurementTemplateModel from './measurement_template';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const MeasurementSchema = new mongoose.Schema({
|
const MeasurementSchema = new mongoose.Schema({
|
||||||
condition_id: {type: mongoose.Schema.Types.ObjectId, ref: ConditionModel},
|
sample_id: {type: mongoose.Schema.Types.ObjectId, ref: SampleModel},
|
||||||
values: mongoose.Schema.Types.Mixed,
|
values: mongoose.Schema.Types.Mixed,
|
||||||
measurement_template: {type: mongoose.Schema.Types.ObjectId, ref: MeasurementTemplateModel},
|
measurement_template: {type: mongoose.Schema.Types.ObjectId, ref: MeasurementTemplateModel},
|
||||||
status: Number
|
status: Number
|
||||||
});
|
}, {minimize: false});
|
||||||
|
|
||||||
export default mongoose.model('measurement', MeasurementSchema);
|
export default mongoose.model('measurement', MeasurementSchema);
|
@ -3,7 +3,7 @@ import mongoose from 'mongoose';
|
|||||||
const NoteSchema = new mongoose.Schema({
|
const NoteSchema = new mongoose.Schema({
|
||||||
comment: String,
|
comment: String,
|
||||||
sample_references: [{
|
sample_references: [{
|
||||||
id: mongoose.Schema.Types.ObjectId,
|
sample_id: mongoose.Schema.Types.ObjectId,
|
||||||
relation: String
|
relation: String
|
||||||
}],
|
}],
|
||||||
custom_fields: mongoose.Schema.Types.Mixed
|
custom_fields: mongoose.Schema.Types.Mixed
|
||||||
|
@ -9,10 +9,11 @@ const SampleSchema = new mongoose.Schema({
|
|||||||
type: String,
|
type: String,
|
||||||
color: String,
|
color: String,
|
||||||
batch: String,
|
batch: String,
|
||||||
|
condition: mongoose.Schema.Types.Mixed,
|
||||||
material_id: {type: mongoose.Schema.Types.ObjectId, ref: MaterialModel},
|
material_id: {type: mongoose.Schema.Types.ObjectId, ref: MaterialModel},
|
||||||
note_id: {type: mongoose.Schema.Types.ObjectId, ref: NoteModel},
|
note_id: {type: mongoose.Schema.Types.ObjectId, ref: NoteModel},
|
||||||
user_id: {type: mongoose.Schema.Types.ObjectId, ref: UserModel},
|
user_id: {type: mongoose.Schema.Types.ObjectId, ref: UserModel},
|
||||||
status: Number
|
status: Number
|
||||||
});
|
}, {minimize: false});
|
||||||
|
|
||||||
export default mongoose.model('sample', SampleSchema);
|
export default mongoose.model('sample', SampleSchema);
|
@ -1,583 +0,0 @@
|
|||||||
import should from 'should/as-function';
|
|
||||||
import ConditionModel from '../models/condition';
|
|
||||||
import TestHelper from "../test/helper";
|
|
||||||
|
|
||||||
// TODO: adding conditions allowed only for m/a
|
|
||||||
// TODO: deleted data only visible for m/a
|
|
||||||
// TODO: restore deleted
|
|
||||||
// TODO: remove number_prefix
|
|
||||||
|
|
||||||
describe('/condition', () => {
|
|
||||||
let server;
|
|
||||||
before(done => TestHelper.before(done));
|
|
||||||
beforeEach(done => server = TestHelper.beforeEach(server, done));
|
|
||||||
afterEach(done => TestHelper.afterEach(server, done));
|
|
||||||
|
|
||||||
describe('GET /condition/{id}', () => {
|
|
||||||
it('returns the right condition', done => {
|
|
||||||
TestHelper.request(server, done, {
|
|
||||||
method: 'get',
|
|
||||||
url: '/condition/700000000000000000000001',
|
|
||||||
auth: {basic: 'janedoe'},
|
|
||||||
httpStatus: 200,
|
|
||||||
res: {_id: '700000000000000000000001', sample_id: '400000000000000000000001', number: 'A1', parameters: {material: 'copper', weeks: 3}, treatment_template: '200000000000000000000001'}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
it('returns the right condition for an API key', done => {
|
|
||||||
TestHelper.request(server, done, {
|
|
||||||
method: 'get',
|
|
||||||
url: '/condition/700000000000000000000001',
|
|
||||||
auth: {key: 'janedoe'},
|
|
||||||
httpStatus: 200,
|
|
||||||
res: {_id: '700000000000000000000001', sample_id: '400000000000000000000001', number: 'A1', parameters: {material: 'copper', weeks: 3}, treatment_template: '200000000000000000000001'}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
it('rejects an invalid id', done => {
|
|
||||||
TestHelper.request(server, done, {
|
|
||||||
method: 'get',
|
|
||||||
url: '/condition/70000000000t000000000001',
|
|
||||||
auth: {basic: 'janedoe'},
|
|
||||||
httpStatus: 404
|
|
||||||
});
|
|
||||||
});
|
|
||||||
it('rejects an unknown id', done => {
|
|
||||||
TestHelper.request(server, done, {
|
|
||||||
method: 'get',
|
|
||||||
url: '/condition/000000000000000000000001',
|
|
||||||
auth: {basic: 'janedoe'},
|
|
||||||
httpStatus: 404
|
|
||||||
});
|
|
||||||
});
|
|
||||||
it('rejects unauthorized requests', done => {
|
|
||||||
TestHelper.request(server, done, {
|
|
||||||
method: 'get',
|
|
||||||
url: '/condition/700000000000000000000001',
|
|
||||||
httpStatus: 401
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('PUT /condition{id}', () => {
|
|
||||||
it('returns the right condition', done => {
|
|
||||||
TestHelper.request(server, done, {
|
|
||||||
method: 'put',
|
|
||||||
url: '/condition/700000000000000000000001',
|
|
||||||
auth: {basic: 'janedoe'},
|
|
||||||
httpStatus: 200,
|
|
||||||
req: {},
|
|
||||||
res: {_id: '700000000000000000000001', sample_id: '400000000000000000000001', number: 'A1', treatment_template: '200000000000000000000001', parameters: {material: 'copper', weeks: 3}}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
it('keeps unchanged properties', done => {
|
|
||||||
TestHelper.request(server, done, {
|
|
||||||
method: 'put',
|
|
||||||
url: '/condition/700000000000000000000001',
|
|
||||||
auth: {basic: 'janedoe'},
|
|
||||||
httpStatus: 200,
|
|
||||||
req: {parameters: {material: 'copper', weeks: 3}}
|
|
||||||
}).end((err, res) => {
|
|
||||||
if (err) return done(err);
|
|
||||||
should(res.body).be.eql({_id: '700000000000000000000001', sample_id: '400000000000000000000001', number: 'A1', treatment_template: '200000000000000000000001', parameters: {material: 'copper', weeks: 3}});
|
|
||||||
ConditionModel.findById('700000000000000000000001').lean().exec((err, data) => {
|
|
||||||
if (err) return done(err);
|
|
||||||
should(data).have.property('status', 10);
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
it('keeps only one unchanged parameter', done => {
|
|
||||||
TestHelper.request(server, done, {
|
|
||||||
method: 'put',
|
|
||||||
url: '/condition/700000000000000000000001',
|
|
||||||
auth: {basic: 'janedoe'},
|
|
||||||
httpStatus: 200,
|
|
||||||
req: {parameters: {material: 'copper'}}
|
|
||||||
}).end((err, res) => {
|
|
||||||
if (err) return done(err);
|
|
||||||
should(res.body).be.eql({_id: '700000000000000000000001', sample_id: '400000000000000000000001', number: 'A1', treatment_template: '200000000000000000000001', parameters: {material: 'copper', weeks: 3}});
|
|
||||||
ConditionModel.findById('700000000000000000000001').lean().exec((err, data) => {
|
|
||||||
if (err) return done(err);
|
|
||||||
should(data).have.property('status', 10);
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
it('changes the given properties', done => {
|
|
||||||
TestHelper.request(server, done, {
|
|
||||||
method: 'put',
|
|
||||||
url: '/condition/700000000000000000000001',
|
|
||||||
auth: {basic: 'janedoe'},
|
|
||||||
httpStatus: 200,
|
|
||||||
req: {parameters: {material: 'hot air', weeks: 10}}
|
|
||||||
}).end((err, res) => {
|
|
||||||
if (err) return done(err);
|
|
||||||
should(res.body).be.eql({_id: '700000000000000000000001', sample_id: '400000000000000000000001', number: 'A1', treatment_template: '200000000000000000000001', parameters: {material: 'hot air', weeks: 10}});
|
|
||||||
ConditionModel.findById('700000000000000000000001').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('400000000000000000000001');
|
|
||||||
should(data).have.property('number', 'A1');
|
|
||||||
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('allows changing only one parameter', done => {
|
|
||||||
TestHelper.request(server, done, {
|
|
||||||
method: 'put',
|
|
||||||
url: '/condition/700000000000000000000001',
|
|
||||||
auth: {basic: 'janedoe'},
|
|
||||||
httpStatus: 200,
|
|
||||||
req: {parameters: {weeks: 8}},
|
|
||||||
res: {_id: '700000000000000000000001', sample_id: '400000000000000000000001', number: 'A1', treatment_template: '200000000000000000000001', parameters: {material: 'copper', weeks: 8}}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
it('rejects changing the condition number', done => {
|
|
||||||
TestHelper.request(server, done, {
|
|
||||||
method: 'put',
|
|
||||||
url: '/condition/700000000000000000000001',
|
|
||||||
auth: {basic: 'janedoe'},
|
|
||||||
httpStatus: 400,
|
|
||||||
req: {number: 'C2'},
|
|
||||||
res: {status: 'Invalid body format', details: '"number" is not allowed'}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
it('rejects not specified parameters', done => {
|
|
||||||
TestHelper.request(server, done, {
|
|
||||||
method: 'put',
|
|
||||||
url: '/condition/700000000000000000000001',
|
|
||||||
auth: {basic: 'janedoe'},
|
|
||||||
httpStatus: 400,
|
|
||||||
req: {parameters: {xx: 13}},
|
|
||||||
res: {status: 'Invalid body format', details: '"xx" is not allowed'}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
it('rejects a parameter not in the value range', done => {
|
|
||||||
TestHelper.request(server, done, {
|
|
||||||
method: 'put',
|
|
||||||
url: '/condition/700000000000000000000001',
|
|
||||||
auth: {basic: 'janedoe'},
|
|
||||||
httpStatus: 400,
|
|
||||||
req: {parameters: {material: 'xxx'}},
|
|
||||||
res: {status: 'Invalid body format', details: '"material" must be one of [copper, hot air]'}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
it('rejects a parameter below minimum range', done => {
|
|
||||||
TestHelper.request(server, done, {
|
|
||||||
method: 'put',
|
|
||||||
url: '/condition/700000000000000000000001',
|
|
||||||
auth: {basic: 'janedoe'},
|
|
||||||
httpStatus: 400,
|
|
||||||
req: {parameters: {weeks: -10}},
|
|
||||||
res: {status: 'Invalid body format', details: '"weeks" must be larger than or equal to 1'}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
it('rejects a parameter above maximum range', done => {
|
|
||||||
TestHelper.request(server, done, {
|
|
||||||
method: 'put',
|
|
||||||
url: '/condition/700000000000000000000001',
|
|
||||||
auth: {basic: 'janedoe'},
|
|
||||||
httpStatus: 400,
|
|
||||||
req: {parameters: {weeks: 11}},
|
|
||||||
res: {status: 'Invalid body format', details: '"weeks" must be less than or equal to 10'}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
it('rejects a new treatment_template', done => {
|
|
||||||
TestHelper.request(server, done, {
|
|
||||||
method: 'put',
|
|
||||||
url: '/condition/700000000000000000000001',
|
|
||||||
auth: {basic: 'janedoe'},
|
|
||||||
httpStatus: 400,
|
|
||||||
req: {treatment_template: '200000000000000000000002'},
|
|
||||||
res: {status: 'Invalid body format', details: '"treatment_template" is not allowed'}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
it('rejects editing a condition for a write user who did not create this condition', done => {
|
|
||||||
TestHelper.request(server, done, {
|
|
||||||
method: 'put',
|
|
||||||
url: '/condition/700000000000000000000003',
|
|
||||||
auth: {basic: 'janedoe'},
|
|
||||||
httpStatus: 403,
|
|
||||||
req: {parameters: {weeks: 8}}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
it('accepts editing a condition of another user for a maintain/admin user', done => {
|
|
||||||
TestHelper.request(server, done, {
|
|
||||||
method: 'put',
|
|
||||||
url: '/condition/700000000000000000000001',
|
|
||||||
auth: {basic: 'admin'},
|
|
||||||
httpStatus: 200,
|
|
||||||
req: {parameters: {material: 'hot air', weeks: 10}},
|
|
||||||
res: {_id: '700000000000000000000001', sample_id: '400000000000000000000001', number: 'A1', treatment_template: '200000000000000000000001', parameters: {material: 'hot air', weeks: 10}}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
it('rejects an API key', done => {
|
|
||||||
TestHelper.request(server, done, {
|
|
||||||
method: 'put',
|
|
||||||
url: '/condition/700000000000000000000001',
|
|
||||||
auth: {key: 'janedoe'},
|
|
||||||
httpStatus: 401,
|
|
||||||
req: {parameters: {material: 'hot air', weeks: 10}}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
it('rejects requests from a read user', done => {
|
|
||||||
TestHelper.request(server, done, {
|
|
||||||
method: 'put',
|
|
||||||
url: '/condition/700000000000000000000001',
|
|
||||||
auth: {basic: 'user'},
|
|
||||||
httpStatus: 403,
|
|
||||||
req: {parameters: {material: 'hot air', weeks: 10}}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
it('rejects unauthorized requests', done => {
|
|
||||||
TestHelper.request(server, done, {
|
|
||||||
method: 'put',
|
|
||||||
url: '/condition/700000000000000000000001',
|
|
||||||
httpStatus: 401,
|
|
||||||
req: {parameters: {material: 'hot air', weeks: 10}}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('DELETE /condition/{id}', () => {
|
|
||||||
it('sets the status to deleted', done => {
|
|
||||||
TestHelper.request(server, done, {
|
|
||||||
method: 'delete',
|
|
||||||
url: '/condition/700000000000000000000004',
|
|
||||||
auth: {basic: 'janedoe'},
|
|
||||||
httpStatus: 200
|
|
||||||
}).end((err, res) => {
|
|
||||||
if (err) return done(err);
|
|
||||||
should(res.body).be.eql({status: 'OK'});
|
|
||||||
ConditionModel.findById('700000000000000000000004').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('400000000000000000000001');
|
|
||||||
should(data).have.property('number', 'A2');
|
|
||||||
should(data.treatment_template.toString()).be.eql('200000000000000000000001');
|
|
||||||
should(data).have.property('status', -1);
|
|
||||||
should(data).have.property('parameters');
|
|
||||||
should(data.parameters).have.property('material', 'hot air');
|
|
||||||
should(data.parameters).have.property('weeks', 5);
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
it('rejects deleting a condition referenced by measurements'/*, done => {
|
|
||||||
TestHelper.request(server, done, {
|
|
||||||
method: 'delete',
|
|
||||||
url: '/condition/700000000000000000000002',
|
|
||||||
auth: {basic: 'janedoe'},
|
|
||||||
httpStatus: 200,
|
|
||||||
res: {status: 'Condition still in use'}
|
|
||||||
});
|
|
||||||
}*/); // TODO after decision
|
|
||||||
it('rejects an invalid id', done => {
|
|
||||||
TestHelper.request(server, done, {
|
|
||||||
method: 'delete',
|
|
||||||
url: '/condition/70000000000w000000000002',
|
|
||||||
auth: {basic: 'janedoe'},
|
|
||||||
httpStatus: 404
|
|
||||||
});
|
|
||||||
});
|
|
||||||
it('rejects an API key', done => {
|
|
||||||
TestHelper.request(server, done, {
|
|
||||||
method: 'delete',
|
|
||||||
url: '/condition/700000000000000000000004',
|
|
||||||
auth: {key: 'janedoe'},
|
|
||||||
httpStatus: 401
|
|
||||||
});
|
|
||||||
});
|
|
||||||
it('rejects requests from a read user', done => {
|
|
||||||
TestHelper.request(server, done, {
|
|
||||||
method: 'delete',
|
|
||||||
url: '/condition/700000000000000000000004',
|
|
||||||
auth: {basic: 'user'},
|
|
||||||
httpStatus: 403
|
|
||||||
});
|
|
||||||
});
|
|
||||||
it('rejects a write user deleting a condition belonging to a sample of another user', done => {
|
|
||||||
TestHelper.request(server, done, {
|
|
||||||
method: 'delete',
|
|
||||||
url: '/condition/700000000000000000000003',
|
|
||||||
auth: {basic: 'janedoe'},
|
|
||||||
httpStatus: 403
|
|
||||||
});
|
|
||||||
});
|
|
||||||
it('accepts an maintain/admin user deleting a condition belonging to a sample of another user', done => {
|
|
||||||
TestHelper.request(server, done, {
|
|
||||||
method: 'delete',
|
|
||||||
url: '/condition/700000000000000000000004',
|
|
||||||
auth: {basic: 'admin'},
|
|
||||||
httpStatus: 200
|
|
||||||
}).end((err, res) => {
|
|
||||||
if (err) return done(err);
|
|
||||||
should(res.body).be.eql({status: 'OK'});
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
it('returns 404 for an unknown id', done => {
|
|
||||||
TestHelper.request(server, done, {
|
|
||||||
method: 'delete',
|
|
||||||
url: '/condition/000000000000000000000002',
|
|
||||||
auth: {basic: 'janedoe'},
|
|
||||||
httpStatus: 404
|
|
||||||
});
|
|
||||||
});
|
|
||||||
it('rejects unauthorized requests', done => {
|
|
||||||
TestHelper.request(server, done, {
|
|
||||||
method: 'delete',
|
|
||||||
url: '/condition/700000000000000000000004',
|
|
||||||
httpStatus: 401
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('POST /condition/new', () => {
|
|
||||||
it('returns the right condition', done => {
|
|
||||||
TestHelper.request(server, done, {
|
|
||||||
method: 'post',
|
|
||||||
url: '/condition/new',
|
|
||||||
auth: {basic: 'janedoe'},
|
|
||||||
httpStatus: 200,
|
|
||||||
req: {sample_id: '400000000000000000000002', parameters: {material: 'hot air', weeks: 10}, treatment_template: '200000000000000000000001'}
|
|
||||||
}).end((err, res) => {
|
|
||||||
if (err) return done(err);
|
|
||||||
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('sample_id', '400000000000000000000002');
|
|
||||||
should(res.body).have.property('number', 'A2');
|
|
||||||
should(res.body).have.property('treatment_template', '200000000000000000000001');
|
|
||||||
should(res.body).have.property('parameters');
|
|
||||||
should(res.body.parameters).have.property('material', 'hot air');
|
|
||||||
should(res.body.parameters).have.property('weeks', 10);
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
it('stores the condition', done => {
|
|
||||||
TestHelper.request(server, done, {
|
|
||||||
method: 'post',
|
|
||||||
url: '/condition/new',
|
|
||||||
auth: {basic: 'janedoe'},
|
|
||||||
httpStatus: 200,
|
|
||||||
req: {sample_id: '400000000000000000000002', 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('400000000000000000000002');
|
|
||||||
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).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('rejects an invalid sample id', done => {
|
|
||||||
TestHelper.request(server, done, {
|
|
||||||
method: 'post',
|
|
||||||
url: '/condition/new',
|
|
||||||
auth: {basic: 'janedoe'},
|
|
||||||
httpStatus: 400,
|
|
||||||
req: {sample_id: '4000000000h0000000000002', parameters: {material: 'hot air', weeks: 10}, treatment_template: '200000000000000000000001'},
|
|
||||||
res: {status: 'Invalid body format', details: '"sample_id" with value "4000000000h0000000000002" fails to match the required pattern: /[0-9a-f]{24}/'}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
it('rejects a sample id not available', done => {
|
|
||||||
TestHelper.request(server, done, {
|
|
||||||
method: 'post',
|
|
||||||
url: '/condition/new',
|
|
||||||
auth: {basic: 'janedoe'},
|
|
||||||
httpStatus: 400,
|
|
||||||
req: {sample_id: '000000000000000000000002', parameters: {material: 'hot air', weeks: 10}, treatment_template: '200000000000000000000001'},
|
|
||||||
res: {status: 'Sample id not available'}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
it('rejects an invalid treatment_template id', done => {
|
|
||||||
TestHelper.request(server, done, {
|
|
||||||
method: 'post',
|
|
||||||
url: '/condition/new',
|
|
||||||
auth: {basic: 'janedoe'},
|
|
||||||
httpStatus: 400,
|
|
||||||
req: {sample_id: '400000000000000000000002', parameters: {material: 'hot air', weeks: 10}, treatment_template: '200000000000h00000000001'},
|
|
||||||
res: {status: 'Invalid body format', details: '"treatment_template" with value "200000000000h00000000001" fails to match the required pattern: /[0-9a-f]{24}/'}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
it('rejects a treatment_template which does not exist', done => {
|
|
||||||
TestHelper.request(server, done, {
|
|
||||||
method: 'post',
|
|
||||||
url: '/condition/new',
|
|
||||||
auth: {basic: 'janedoe'},
|
|
||||||
httpStatus: 400,
|
|
||||||
req: {sample_id: '400000000000000000000002', parameters: {material: 'hot air', weeks: 10}, treatment_template: '000000000000000000000001'},
|
|
||||||
res: {status: 'Treatment template not available'}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
it('rejects setting a condition number', done => {
|
|
||||||
TestHelper.request(server, done, {
|
|
||||||
method: 'post',
|
|
||||||
url: '/condition/new',
|
|
||||||
auth: {basic: 'janedoe'},
|
|
||||||
httpStatus: 400,
|
|
||||||
req: {sample_id: '400000000000000000000001', number: 'A7', parameters: {material: 'hot air', weeks: 10}, treatment_template: '200000000000000000000001'},
|
|
||||||
res: {status: 'Invalid body format', details: '"number" is not allowed'}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
it('rejects not specified parameters', done => {
|
|
||||||
TestHelper.request(server, done, {
|
|
||||||
method: 'post',
|
|
||||||
url: '/condition/new',
|
|
||||||
auth: {basic: 'janedoe'},
|
|
||||||
httpStatus: 400,
|
|
||||||
req: {sample_id: '400000000000000000000002', parameters: {material: 'hot air', weeks: 10, xx: 12}, treatment_template: '200000000000000000000001'},
|
|
||||||
res: {status: 'Invalid body format', details: '"xx" is not allowed'}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
it('rejects missing parameters', done => {
|
|
||||||
TestHelper.request(server, done, {
|
|
||||||
method: 'post',
|
|
||||||
url: '/condition/new',
|
|
||||||
auth: {basic: 'janedoe'},
|
|
||||||
httpStatus: 400,
|
|
||||||
req: {sample_id: '400000000000000000000002', parameters: {material: 'hot air'}, treatment_template: '200000000000000000000001'},
|
|
||||||
res: {status: 'Invalid body format', details: '"weeks" is required'}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
it('rejects a parameter not in the value range', done => {
|
|
||||||
TestHelper.request(server, done, {
|
|
||||||
method: 'post',
|
|
||||||
url: '/condition/new',
|
|
||||||
auth: {basic: 'janedoe'},
|
|
||||||
httpStatus: 400,
|
|
||||||
req: {sample_id: '400000000000000000000002', parameters: {material: 'xxx', weeks: 10}, treatment_template: '200000000000000000000001'},
|
|
||||||
res: {status: 'Invalid body format', details: '"material" must be one of [copper, hot air]'}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
it('rejects a parameter below minimum range', done => {
|
|
||||||
TestHelper.request(server, done, {
|
|
||||||
method: 'post',
|
|
||||||
url: '/condition/new',
|
|
||||||
auth: {basic: 'janedoe'},
|
|
||||||
httpStatus: 400,
|
|
||||||
req: {sample_id: '400000000000000000000002', parameters: {material: 'hot air', weeks: -10}, treatment_template: '200000000000000000000001'},
|
|
||||||
res: {status: 'Invalid body format', details: '"weeks" must be larger than or equal to 1'}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
it('rejects a parameter above maximum range', done => {
|
|
||||||
TestHelper.request(server, done, {
|
|
||||||
method: 'post',
|
|
||||||
url: '/condition/new',
|
|
||||||
auth: {basic: 'janedoe'},
|
|
||||||
httpStatus: 400,
|
|
||||||
req: {sample_id: '400000000000000000000002', parameters: {material: 'hot air', weeks: 11}, treatment_template: '200000000000000000000001'},
|
|
||||||
res: {status: 'Invalid body format', details: '"weeks" must be less than or equal to 10'}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
it('rejects a missing sample id', done => {
|
|
||||||
TestHelper.request(server, done, {
|
|
||||||
method: 'post',
|
|
||||||
url: '/condition/new',
|
|
||||||
auth: {basic: 'janedoe'},
|
|
||||||
httpStatus: 400,
|
|
||||||
req: {parameters: {material: 'hot air', weeks: 10}, treatment_template: '200000000000000000000001'},
|
|
||||||
res: {status: 'Invalid body format', details: '"sample_id" is required'}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
it('rejects a missing treatment_template', done => {
|
|
||||||
TestHelper.request(server, done, {
|
|
||||||
method: 'post',
|
|
||||||
url: '/condition/new',
|
|
||||||
auth: {basic: 'janedoe'},
|
|
||||||
httpStatus: 400,
|
|
||||||
req: {sample_id: '400000000000000000000002', parameters: {material: 'hot air', weeks: 10}},
|
|
||||||
res: {status: 'Invalid body format', details: '"treatment_template" is required'}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
it('rejects adding a condition to the sample of an other user for a write user', done => {
|
|
||||||
TestHelper.request(server, done, {
|
|
||||||
method: 'post',
|
|
||||||
url: '/condition/new',
|
|
||||||
auth: {basic: 'janedoe'},
|
|
||||||
httpStatus: 403,
|
|
||||||
req: {sample_id: '400000000000000000000003', parameters: {material: 'hot air', weeks: 10}, treatment_template: '200000000000000000000001'}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
it('accepts adding a condition to the sample of an other user for a maintain/admin user', done => {
|
|
||||||
TestHelper.request(server, done, {
|
|
||||||
method: 'post',
|
|
||||||
url: '/condition/new',
|
|
||||||
auth: {basic: 'admin'},
|
|
||||||
httpStatus: 200,
|
|
||||||
req: {sample_id: '400000000000000000000002', parameters: {material: 'hot air', weeks: 10}, treatment_template: '200000000000000000000001'}
|
|
||||||
}).end((err, res) => {
|
|
||||||
if (err) return done(err);
|
|
||||||
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('sample_id', '400000000000000000000002');
|
|
||||||
should(res.body).have.property('number', 'A2');
|
|
||||||
should(res.body).have.property('treatment_template', '200000000000000000000001');
|
|
||||||
should(res.body).have.property('parameters');
|
|
||||||
should(res.body.parameters).have.property('material', 'hot air');
|
|
||||||
should(res.body.parameters).have.property('weeks', 10);
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
it('rejects an API key', done => {
|
|
||||||
TestHelper.request(server, done, {
|
|
||||||
method: 'post',
|
|
||||||
url: '/condition/new',
|
|
||||||
auth: {key: 'janedoe'},
|
|
||||||
httpStatus: 401,
|
|
||||||
req: {sample_id: '400000000000000000000002', parameters: {material: 'hot air', weeks: 10}, treatment_template: '200000000000000000000001'}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
it('rejects requests from a read user', done => {
|
|
||||||
TestHelper.request(server, done, {
|
|
||||||
method: 'post',
|
|
||||||
url: '/condition/new',
|
|
||||||
auth: {basic: 'user'},
|
|
||||||
httpStatus: 403,
|
|
||||||
req: {sample_id: '400000000000000000000002', parameters: {material: 'hot air', weeks: 10}, treatment_template: '200000000000000000000001'}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
it('rejects unauthorized requests', done => {
|
|
||||||
TestHelper.request(server, done, {
|
|
||||||
method: 'post',
|
|
||||||
url: '/condition/new',
|
|
||||||
httpStatus: 401,
|
|
||||||
req: {sample_id: '400000000000000000000002', parameters: {material: 'hot air', weeks: 10}, treatment_template: '200000000000000000000001'}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
@ -1,133 +0,0 @@
|
|||||||
import express from 'express';
|
|
||||||
import _ from 'lodash';
|
|
||||||
|
|
||||||
import ConditionValidate from './validate/condition';
|
|
||||||
import ParametersValidate from './validate/parameters';
|
|
||||||
import res400 from './validate/res400';
|
|
||||||
import SampleModel from '../models/sample';
|
|
||||||
import ConditionModel from '../models/condition';
|
|
||||||
import TreatmentTemplateModel from '../models/treatment_template';
|
|
||||||
import IdValidate from './validate/id';
|
|
||||||
|
|
||||||
|
|
||||||
const router = express.Router();
|
|
||||||
|
|
||||||
router.get('/condition/' + IdValidate.parameter(), (req, res, next) => {
|
|
||||||
if (!req.auth(res, ['read', 'write', 'maintain', 'dev', 'admin'], 'all')) return;
|
|
||||||
|
|
||||||
ConditionModel.findById(req.params.id).lean().exec((err, data) => {
|
|
||||||
if (err) return next(err);
|
|
||||||
if (data) {
|
|
||||||
res.json(ConditionValidate.output(data));
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
res.status(404).json({status: 'Not found'});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
router.put('/condition/' + IdValidate.parameter(), async (req, res, next) => {
|
|
||||||
if (!req.auth(res, ['write', 'maintain', 'dev', 'admin'], 'basic')) return;
|
|
||||||
|
|
||||||
const {error, value: condition} = ConditionValidate.input(req.body, 'change');
|
|
||||||
if (error) return res400(error, res);
|
|
||||||
|
|
||||||
const data = await ConditionModel.findById(req.params.id).lean().exec().catch(err => {next(err);}) as any;
|
|
||||||
if (data instanceof Error) return;
|
|
||||||
if (!data) {
|
|
||||||
res.status(404).json({status: 'Not found'});
|
|
||||||
}
|
|
||||||
|
|
||||||
// add properties needed for sampleIdCheck
|
|
||||||
condition.treatment_template = data.treatment_template;
|
|
||||||
condition.sample_id = data.sample_id;
|
|
||||||
if (!await sampleIdCheck(condition, req, res, next)) return;
|
|
||||||
if (condition.parameters) {
|
|
||||||
condition.parameters = _.assign({}, data.parameters, condition.parameters);
|
|
||||||
if (!_.isEqual(condition.parameters, data.parameters)) { // parameters did not change
|
|
||||||
condition.status = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!await treatmentCheck(condition, 'change', res, next)) return;
|
|
||||||
|
|
||||||
await ConditionModel.findByIdAndUpdate(req.params.id, condition, {new: true}).lean().exec((err, data) => {
|
|
||||||
if (err) return next(err);
|
|
||||||
res.json(ConditionValidate.output(data));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
router.delete('/condition/' + IdValidate.parameter(), (req, res, next) => {
|
|
||||||
if (!req.auth(res, ['write', 'maintain', 'dev', 'admin'], 'basic')) return;
|
|
||||||
|
|
||||||
ConditionModel.findById(req.params.id).lean().exec(async (err, data: any) => {
|
|
||||||
if (err) return next(err);
|
|
||||||
if (!data) {
|
|
||||||
res.status(404).json({status: 'Not found'});
|
|
||||||
}
|
|
||||||
if (!await sampleIdCheck(data, req, res, next)) return;
|
|
||||||
await ConditionModel.findByIdAndUpdate(req.params.id, {status: -1}).lean().exec(err => {
|
|
||||||
if (err) return next(err);
|
|
||||||
res.json({status: 'OK'});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
router.post('/condition/new', async (req, res, next) => {
|
|
||||||
if (!req.auth(res, ['write', 'maintain', 'dev', 'admin'], 'basic')) return;
|
|
||||||
|
|
||||||
const {error, value: condition} = ConditionValidate.input(req.body, 'new');
|
|
||||||
if (error) return res400(error, res);
|
|
||||||
|
|
||||||
if (!await sampleIdCheck(condition, req, res, next)) return;
|
|
||||||
const treatmentData = await treatmentCheck(condition, 'new', res, next)
|
|
||||||
if (!treatmentData) return;
|
|
||||||
|
|
||||||
condition.number = await numberGenerate(condition, treatmentData, next);
|
|
||||||
if (!condition.number) return;
|
|
||||||
condition.status = 0; // set status to new
|
|
||||||
await new ConditionModel(condition).save((err, data) => {
|
|
||||||
if (err) return next(err);
|
|
||||||
res.json(ConditionValidate.output(data.toObject()));
|
|
||||||
});
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
module.exports = router;
|
|
||||||
|
|
||||||
|
|
||||||
async function sampleIdCheck (condition, req, res, next) { // validate sample_id, returns false if invalid
|
|
||||||
const sampleData = await SampleModel.findById(condition.sample_id).lean().exec().catch(err => {next(err); return false;}) as any;
|
|
||||||
if (!sampleData) { // sample_id not found
|
|
||||||
res.status(400).json({status: 'Sample id not available'});
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sampleData.user_id.toString() !== req.authDetails.id && !req.auth(res, ['maintain', 'admin'], 'basic')) return false; // sample does not belong to user
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
async function numberGenerate (condition, treatmentData, next) { // generate number, returns false on error
|
|
||||||
const conditionData = await ConditionModel // find condition with highest number belonging to the same sample
|
|
||||||
.find({sample_id: condition.sample_id, number: new RegExp('^' + treatmentData.number_prefix + '[0-9]+$', 'm')})
|
|
||||||
.sort({number: -1})
|
|
||||||
.limit(1)
|
|
||||||
.lean()
|
|
||||||
.exec()
|
|
||||||
.catch(err => next(err)) as any;
|
|
||||||
if (conditionData instanceof Error) return false;
|
|
||||||
return treatmentData.number_prefix + (conditionData.length > 0 ? Number(conditionData[0].number.replace(/[^0-9]+/g, '')) + 1 : 1); // return new number
|
|
||||||
}
|
|
||||||
|
|
||||||
async function treatmentCheck (condition, param, res, next) { // validate treatment template, returns false if invalid, otherwise template data
|
|
||||||
const treatmentData = await TreatmentTemplateModel.findById(condition.treatment_template).lean().exec().catch(err => next(err)) as any;
|
|
||||||
if (treatmentData instanceof Error) return false;
|
|
||||||
if (!treatmentData) { // template not found
|
|
||||||
res.status(400).json({status: 'Treatment template not available'});
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// validate parameters
|
|
||||||
const {error, value: ignore} = ParametersValidate.input(condition.parameters, treatmentData.parameters, param);
|
|
||||||
if (error) {res400(error, res); return false;}
|
|
||||||
return treatmentData;
|
|
||||||
}
|
|
@ -2,6 +2,7 @@ import should from 'should/as-function';
|
|||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import MaterialModel from '../models/material';
|
import MaterialModel from '../models/material';
|
||||||
import TestHelper from "../test/helper";
|
import TestHelper from "../test/helper";
|
||||||
|
import globals from '../globals';
|
||||||
|
|
||||||
// TODO: color name must be unique to get color number
|
// TODO: color name must be unique to get color number
|
||||||
// TODO: separate supplier/ material name into own collections
|
// TODO: separate supplier/ material name into own collections
|
||||||
@ -11,6 +12,7 @@ describe('/material', () => {
|
|||||||
before(done => TestHelper.before(done));
|
before(done => TestHelper.before(done));
|
||||||
beforeEach(done => server = TestHelper.beforeEach(server, done));
|
beforeEach(done => server = TestHelper.beforeEach(server, done));
|
||||||
afterEach(done => TestHelper.afterEach(server, done));
|
afterEach(done => TestHelper.afterEach(server, done));
|
||||||
|
after(done => TestHelper.after(done));
|
||||||
|
|
||||||
describe('GET /materials', () => {
|
describe('GET /materials', () => {
|
||||||
it('returns all materials', done => {
|
it('returns all materials', done => {
|
||||||
@ -22,7 +24,7 @@ describe('/material', () => {
|
|||||||
}).end((err, res) => {
|
}).end((err, res) => {
|
||||||
if (err) return done(err);
|
if (err) return done(err);
|
||||||
const json = require('../test/db.json');
|
const json = require('../test/db.json');
|
||||||
should(res.body).have.lengthOf(json.collections.materials.filter(e => e.status === 10).length);
|
should(res.body).have.lengthOf(json.collections.materials.filter(e => e.status === globals.status.validated).length);
|
||||||
should(res.body).matchEach(material => {
|
should(res.body).matchEach(material => {
|
||||||
should(material).have.only.keys('_id', 'name', 'supplier', 'group', 'mineral', 'glass_fiber', 'carbon_fiber', 'numbers');
|
should(material).have.only.keys('_id', 'name', 'supplier', 'group', 'mineral', 'glass_fiber', 'carbon_fiber', 'numbers');
|
||||||
should(material).have.property('_id').be.type('string');
|
should(material).have.property('_id').be.type('string');
|
||||||
@ -50,7 +52,7 @@ describe('/material', () => {
|
|||||||
}).end((err, res) => {
|
}).end((err, res) => {
|
||||||
if (err) return done(err);
|
if (err) return done(err);
|
||||||
const json = require('../test/db.json');
|
const json = require('../test/db.json');
|
||||||
should(res.body).have.lengthOf(json.collections.materials.filter(e => e.status === 10).length);
|
should(res.body).have.lengthOf(json.collections.materials.filter(e => e.status === globals.status.validated).length);
|
||||||
should(res.body).matchEach(material => {
|
should(res.body).matchEach(material => {
|
||||||
should(material).have.only.keys('_id', 'name', 'supplier', 'group', 'mineral', 'glass_fiber', 'carbon_fiber', 'numbers');
|
should(material).have.only.keys('_id', 'name', 'supplier', 'group', 'mineral', 'glass_fiber', 'carbon_fiber', 'numbers');
|
||||||
should(material).have.property('_id').be.type('string');
|
should(material).have.property('_id').be.type('string');
|
||||||
@ -89,7 +91,7 @@ describe('/material', () => {
|
|||||||
if (err) return done(err);
|
if (err) return done(err);
|
||||||
const json = require('../test/db.json');
|
const json = require('../test/db.json');
|
||||||
let asyncCounter = res.body.length;
|
let asyncCounter = res.body.length;
|
||||||
should(res.body).have.lengthOf(json.collections.materials.filter(e => e.status === 0).length);
|
should(res.body).have.lengthOf(json.collections.materials.filter(e => e.status ===globals.status.new).length);
|
||||||
should(res.body).matchEach(material => {
|
should(res.body).matchEach(material => {
|
||||||
should(material).have.only.keys('_id', 'name', 'supplier', 'group', 'mineral', 'glass_fiber', 'carbon_fiber', 'numbers');
|
should(material).have.only.keys('_id', 'name', 'supplier', 'group', 'mineral', 'glass_fiber', 'carbon_fiber', 'numbers');
|
||||||
should(material).have.property('_id').be.type('string');
|
should(material).have.property('_id').be.type('string');
|
||||||
@ -105,7 +107,7 @@ describe('/material', () => {
|
|||||||
should(number).have.property('number').be.type('string');
|
should(number).have.property('number').be.type('string');
|
||||||
});
|
});
|
||||||
MaterialModel.findById(material._id).lean().exec((err, data) => {
|
MaterialModel.findById(material._id).lean().exec((err, data) => {
|
||||||
should(data).have.property('status', 0);
|
should(data).have.property('status',globals.status.new);
|
||||||
if (--asyncCounter === 0) {
|
if (--asyncCounter === 0) {
|
||||||
done();
|
done();
|
||||||
}
|
}
|
||||||
@ -123,7 +125,7 @@ describe('/material', () => {
|
|||||||
if (err) return done(err);
|
if (err) return done(err);
|
||||||
const json = require('../test/db.json');
|
const json = require('../test/db.json');
|
||||||
let asyncCounter = res.body.length;
|
let asyncCounter = res.body.length;
|
||||||
should(res.body).have.lengthOf(json.collections.materials.filter(e => e.status === -1).length);
|
should(res.body).have.lengthOf(json.collections.materials.filter(e => e.status ===globals.status.deleted).length);
|
||||||
should(res.body).matchEach(material => {
|
should(res.body).matchEach(material => {
|
||||||
should(material).have.only.keys('_id', 'name', 'supplier', 'group', 'mineral', 'glass_fiber', 'carbon_fiber', 'numbers');
|
should(material).have.only.keys('_id', 'name', 'supplier', 'group', 'mineral', 'glass_fiber', 'carbon_fiber', 'numbers');
|
||||||
should(material).have.property('_id').be.type('string');
|
should(material).have.property('_id').be.type('string');
|
||||||
@ -139,13 +141,12 @@ describe('/material', () => {
|
|||||||
should(number).have.property('number').be.type('string');
|
should(number).have.property('number').be.type('string');
|
||||||
});
|
});
|
||||||
MaterialModel.findById(material._id).lean().exec((err, data) => {
|
MaterialModel.findById(material._id).lean().exec((err, data) => {
|
||||||
should(data).have.property('status', -1);
|
should(data).have.property('status',globals.status.deleted);
|
||||||
if (--asyncCounter === 0) {
|
if (--asyncCounter === 0) {
|
||||||
done();
|
done();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
done();
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
it('rejects requests from a write user', done => {
|
it('rejects requests from a write user', done => {
|
||||||
@ -249,7 +250,7 @@ describe('/material', () => {
|
|||||||
should(res.body).be.eql({_id: '100000000000000000000001', name: 'Stanyl TW 200 F8', supplier: 'DSM', group: 'PA46', mineral: 0, glass_fiber: 40, carbon_fiber: 0, numbers: [{color: 'black', number: '5514263423'}, {color: 'natural', number: '5514263422'}]});
|
should(res.body).be.eql({_id: '100000000000000000000001', name: 'Stanyl TW 200 F8', supplier: 'DSM', group: 'PA46', mineral: 0, glass_fiber: 40, carbon_fiber: 0, numbers: [{color: 'black', number: '5514263423'}, {color: 'natural', number: '5514263422'}]});
|
||||||
MaterialModel.findById('100000000000000000000001').lean().exec((err, data) => {
|
MaterialModel.findById('100000000000000000000001').lean().exec((err, data) => {
|
||||||
if (err) return done(err);
|
if (err) return done(err);
|
||||||
should(data).have.property('status', 10);
|
should(data).have.property('status',globals.status.validated);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -266,7 +267,7 @@ describe('/material', () => {
|
|||||||
should(res.body).be.eql({_id: '100000000000000000000001', name: 'Stanyl TW 200 F8', supplier: 'DSM', group: 'PA46', mineral: 0, glass_fiber: 40, carbon_fiber: 0, numbers: [{color: 'black', number: '5514263423'}, {color: 'natural', number: '5514263422'}]});
|
should(res.body).be.eql({_id: '100000000000000000000001', name: 'Stanyl TW 200 F8', supplier: 'DSM', group: 'PA46', mineral: 0, glass_fiber: 40, carbon_fiber: 0, numbers: [{color: 'black', number: '5514263423'}, {color: 'natural', number: '5514263422'}]});
|
||||||
MaterialModel.findById('100000000000000000000001').lean().exec((err, data) => {
|
MaterialModel.findById('100000000000000000000001').lean().exec((err, data) => {
|
||||||
if (err) return done(err);
|
if (err) return done(err);
|
||||||
should(data).have.property('status', 10);
|
should(data).have.property('status',globals.status.validated);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -513,7 +514,7 @@ describe('/material', () => {
|
|||||||
should(data[0]).have.property('mineral', '0');
|
should(data[0]).have.property('mineral', '0');
|
||||||
should(data[0]).have.property('glass_fiber', '30');
|
should(data[0]).have.property('glass_fiber', '30');
|
||||||
should(data[0]).have.property('carbon_fiber', '0');
|
should(data[0]).have.property('carbon_fiber', '0');
|
||||||
should(data[0]).have.property('status', 0);
|
should(data[0]).have.property('status',globals.status.new);
|
||||||
should(data[0].numbers).have.lengthOf(0);
|
should(data[0].numbers).have.lengthOf(0);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
@ -552,7 +553,7 @@ describe('/material', () => {
|
|||||||
should(data[0]).have.property('mineral', '0');
|
should(data[0]).have.property('mineral', '0');
|
||||||
should(data[0]).have.property('glass_fiber', '30');
|
should(data[0]).have.property('glass_fiber', '30');
|
||||||
should(data[0]).have.property('carbon_fiber', '0');
|
should(data[0]).have.property('carbon_fiber', '0');
|
||||||
should(data[0]).have.property('status', 0);
|
should(data[0]).have.property('status',globals.status.new);
|
||||||
should(_.omit(data[0].numbers[0], '_id')).be.eql({color: 'black', number: ''});
|
should(_.omit(data[0].numbers[0], '_id')).be.eql({color: 'black', number: ''});
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
@ -7,6 +7,7 @@ import SampleModel from '../models/sample';
|
|||||||
import IdValidate from './validate/id';
|
import IdValidate from './validate/id';
|
||||||
import res400 from './validate/res400';
|
import res400 from './validate/res400';
|
||||||
import mongoose from 'mongoose';
|
import mongoose from 'mongoose';
|
||||||
|
import globals from '../globals';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -15,7 +16,7 @@ const router = express.Router();
|
|||||||
router.get('/materials', (req, res, next) => {
|
router.get('/materials', (req, res, next) => {
|
||||||
if (!req.auth(res, ['read', 'write', 'maintain', 'dev', 'admin'], 'all')) return;
|
if (!req.auth(res, ['read', 'write', 'maintain', 'dev', 'admin'], 'all')) return;
|
||||||
|
|
||||||
MaterialModel.find({status: 10}).lean().exec((err, data) => {
|
MaterialModel.find({status:globals.status.validated}).lean().exec((err, data) => {
|
||||||
if (err) return next(err);
|
if (err) return next(err);
|
||||||
res.json(_.compact(data.map(e => MaterialValidate.output(e)))); // validate all and filter null values from validation errors
|
res.json(_.compact(data.map(e => MaterialValidate.output(e)))); // validate all and filter null values from validation errors
|
||||||
});
|
});
|
||||||
@ -24,14 +25,7 @@ router.get('/materials', (req, res, next) => {
|
|||||||
router.get('/materials/:group(new|deleted)', (req, res, next) => {
|
router.get('/materials/:group(new|deleted)', (req, res, next) => {
|
||||||
if (!req.auth(res, ['maintain', 'admin'], 'basic')) return;
|
if (!req.auth(res, ['maintain', 'admin'], 'basic')) return;
|
||||||
|
|
||||||
let status;
|
MaterialModel.find({status: globals.status[req.params.group]}).lean().exec((err, data) => {
|
||||||
switch (req.params.group) {
|
|
||||||
case 'new': status = 0;
|
|
||||||
break;
|
|
||||||
case 'deleted': status = -1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
MaterialModel.find({status: status}).lean().exec((err, data) => {
|
|
||||||
if (err) return next(err);
|
if (err) return next(err);
|
||||||
res.json(_.compact(data.map(e => MaterialValidate.output(e)))); // validate all and filter null values from validation errors
|
res.json(_.compact(data.map(e => MaterialValidate.output(e)))); // validate all and filter null values from validation errors
|
||||||
});
|
});
|
||||||
@ -67,7 +61,7 @@ router.put('/material/' + IdValidate.parameter(), (req, res, next) => {
|
|||||||
|
|
||||||
// check for changes
|
// check for changes
|
||||||
if (!_.isEqual(_.pick(IdValidate.stringify(materialData), _.keys(material)), material)) {
|
if (!_.isEqual(_.pick(IdValidate.stringify(materialData), _.keys(material)), material)) {
|
||||||
material.status = 0; // set status to new
|
material.status = globals.status.new; // set status to new
|
||||||
}
|
}
|
||||||
|
|
||||||
await MaterialModel.findByIdAndUpdate(req.params.id, material, {new: true}).lean().exec((err, data) => {
|
await MaterialModel.findByIdAndUpdate(req.params.id, material, {new: true}).lean().exec((err, data) => {
|
||||||
@ -86,7 +80,7 @@ router.delete('/material/' + IdValidate.parameter(), (req, res, next) => {
|
|||||||
if (data.length) {
|
if (data.length) {
|
||||||
return res.status(400).json({status: 'Material still in use'});
|
return res.status(400).json({status: 'Material still in use'});
|
||||||
}
|
}
|
||||||
MaterialModel.findByIdAndUpdate(req.params.id, {status: -1}).lean().exec((err, data) => {
|
MaterialModel.findByIdAndUpdate(req.params.id, {status:globals.status.deleted}).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'});
|
||||||
@ -106,7 +100,7 @@ router.post('/material/new', async (req, res, next) => {
|
|||||||
|
|
||||||
if (!await nameCheck(material, res, next)) return;
|
if (!await nameCheck(material, res, next)) return;
|
||||||
|
|
||||||
material.status = 0; // set status to new
|
material.status = globals.status.new; // set status to new
|
||||||
await new MaterialModel(material).save((err, data) => {
|
await new MaterialModel(material).save((err, data) => {
|
||||||
if (err) return next(err);
|
if (err) return next(err);
|
||||||
res.json(MaterialValidate.output(data.toObject()));
|
res.json(MaterialValidate.output(data.toObject()));
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
import should from 'should/as-function';
|
import should from 'should/as-function';
|
||||||
import MeasurementModel from '../models/measurement';
|
import MeasurementModel from '../models/measurement';
|
||||||
import TestHelper from "../test/helper";
|
import TestHelper from "../test/helper";
|
||||||
|
import globals from '../globals';
|
||||||
|
|
||||||
// TODO: allow empty values
|
// TODO: restore measurements for m/a
|
||||||
|
|
||||||
|
|
||||||
describe('/measurement', () => {
|
describe('/measurement', () => {
|
||||||
@ -10,15 +11,16 @@ describe('/measurement', () => {
|
|||||||
before(done => TestHelper.before(done));
|
before(done => TestHelper.before(done));
|
||||||
beforeEach(done => server = TestHelper.beforeEach(server, done));
|
beforeEach(done => server = TestHelper.beforeEach(server, done));
|
||||||
afterEach(done => TestHelper.afterEach(server, done));
|
afterEach(done => TestHelper.afterEach(server, done));
|
||||||
|
after(done => TestHelper.after(done));
|
||||||
|
|
||||||
describe('GET /mesurement/{id}', () => {
|
describe('GET /measurement/{id}', () => {
|
||||||
it('returns the right measurement', done => {
|
it('returns the right measurement', done => {
|
||||||
TestHelper.request(server, done, {
|
TestHelper.request(server, done, {
|
||||||
method: 'get',
|
method: 'get',
|
||||||
url: '/measurement/800000000000000000000001',
|
url: '/measurement/800000000000000000000001',
|
||||||
auth: {basic: 'janedoe'},
|
auth: {basic: 'janedoe'},
|
||||||
httpStatus: 200,
|
httpStatus: 200,
|
||||||
res: {_id: '800000000000000000000001', condition_id: '700000000000000000000001', values: {dpt: [[3997.12558,98.00555],[3995.08519,98.03253],[3993.04480,98.02657]]}, measurement_template: '300000000000000000000001'}
|
res: {_id: '800000000000000000000001', sample_id: '400000000000000000000001', values: {dpt: [[3997.12558,98.00555],[3995.08519,98.03253],[3993.04480,98.02657]]}, measurement_template: '300000000000000000000001'}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
it('returns the measurement for an API key', done => {
|
it('returns the measurement for an API key', done => {
|
||||||
@ -27,7 +29,24 @@ describe('/measurement', () => {
|
|||||||
url: '/measurement/800000000000000000000001',
|
url: '/measurement/800000000000000000000001',
|
||||||
auth: {key: 'janedoe'},
|
auth: {key: 'janedoe'},
|
||||||
httpStatus: 200,
|
httpStatus: 200,
|
||||||
res: {_id: '800000000000000000000001', condition_id: '700000000000000000000001', values: {dpt: [[3997.12558,98.00555],[3995.08519,98.03253],[3993.04480,98.02657]]}, measurement_template: '300000000000000000000001'}
|
res: {_id: '800000000000000000000001', sample_id: '400000000000000000000001', values: {dpt: [[3997.12558,98.00555],[3995.08519,98.03253],[3993.04480,98.02657]]}, measurement_template: '300000000000000000000001'}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it('returns deleted measurements for a maintain/admin user', done => {
|
||||||
|
TestHelper.request(server, done, {
|
||||||
|
method: 'get',
|
||||||
|
url: '/measurement/800000000000000000000004',
|
||||||
|
auth: {basic: 'admin'},
|
||||||
|
httpStatus: 200,
|
||||||
|
res: {_id: '800000000000000000000004', sample_id: '400000000000000000000003', values: {val1: 1}, measurement_template: '300000000000000000000003'}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it('rejects requests for deleted measurements from a write user', done => {
|
||||||
|
TestHelper.request(server, done, {
|
||||||
|
method: 'get',
|
||||||
|
url: '/measurement/800000000000000000000004',
|
||||||
|
auth: {basic: 'janedoe'},
|
||||||
|
httpStatus: 403
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
it('rejects an invalid id', done => {
|
it('rejects an invalid id', done => {
|
||||||
@ -63,7 +82,7 @@ describe('/measurement', () => {
|
|||||||
auth: {basic: 'janedoe'},
|
auth: {basic: 'janedoe'},
|
||||||
httpStatus: 200,
|
httpStatus: 200,
|
||||||
req: {},
|
req: {},
|
||||||
res: {_id: '800000000000000000000001', condition_id: '700000000000000000000001', values: {dpt: [[3997.12558,98.00555],[3995.08519,98.03253],[3993.04480,98.02657]]}, measurement_template: '300000000000000000000001'}
|
res: {_id: '800000000000000000000001', sample_id: '400000000000000000000001', values: {dpt: [[3997.12558,98.00555],[3995.08519,98.03253],[3993.04480,98.02657]]}, measurement_template: '300000000000000000000001'}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
it('keeps unchanged values', done => {
|
it('keeps unchanged values', done => {
|
||||||
@ -75,10 +94,10 @@ describe('/measurement', () => {
|
|||||||
req: {values: {dpt: [[3997.12558,98.00555],[3995.08519,98.03253],[3993.04480,98.02657]]}}
|
req: {values: {dpt: [[3997.12558,98.00555],[3995.08519,98.03253],[3993.04480,98.02657]]}}
|
||||||
}).end((err, res) => {
|
}).end((err, res) => {
|
||||||
if (err) return done(err);
|
if (err) return done(err);
|
||||||
should(res.body).be.eql({_id: '800000000000000000000001', condition_id: '700000000000000000000001', values: {dpt: [[3997.12558,98.00555],[3995.08519,98.03253],[3993.04480,98.02657]]}, measurement_template: '300000000000000000000001'});
|
should(res.body).be.eql({_id: '800000000000000000000001', sample_id: '400000000000000000000001', values: {dpt: [[3997.12558,98.00555],[3995.08519,98.03253],[3993.04480,98.02657]]}, measurement_template: '300000000000000000000001'});
|
||||||
MeasurementModel.findById('800000000000000000000001').lean().exec((err, data: any) => {
|
MeasurementModel.findById('800000000000000000000001').lean().exec((err, data: any) => {
|
||||||
if (err) return done(err);
|
if (err) return done(err);
|
||||||
should(data).have.property('status', 10);
|
should(data).have.property('status',globals.status.validated);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -92,10 +111,10 @@ describe('/measurement', () => {
|
|||||||
req: {values: {'weight %': 0.5}}
|
req: {values: {'weight %': 0.5}}
|
||||||
}).end((err, res) => {
|
}).end((err, res) => {
|
||||||
if (err) return done(err);
|
if (err) return done(err);
|
||||||
should(res.body).be.eql({_id: '800000000000000000000002', condition_id: '700000000000000000000002', values: {'weight %': 0.5, 'standard deviation': 0.2}, measurement_template: '300000000000000000000002'});
|
should(res.body).be.eql({_id: '800000000000000000000002', sample_id: '400000000000000000000002', values: {'weight %': 0.5, 'standard deviation': 0.2}, measurement_template: '300000000000000000000002'});
|
||||||
MeasurementModel.findById('800000000000000000000002').lean().exec((err, data: any) => {
|
MeasurementModel.findById('800000000000000000000002').lean().exec((err, data: any) => {
|
||||||
if (err) return done(err);
|
if (err) return done(err);
|
||||||
should(data).have.property('status', 10);
|
should(data).have.property('status',globals.status.validated);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -109,12 +128,12 @@ describe('/measurement', () => {
|
|||||||
req: {values: {dpt: [[1,2],[3,4],[5,6]]}}
|
req: {values: {dpt: [[1,2],[3,4],[5,6]]}}
|
||||||
}).end((err, res) => {
|
}).end((err, res) => {
|
||||||
if (err) return done(err);
|
if (err) return done(err);
|
||||||
should(res.body).be.eql({_id: '800000000000000000000001', condition_id: '700000000000000000000001', values: {dpt: [[1,2],[3,4],[5,6]]}, measurement_template: '300000000000000000000001'});
|
should(res.body).be.eql({_id: '800000000000000000000001', sample_id: '400000000000000000000001', values: {dpt: [[1,2],[3,4],[5,6]]}, measurement_template: '300000000000000000000001'});
|
||||||
MeasurementModel.findById('800000000000000000000001').lean().exec((err, data: any) => {
|
MeasurementModel.findById('800000000000000000000001').lean().exec((err, data: any) => {
|
||||||
should(data).have.only.keys('_id', 'condition_id', 'values', 'measurement_template', 'status', '__v');
|
should(data).have.only.keys('_id', 'sample_id', 'values', 'measurement_template', 'status', '__v');
|
||||||
should(data.condition_id.toString()).be.eql('700000000000000000000001');
|
should(data.sample_id.toString()).be.eql('400000000000000000000001');
|
||||||
should(data.measurement_template.toString()).be.eql('300000000000000000000001');
|
should(data.measurement_template.toString()).be.eql('300000000000000000000001');
|
||||||
should(data).have.property('status', 0);
|
should(data).have.property('status',globals.status.new);
|
||||||
should(data).have.property('values');
|
should(data).have.property('values');
|
||||||
should(data.values).have.property('dpt', [[1,2],[3,4],[5,6]]);
|
should(data.values).have.property('dpt', [[1,2],[3,4],[5,6]]);
|
||||||
done();
|
done();
|
||||||
@ -128,7 +147,17 @@ describe('/measurement', () => {
|
|||||||
auth: {basic: 'janedoe'},
|
auth: {basic: 'janedoe'},
|
||||||
httpStatus: 200,
|
httpStatus: 200,
|
||||||
req: {values: {'weight %': 0.9}},
|
req: {values: {'weight %': 0.9}},
|
||||||
res: {_id: '800000000000000000000002', condition_id: '700000000000000000000002', values: {'weight %': 0.9, 'standard deviation': 0.2}, measurement_template: '300000000000000000000002'}
|
res: {_id: '800000000000000000000002', sample_id: '400000000000000000000002', values: {'weight %': 0.9, 'standard deviation': 0.2}, measurement_template: '300000000000000000000002'}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it('allows keeping empty values empty', done => {
|
||||||
|
TestHelper.request(server, done, {
|
||||||
|
method: 'put',
|
||||||
|
url: '/measurement/800000000000000000000005',
|
||||||
|
auth: {basic: 'janedoe'},
|
||||||
|
httpStatus: 200,
|
||||||
|
req: {values: {'weight %': 0.9}},
|
||||||
|
res: {_id: '800000000000000000000005', sample_id: '400000000000000000000002', values: {'weight %': 0.9, 'standard deviation': null}, measurement_template: '300000000000000000000002'}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
it('rejects not specified values', done => {
|
it('rejects not specified values', done => {
|
||||||
@ -148,7 +177,7 @@ describe('/measurement', () => {
|
|||||||
auth: {basic: 'admin'},
|
auth: {basic: 'admin'},
|
||||||
httpStatus: 400,
|
httpStatus: 400,
|
||||||
req: {values: {val1: 4}},
|
req: {values: {val1: 4}},
|
||||||
res: {status: 'Invalid body format', details: '"val1" must be one of [1, 2, 3]'}
|
res: {status: 'Invalid body format', details: '"val1" must be one of [1, 2, 3, null]'}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
it('rejects a value below minimum range', done => {
|
it('rejects a value below minimum range', done => {
|
||||||
@ -181,6 +210,16 @@ describe('/measurement', () => {
|
|||||||
res: {status: 'Invalid body format', details: '"measurement_template" is not allowed'}
|
res: {status: 'Invalid body format', details: '"measurement_template" is not allowed'}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
it('rejects a new sample id', done => {
|
||||||
|
TestHelper.request(server, done, {
|
||||||
|
method: 'put',
|
||||||
|
url: '/measurement/800000000000000000000002',
|
||||||
|
auth: {basic: 'janedoe'},
|
||||||
|
httpStatus: 400,
|
||||||
|
req: {values: {'weight %': 0.9, 'standard deviation': 0.3}, sample_id: '400000000000000000000002'},
|
||||||
|
res: {status: 'Invalid body format', details: '"sample_id" is not allowed'}
|
||||||
|
});
|
||||||
|
});
|
||||||
it('rejects editing a measurement for a write user who did not create this measurement', done => {
|
it('rejects editing a measurement for a write user who did not create this measurement', done => {
|
||||||
TestHelper.request(server, done, {
|
TestHelper.request(server, done, {
|
||||||
method: 'put',
|
method: 'put',
|
||||||
@ -197,7 +236,7 @@ describe('/measurement', () => {
|
|||||||
auth: {basic: 'admin'},
|
auth: {basic: 'admin'},
|
||||||
httpStatus: 200,
|
httpStatus: 200,
|
||||||
req: {values: {'weight %': 0.9, 'standard deviation': 0.3}},
|
req: {values: {'weight %': 0.9, 'standard deviation': 0.3}},
|
||||||
res: {_id: '800000000000000000000002', condition_id: '700000000000000000000002', values: {'weight %': 0.9, 'standard deviation': 0.3}, measurement_template: '300000000000000000000002'}
|
res: {_id: '800000000000000000000002', sample_id: '400000000000000000000002', values: {'weight %': 0.9, 'standard deviation': 0.3}, measurement_template: '300000000000000000000002'}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
it('rejects an invalid id', done => {
|
it('rejects an invalid id', done => {
|
||||||
@ -256,7 +295,7 @@ describe('/measurement', () => {
|
|||||||
should(res.body).be.eql({status: 'OK'});
|
should(res.body).be.eql({status: 'OK'});
|
||||||
MeasurementModel.findById('800000000000000000000001').lean().exec((err, data) => {
|
MeasurementModel.findById('800000000000000000000001').lean().exec((err, data) => {
|
||||||
if (err) return done(err);
|
if (err) return done(err);
|
||||||
should(data).have.property('status', -1);
|
should(data).have.property('status',globals.status.deleted);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -326,12 +365,12 @@ describe('/measurement', () => {
|
|||||||
url: '/measurement/new',
|
url: '/measurement/new',
|
||||||
auth: {basic: 'janedoe'},
|
auth: {basic: 'janedoe'},
|
||||||
httpStatus: 200,
|
httpStatus: 200,
|
||||||
req: {condition_id: '700000000000000000000001', values: {'weight %': 0.8, 'standard deviation': 0.1}, measurement_template: '300000000000000000000002'}
|
req: {sample_id: '400000000000000000000001', values: {'weight %': 0.8, 'standard deviation': 0.1}, measurement_template: '300000000000000000000002'}
|
||||||
}).end((err, res) => {
|
}).end((err, res) => {
|
||||||
if (err) return done(err);
|
if (err) return done(err);
|
||||||
should(res.body).have.only.keys('_id', 'condition_id', 'values', 'measurement_template');
|
should(res.body).have.only.keys('_id', 'sample_id', 'values', 'measurement_template');
|
||||||
should(res.body).have.property('_id').be.type('string');
|
should(res.body).have.property('_id').be.type('string');
|
||||||
should(res.body).have.property('condition_id', '700000000000000000000001');
|
should(res.body).have.property('sample_id', '400000000000000000000001');
|
||||||
should(res.body).have.property('measurement_template', '300000000000000000000002');
|
should(res.body).have.property('measurement_template', '300000000000000000000002');
|
||||||
should(res.body).have.property('values');
|
should(res.body).have.property('values');
|
||||||
should(res.body.values).have.property('weight %', 0.8);
|
should(res.body.values).have.property('weight %', 0.8);
|
||||||
@ -345,13 +384,13 @@ describe('/measurement', () => {
|
|||||||
url: '/measurement/new',
|
url: '/measurement/new',
|
||||||
auth: {basic: 'janedoe'},
|
auth: {basic: 'janedoe'},
|
||||||
httpStatus: 200,
|
httpStatus: 200,
|
||||||
req: {condition_id: '700000000000000000000001', values: {'weight %': 0.8, 'standard deviation': 0.1}, measurement_template: '300000000000000000000002'}
|
req: {sample_id: '400000000000000000000001', values: {'weight %': 0.8, 'standard deviation': 0.1}, measurement_template: '300000000000000000000002'}
|
||||||
}).end((err, res) => {
|
}).end((err, res) => {
|
||||||
if (err) return done(err);
|
if (err) return done(err);
|
||||||
MeasurementModel.findById(res.body._id).lean().exec((err, data: any) => {
|
MeasurementModel.findById(res.body._id).lean().exec((err, data: any) => {
|
||||||
if (err) return done(err);
|
if (err) return done(err);
|
||||||
should(data).have.only.keys('_id', 'condition_id', 'values', 'measurement_template', 'status', '__v');
|
should(data).have.only.keys('_id', 'sample_id', 'values', 'measurement_template', 'status', '__v');
|
||||||
should(data.condition_id.toString()).be.eql('700000000000000000000001');
|
should(data.sample_id.toString()).be.eql('400000000000000000000001');
|
||||||
should(data.measurement_template.toString()).be.eql('300000000000000000000002');
|
should(data.measurement_template.toString()).be.eql('300000000000000000000002');
|
||||||
should(data).have.property('status', 0);
|
should(data).have.property('status', 0);
|
||||||
should(data).have.property('values');
|
should(data).have.property('values');
|
||||||
@ -361,24 +400,24 @@ describe('/measurement', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
it('rejects an invalid condition id', done => {
|
it('rejects an invalid sample id', done => {
|
||||||
TestHelper.request(server, done, {
|
TestHelper.request(server, done, {
|
||||||
method: 'post',
|
method: 'post',
|
||||||
url: '/measurement/new',
|
url: '/measurement/new',
|
||||||
auth: {basic: 'janedoe'},
|
auth: {basic: 'janedoe'},
|
||||||
httpStatus: 400,
|
httpStatus: 400,
|
||||||
req: {condition_id: '700000000000h00000000001', values: {'weight %': 0.8, 'standard deviation': 0.1}, measurement_template: '300000000000000000000002'},
|
req: {sample_id: '400000000000h00000000001', values: {'weight %': 0.8, 'standard deviation': 0.1}, measurement_template: '300000000000000000000002'},
|
||||||
res: {status: 'Invalid body format', details: '"condition_id" with value "700000000000h00000000001" fails to match the required pattern: /[0-9a-f]{24}/'}
|
res: {status: 'Invalid body format', details: '"sample_id" with value "400000000000h00000000001" fails to match the required pattern: /[0-9a-f]{24}/'}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
it('rejects a condition id not available', done => {
|
it('rejects a sample id not available', done => {
|
||||||
TestHelper.request(server, done, {
|
TestHelper.request(server, done, {
|
||||||
method: 'post',
|
method: 'post',
|
||||||
url: '/measurement/new',
|
url: '/measurement/new',
|
||||||
auth: {basic: 'janedoe'},
|
auth: {basic: 'janedoe'},
|
||||||
httpStatus: 400,
|
httpStatus: 400,
|
||||||
req: {condition_id: '000000000000000000000001', values: {'weight %': 0.8, 'standard deviation': 0.1}, measurement_template: '300000000000000000000002'},
|
req: {sample_id: '000000000000000000000001', values: {'weight %': 0.8, 'standard deviation': 0.1}, measurement_template: '300000000000000000000002'},
|
||||||
res: {status: 'Condition id not available'}
|
res: {status: 'Sample id not available'}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
it('rejects an invalid measurement_template id', done => {
|
it('rejects an invalid measurement_template id', done => {
|
||||||
@ -387,7 +426,7 @@ describe('/measurement', () => {
|
|||||||
url: '/measurement/new',
|
url: '/measurement/new',
|
||||||
auth: {basic: 'janedoe'},
|
auth: {basic: 'janedoe'},
|
||||||
httpStatus: 400,
|
httpStatus: 400,
|
||||||
req: {condition_id: '700000000000000000000001', values: {'weight %': 0.8, 'standard deviation': 0.1}, measurement_template: '30000000000h000000000002'},
|
req: {sample_id: '400000000000000000000001', values: {'weight %': 0.8, 'standard deviation': 0.1}, measurement_template: '30000000000h000000000002'},
|
||||||
res: {status: 'Invalid body format', details: '"measurement_template" with value "30000000000h000000000002" fails to match the required pattern: /[0-9a-f]{24}/'}
|
res: {status: 'Invalid body format', details: '"measurement_template" with value "30000000000h000000000002" fails to match the required pattern: /[0-9a-f]{24}/'}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -397,7 +436,7 @@ describe('/measurement', () => {
|
|||||||
url: '/measurement/new',
|
url: '/measurement/new',
|
||||||
auth: {basic: 'janedoe'},
|
auth: {basic: 'janedoe'},
|
||||||
httpStatus: 400,
|
httpStatus: 400,
|
||||||
req: {condition_id: '700000000000000000000001', values: {'weight %': 0.8, 'standard deviation': 0.1}, measurement_template: '000000000000000000000002'},
|
req: {sample_id: '400000000000000000000001', values: {'weight %': 0.8, 'standard deviation': 0.1}, measurement_template: '000000000000000000000002'},
|
||||||
res: {status: 'Measurement template not available'}
|
res: {status: 'Measurement template not available'}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -407,18 +446,27 @@ describe('/measurement', () => {
|
|||||||
url: '/measurement/new',
|
url: '/measurement/new',
|
||||||
auth: {basic: 'janedoe'},
|
auth: {basic: 'janedoe'},
|
||||||
httpStatus: 400,
|
httpStatus: 400,
|
||||||
req: {condition_id: '700000000000000000000001', values: {'weight %': 0.8, 'standard deviation': 0.1, xx: 44}, measurement_template: '300000000000000000000002'},
|
req: {sample_id: '400000000000000000000001', values: {'weight %': 0.8, 'standard deviation': 0.1, xx: 44}, measurement_template: '300000000000000000000002'},
|
||||||
res: {status: 'Invalid body format', details: '"xx" is not allowed'}
|
res: {status: 'Invalid body format', details: '"xx" is not allowed'}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
it('rejects missing values', done => {
|
it('accepts missing values', done => {
|
||||||
TestHelper.request(server, done, {
|
TestHelper.request(server, done, {
|
||||||
method: 'post',
|
method: 'post',
|
||||||
url: '/measurement/new',
|
url: '/measurement/new',
|
||||||
auth: {basic: 'janedoe'},
|
auth: {basic: 'janedoe'},
|
||||||
httpStatus: 400,
|
httpStatus: 200,
|
||||||
req: {condition_id: '700000000000000000000001', values: {'weight %': 0.8}, measurement_template: '300000000000000000000002'},
|
req: {sample_id: '400000000000000000000001', values: {'weight %': 0.8}, measurement_template: '300000000000000000000002'}
|
||||||
res: {status: 'Invalid body format', details: '"standard deviation" is required'}
|
}).end((err, res) => {
|
||||||
|
if (err) return done(err);
|
||||||
|
should(res.body).have.only.keys('_id', 'sample_id', 'values', 'measurement_template');
|
||||||
|
should(res.body).have.property('_id').be.type('string');
|
||||||
|
should(res.body).have.property('sample_id', '400000000000000000000001');
|
||||||
|
should(res.body).have.property('measurement_template', '300000000000000000000002');
|
||||||
|
should(res.body).have.property('values');
|
||||||
|
should(res.body.values).have.property('weight %', 0.8);
|
||||||
|
should(res.body.values).have.property('standard deviation', null);
|
||||||
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
it('rejects a value not in the value range', done => {
|
it('rejects a value not in the value range', done => {
|
||||||
@ -427,8 +475,8 @@ describe('/measurement', () => {
|
|||||||
url: '/measurement/new',
|
url: '/measurement/new',
|
||||||
auth: {basic: 'janedoe'},
|
auth: {basic: 'janedoe'},
|
||||||
httpStatus: 400,
|
httpStatus: 400,
|
||||||
req: {condition_id: '700000000000000000000001', values: {val1: 4}, measurement_template: '300000000000000000000003'},
|
req: {sample_id: '400000000000000000000001', values: {val1: 4}, measurement_template: '300000000000000000000003'},
|
||||||
res: {status: 'Invalid body format', details: '"val1" must be one of [1, 2, 3]'}
|
res: {status: 'Invalid body format', details: '"val1" must be one of [1, 2, 3, null]'}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
it('rejects a value below minimum range', done => {
|
it('rejects a value below minimum range', done => {
|
||||||
@ -437,7 +485,7 @@ describe('/measurement', () => {
|
|||||||
url: '/measurement/new',
|
url: '/measurement/new',
|
||||||
auth: {basic: 'janedoe'},
|
auth: {basic: 'janedoe'},
|
||||||
httpStatus: 400,
|
httpStatus: 400,
|
||||||
req: {condition_id: '700000000000000000000001', values: {'weight %': -1, 'standard deviation': 0.1}, measurement_template: '300000000000000000000002'},
|
req: {sample_id: '400000000000000000000001', values: {'weight %': -1, 'standard deviation': 0.1}, measurement_template: '300000000000000000000002'},
|
||||||
res: {status: 'Invalid body format', details: '"weight %" must be larger than or equal to 0'}
|
res: {status: 'Invalid body format', details: '"weight %" must be larger than or equal to 0'}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -447,18 +495,18 @@ describe('/measurement', () => {
|
|||||||
url: '/measurement/new',
|
url: '/measurement/new',
|
||||||
auth: {basic: 'janedoe'},
|
auth: {basic: 'janedoe'},
|
||||||
httpStatus: 400,
|
httpStatus: 400,
|
||||||
req: {condition_id: '700000000000000000000001', values: {'weight %': 0.8, 'standard deviation': 2}, measurement_template: '300000000000000000000002'},
|
req: {sample_id: '400000000000000000000001', values: {'weight %': 0.8, 'standard deviation': 2}, measurement_template: '300000000000000000000002'},
|
||||||
res: {status: 'Invalid body format', details: '"standard deviation" must be less than or equal to 0.5'}
|
res: {status: 'Invalid body format', details: '"standard deviation" must be less than or equal to 0.5'}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
it('rejects a missing condition id', done => {
|
it('rejects a missing sample id', done => {
|
||||||
TestHelper.request(server, done, {
|
TestHelper.request(server, done, {
|
||||||
method: 'post',
|
method: 'post',
|
||||||
url: '/measurement/new',
|
url: '/measurement/new',
|
||||||
auth: {basic: 'janedoe'},
|
auth: {basic: 'janedoe'},
|
||||||
httpStatus: 400,
|
httpStatus: 400,
|
||||||
req: {values: {'weight %': 0.8, 'standard deviation': 0.1}, measurement_template: '300000000000000000000002'},
|
req: {values: {'weight %': 0.8, 'standard deviation': 0.1}, measurement_template: '300000000000000000000002'},
|
||||||
res: {status: 'Invalid body format', details: '"condition_id" is required'}
|
res: {status: 'Invalid body format', details: '"sample_id" is required'}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
it('rejects a missing measurement_template', done => {
|
it('rejects a missing measurement_template', done => {
|
||||||
@ -467,7 +515,7 @@ describe('/measurement', () => {
|
|||||||
url: '/measurement/new',
|
url: '/measurement/new',
|
||||||
auth: {basic: 'janedoe'},
|
auth: {basic: 'janedoe'},
|
||||||
httpStatus: 400,
|
httpStatus: 400,
|
||||||
req: {condition_id: '700000000000000000000001', values: {'weight %': 0.8, 'standard deviation': 0.1}},
|
req: {sample_id: '400000000000000000000001', values: {'weight %': 0.8, 'standard deviation': 0.1}},
|
||||||
res: {status: 'Invalid body format', details: '"measurement_template" is required'}
|
res: {status: 'Invalid body format', details: '"measurement_template" is required'}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -477,7 +525,7 @@ describe('/measurement', () => {
|
|||||||
url: '/measurement/new',
|
url: '/measurement/new',
|
||||||
auth: {basic: 'janedoe'},
|
auth: {basic: 'janedoe'},
|
||||||
httpStatus: 403,
|
httpStatus: 403,
|
||||||
req: {condition_id: '700000000000000000000003', values: {'weight %': 0.8, 'standard deviation': 0.1}, measurement_template: '300000000000000000000002'}
|
req: {sample_id: '400000000000000000000003', values: {'weight %': 0.8, 'standard deviation': 0.1}, measurement_template: '300000000000000000000002'}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
it('accepts adding a measurement to the sample of another user for a maintain/admin user', done => {
|
it('accepts adding a measurement to the sample of another user for a maintain/admin user', done => {
|
||||||
@ -486,12 +534,12 @@ describe('/measurement', () => {
|
|||||||
url: '/measurement/new',
|
url: '/measurement/new',
|
||||||
auth: {basic: 'admin'},
|
auth: {basic: 'admin'},
|
||||||
httpStatus: 200,
|
httpStatus: 200,
|
||||||
req: {condition_id: '700000000000000000000001', values: {'weight %': 0.8, 'standard deviation': 0.1}, measurement_template: '300000000000000000000002'}
|
req: {sample_id: '400000000000000000000001', values: {'weight %': 0.8, 'standard deviation': 0.1}, measurement_template: '300000000000000000000002'}
|
||||||
}).end((err, res) => {
|
}).end((err, res) => {
|
||||||
if (err) return done(err);
|
if (err) return done(err);
|
||||||
should(res.body).have.only.keys('_id', 'condition_id', 'values', 'measurement_template');
|
should(res.body).have.only.keys('_id', 'sample_id', 'values', 'measurement_template');
|
||||||
should(res.body).have.property('_id').be.type('string');
|
should(res.body).have.property('_id').be.type('string');
|
||||||
should(res.body).have.property('condition_id', '700000000000000000000001');
|
should(res.body).have.property('sample_id', '400000000000000000000001');
|
||||||
should(res.body).have.property('measurement_template', '300000000000000000000002');
|
should(res.body).have.property('measurement_template', '300000000000000000000002');
|
||||||
should(res.body).have.property('values');
|
should(res.body).have.property('values');
|
||||||
should(res.body.values).have.property('weight %', 0.8);
|
should(res.body.values).have.property('weight %', 0.8);
|
||||||
@ -505,7 +553,7 @@ describe('/measurement', () => {
|
|||||||
url: '/measurement/new',
|
url: '/measurement/new',
|
||||||
auth: {key: 'janedoe'},
|
auth: {key: 'janedoe'},
|
||||||
httpStatus: 401,
|
httpStatus: 401,
|
||||||
req: {condition_id: '700000000000000000000001', values: {'weight %': 0.8, 'standard deviation': 0.1}, measurement_template: '300000000000000000000002'}
|
req: {sample_id: '400000000000000000000001', values: {'weight %': 0.8, 'standard deviation': 0.1}, measurement_template: '300000000000000000000002'}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
it('rejects requests from a read user', done => {
|
it('rejects requests from a read user', done => {
|
||||||
@ -514,7 +562,7 @@ describe('/measurement', () => {
|
|||||||
url: '/measurement/new',
|
url: '/measurement/new',
|
||||||
auth: {basic: 'user'},
|
auth: {basic: 'user'},
|
||||||
httpStatus: 403,
|
httpStatus: 403,
|
||||||
req: {condition_id: '700000000000000000000001', values: {'weight %': 0.8, 'standard deviation': 0.1}, measurement_template: '300000000000000000000002'}
|
req: {sample_id: '400000000000000000000001', values: {'weight %': 0.8, 'standard deviation': 0.1}, measurement_template: '300000000000000000000002'}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
it('rejects unauthorized requests', done => {
|
it('rejects unauthorized requests', done => {
|
||||||
@ -522,7 +570,7 @@ describe('/measurement', () => {
|
|||||||
method: 'post',
|
method: 'post',
|
||||||
url: '/measurement/new',
|
url: '/measurement/new',
|
||||||
httpStatus: 401,
|
httpStatus: 401,
|
||||||
req: {condition_id: '700000000000000000000001', values: {'weight %': 0.8, 'standard deviation': 0.1}, measurement_template: '300000000000000000000002'}
|
req: {sample_id: '400000000000000000000001', values: {'weight %': 0.8, 'standard deviation': 0.1}, measurement_template: '300000000000000000000002'}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -2,12 +2,13 @@ import express from 'express';
|
|||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
|
|
||||||
import MeasurementModel from '../models/measurement';
|
import MeasurementModel from '../models/measurement';
|
||||||
import ConditionModel from '../models/condition';
|
|
||||||
import MeasurementTemplateModel from '../models/measurement_template';
|
import MeasurementTemplateModel from '../models/measurement_template';
|
||||||
|
import SampleModel from '../models/sample';
|
||||||
import MeasurementValidate from './validate/measurement';
|
import MeasurementValidate from './validate/measurement';
|
||||||
import IdValidate from './validate/id';
|
import IdValidate from './validate/id';
|
||||||
import res400 from './validate/res400';
|
import res400 from './validate/res400';
|
||||||
import ParametersValidate from './validate/parameters';
|
import ParametersValidate from './validate/parameters';
|
||||||
|
import globals from '../globals';
|
||||||
|
|
||||||
|
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
@ -15,11 +16,12 @@ const router = express.Router();
|
|||||||
router.get('/measurement/' + IdValidate.parameter(), (req, res, next) => {
|
router.get('/measurement/' + IdValidate.parameter(), (req, res, next) => {
|
||||||
if (!req.auth(res, ['read', 'write', 'maintain', 'dev', 'admin'], 'all')) return;
|
if (!req.auth(res, ['read', 'write', 'maintain', 'dev', 'admin'], 'all')) return;
|
||||||
|
|
||||||
MeasurementModel.findById(req.params.id).lean().exec((err, data) => {
|
MeasurementModel.findById(req.params.id).lean().exec((err, data: any) => {
|
||||||
if (err) return next(err);
|
if (err) return next(err);
|
||||||
if (!data) {
|
if (!data) {
|
||||||
return res.status(404).json({status: 'Not found'});
|
return res.status(404).json({status: 'Not found'});
|
||||||
}
|
}
|
||||||
|
if (data.status ===globals.status.deleted && !req.auth(res, ['maintain', 'admin'], 'all')) return; // deleted measurements only available for maintain/admin
|
||||||
|
|
||||||
res.json(MeasurementValidate.output(data));
|
res.json(MeasurementValidate.output(data));
|
||||||
});
|
});
|
||||||
@ -34,19 +36,19 @@ router.put('/measurement/' + IdValidate.parameter(), async (req, res, next) => {
|
|||||||
const data = await MeasurementModel.findById(req.params.id).lean().exec().catch(err => {next(err);}) as any;
|
const data = await MeasurementModel.findById(req.params.id).lean().exec().catch(err => {next(err);}) as any;
|
||||||
if (data instanceof Error) return;
|
if (data instanceof Error) return;
|
||||||
if (!data) {
|
if (!data) {
|
||||||
res.status(404).json({status: 'Not found'});
|
return res.status(404).json({status: 'Not found'});
|
||||||
}
|
}
|
||||||
|
|
||||||
// add properties needed for conditionIdCheck
|
// add properties needed for sampleIdCheck
|
||||||
measurement.measurement_template = data.measurement_template;
|
measurement.measurement_template = data.measurement_template;
|
||||||
measurement.condition_id = data.condition_id;
|
measurement.sample_id = data.sample_id;
|
||||||
if (!await conditionIdCheck(measurement, req, res, next)) return;
|
if (!await sampleIdCheck(measurement, req, res, next)) return;
|
||||||
|
|
||||||
// check for changes
|
// check for changes
|
||||||
if (measurement.values) {
|
if (measurement.values) { // fill not changed values from database
|
||||||
measurement.values = _.assign({}, data.values, measurement.values);
|
measurement.values = _.assign({}, data.values, measurement.values);
|
||||||
if (!_.isEqual(measurement.values, data.values)) {
|
if (!_.isEqual(measurement.values, data.values)) {
|
||||||
measurement.status = 0; // set status to new
|
measurement.status = globals.status.new; // set status to new
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -63,12 +65,12 @@ router.delete('/measurement/' + IdValidate.parameter(), (req, res, next) => {
|
|||||||
MeasurementModel.findById(req.params.id).lean().exec(async (err, data) => {
|
MeasurementModel.findById(req.params.id).lean().exec(async (err, data) => {
|
||||||
if (err) return next(err);
|
if (err) return next(err);
|
||||||
if (!data) {
|
if (!data) {
|
||||||
res.status(404).json({status: 'Not found'});
|
return res.status(404).json({status: 'Not found'});
|
||||||
}
|
}
|
||||||
if (!await conditionIdCheck(data, req, res, next)) return;
|
if (!await sampleIdCheck(data, req, res, next)) return;
|
||||||
await MeasurementModel.findByIdAndUpdate(req.params.id, {status: -1}).lean().exec(err => {
|
await MeasurementModel.findByIdAndUpdate(req.params.id, {status:globals.status.deleted}).lean().exec(err => {
|
||||||
if (err) return next(err);
|
if (err) return next(err);
|
||||||
res.json({status: 'OK'});
|
return res.json({status: 'OK'});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -79,8 +81,9 @@ router.post('/measurement/new', async (req, res, next) => {
|
|||||||
const {error, value: measurement} = MeasurementValidate.input(req.body, 'new');
|
const {error, value: measurement} = MeasurementValidate.input(req.body, 'new');
|
||||||
if (error) return res400(error, res);
|
if (error) return res400(error, res);
|
||||||
|
|
||||||
if (!await conditionIdCheck(measurement, req, res, next)) return;
|
if (!await sampleIdCheck(measurement, req, res, next)) return;
|
||||||
if (!await templateCheck(measurement, 'new', res, next)) return;
|
measurement.values = await templateCheck(measurement, 'new', res, next);
|
||||||
|
if (!measurement.values) return;
|
||||||
|
|
||||||
measurement.status = 0;
|
measurement.status = 0;
|
||||||
await new MeasurementModel(measurement).save((err, data) => {
|
await new MeasurementModel(measurement).save((err, data) => {
|
||||||
@ -93,25 +96,38 @@ router.post('/measurement/new', async (req, res, next) => {
|
|||||||
module.exports = router;
|
module.exports = router;
|
||||||
|
|
||||||
|
|
||||||
async function conditionIdCheck (measurement, req, res, next) { // validate condition_id, returns false if invalid
|
async function sampleIdCheck (measurement, req, res, next) { // validate sample_id, returns false if invalid or user has no access for this sample
|
||||||
const sampleData = await ConditionModel.findById(measurement.condition_id).populate('sample_id').lean().exec().catch(err => {next(err); return false;}) as any;
|
const sampleData = await SampleModel.findById(measurement.sample_id).lean().exec().catch(err => {next(err); return false;}) as any;
|
||||||
if (!sampleData) { // sample_id not found
|
if (!sampleData) { // sample_id not found
|
||||||
res.status(400).json({status: 'Condition id not available'});
|
res.status(400).json({status: 'Sample id not available'});
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if (sampleData.sample_id.user_id.toString() !== req.authDetails.id && !req.auth(res, ['maintain', 'admin'], 'basic')) return false; // sample does not belong to user
|
if (sampleData.user_id.toString() !== req.authDetails.id && !req.auth(res, ['maintain', 'admin'], 'basic')) return false; // sample does not belong to user
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function templateCheck (measurement, param, res, next) { // validate measurement_template and values, param for new/change
|
async function templateCheck (measurement, param, res, next) { // validate measurement_template and values, returns values, true if values are {} or false if invalid, param for 'new'/'change'
|
||||||
const templateData = await MeasurementTemplateModel.findById(measurement.measurement_template).lean().exec().catch(err => {next(err); return false;}) as any;
|
const templateData = await MeasurementTemplateModel.findById(measurement.measurement_template).lean().exec().catch(err => {next(err); return false;}) as any;
|
||||||
if (!templateData) { // template not found
|
if (!templateData) { // template not found
|
||||||
res.status(400).json({status: 'Measurement template not available'});
|
res.status(400).json({status: 'Measurement template not available'});
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// validate values
|
// fill not given values for new measurements
|
||||||
const {error, value: ignore} = ParametersValidate.input(measurement.values, templateData.parameters, param);
|
if (param === 'new') {
|
||||||
if (error) {res400(error, res); return false;}
|
if (Object.keys(measurement.values).length === 0) {
|
||||||
return true;
|
res.status(400).json({status: 'At least one value is required'});
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
const fillValues = {}; // initialize not given values with null
|
||||||
|
templateData.parameters.forEach(parameter => {
|
||||||
|
fillValues[parameter.name] = null;
|
||||||
|
});
|
||||||
|
measurement.values = _.assign({}, fillValues, measurement.values);
|
||||||
|
}
|
||||||
|
|
||||||
|
// validate values
|
||||||
|
const {error, value} = ParametersValidate.input(measurement.values, templateData.parameters, 'null');
|
||||||
|
if (error) {res400(error, res); return false;}
|
||||||
|
return value || true;
|
||||||
}
|
}
|
@ -1,4 +1,5 @@
|
|||||||
import TestHelper from "../test/helper";
|
import TestHelper from "../test/helper";
|
||||||
|
import db from '../db';
|
||||||
|
|
||||||
|
|
||||||
describe('/', () => {
|
describe('/', () => {
|
||||||
@ -6,6 +7,7 @@ describe('/', () => {
|
|||||||
before(done => TestHelper.before(done));
|
before(done => TestHelper.before(done));
|
||||||
beforeEach(done => server = TestHelper.beforeEach(server, done));
|
beforeEach(done => server = TestHelper.beforeEach(server, done));
|
||||||
afterEach(done => TestHelper.afterEach(server, done));
|
afterEach(done => TestHelper.afterEach(server, done));
|
||||||
|
after(done => TestHelper.after(done));
|
||||||
|
|
||||||
describe('GET /', () => {
|
describe('GET /', () => {
|
||||||
it('returns the root message', done => {
|
it('returns the root message', done => {
|
||||||
@ -40,7 +42,15 @@ describe('/', () => {
|
|||||||
TestHelper.request(server, done, {
|
TestHelper.request(server, done, {
|
||||||
method: 'get',
|
method: 'get',
|
||||||
url: '/authorized',
|
url: '/authorized',
|
||||||
auth: {name: 'admin', pass: 'Abc123!!'},
|
auth: {basic: {name: 'admin', pass: 'Abc123!!'}},
|
||||||
|
httpStatus: 401
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it('does not work with incorrect username', done => {
|
||||||
|
TestHelper.request(server, done, {
|
||||||
|
method: 'get',
|
||||||
|
url: '/authorized',
|
||||||
|
auth: {basic: {name: 'adminxx', pass: 'Abc123!!'}},
|
||||||
httpStatus: 401
|
httpStatus: 401
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -66,4 +76,65 @@ describe('/', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('An invalid JSON body', () => {
|
||||||
|
it('is rejected', done => {
|
||||||
|
TestHelper.request(server, done, {
|
||||||
|
method: 'post',
|
||||||
|
url: '/',
|
||||||
|
httpStatus: 400,
|
||||||
|
reqType: 'json',
|
||||||
|
req: '{"xxx"}',
|
||||||
|
res: {status: 'Invalid JSON body'}
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('A not connected database', () => { // RUN AS LAST OR RECONNECT DATABASE!!
|
||||||
|
it('resolves to an 500 error', done => {
|
||||||
|
db.disconnect(() => {
|
||||||
|
TestHelper.request(server, done, {
|
||||||
|
method: 'get',
|
||||||
|
url: '/',
|
||||||
|
httpStatus: 500
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('The /api/{url} redirect', () => {
|
||||||
|
let server;
|
||||||
|
let counter = 0; // count number of current test method
|
||||||
|
before(done => {
|
||||||
|
process.env.port = '2999';
|
||||||
|
db.connect('test', done);
|
||||||
|
});
|
||||||
|
beforeEach(done => {
|
||||||
|
process.env.NODE_ENV = counter === 1 ? 'production' : 'test';
|
||||||
|
counter ++;
|
||||||
|
server = TestHelper.beforeEach(server, done);
|
||||||
|
});
|
||||||
|
afterEach(done => TestHelper.afterEach(server, done));
|
||||||
|
after(done => TestHelper.after(done));
|
||||||
|
|
||||||
|
|
||||||
|
it('returns the right method', done => {
|
||||||
|
TestHelper.request(server, done, {
|
||||||
|
method: 'get',
|
||||||
|
url: '/api/authorized',
|
||||||
|
auth: {basic: 'admin'},
|
||||||
|
httpStatus: 200,
|
||||||
|
res: {status: 'Authorization successful', method: 'basic'}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it('is disabled in production', done => {
|
||||||
|
TestHelper.request(server, done, {
|
||||||
|
method: 'get',
|
||||||
|
url: '/api/authorized',
|
||||||
|
auth: {basic: 'admin'},
|
||||||
|
httpStatus: 404
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
@ -3,16 +3,23 @@ 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";
|
||||||
|
import globals from '../globals';
|
||||||
|
|
||||||
// TODO: generate output for ML in format DPT -> data, implement filtering, field selection
|
// TODO: generate output for ML in format DPT -> data, implement filtering, field selection
|
||||||
|
// TODO: filter by not completely filled/no measurements
|
||||||
// TODO: write script for data import
|
// TODO: write script for data import
|
||||||
// TODO: delete everything (measurements, condition) with sample
|
// TODO: delete everything (measurements, condition) with sample
|
||||||
|
// TODO: allow adding sample numbers for existing samples
|
||||||
|
|
||||||
|
// TODO: Do not allow validation or measurement entry without condition
|
||||||
|
|
||||||
|
|
||||||
describe('/sample', () => {
|
describe('/sample', () => {
|
||||||
let server;
|
let server;
|
||||||
before(done => TestHelper.before(done));
|
before(done => TestHelper.before(done));
|
||||||
beforeEach(done => server = TestHelper.beforeEach(server, done));
|
beforeEach(done => server = TestHelper.beforeEach(server, done));
|
||||||
afterEach(done => TestHelper.afterEach(server, done));
|
afterEach(done => TestHelper.afterEach(server, done));
|
||||||
|
after(done => TestHelper.after(done));
|
||||||
|
|
||||||
describe('GET /samples', () => {
|
describe('GET /samples', () => {
|
||||||
it('returns all samples', done => {
|
it('returns all samples', done => {
|
||||||
@ -24,14 +31,16 @@ describe('/sample', () => {
|
|||||||
}).end((err, res) => {
|
}).end((err, res) => {
|
||||||
if (err) return done(err);
|
if (err) return done(err);
|
||||||
const json = require('../test/db.json');
|
const json = require('../test/db.json');
|
||||||
should(res.body).have.lengthOf(json.collections.samples.filter(e => e.status === 10).length);
|
should(res.body).have.lengthOf(json.collections.samples.filter(e => e.status ===globals.status.validated).length);
|
||||||
should(res.body).matchEach(sample => {
|
should(res.body).matchEach(sample => {
|
||||||
should(sample).have.only.keys('_id', 'number', 'type', 'color', 'batch', 'material_id', 'note_id', 'user_id');
|
should(sample).have.only.keys('_id', 'number', 'type', 'color', 'batch', 'condition', 'material_id', 'note_id', 'user_id');
|
||||||
should(sample).have.property('_id').be.type('string');
|
should(sample).have.property('_id').be.type('string');
|
||||||
should(sample).have.property('number').be.type('string');
|
should(sample).have.property('number').be.type('string');
|
||||||
should(sample).have.property('type').be.type('string');
|
should(sample).have.property('type').be.type('string');
|
||||||
should(sample).have.property('color').be.type('string');
|
should(sample).have.property('color').be.type('string');
|
||||||
should(sample).have.property('batch').be.type('string');
|
should(sample).have.property('batch').be.type('string');
|
||||||
|
should(sample).have.property('condition').be.type('object');
|
||||||
|
should(sample.condition).have.property('condition_template').be.type('string');
|
||||||
should(sample).have.property('material_id').be.type('string');
|
should(sample).have.property('material_id').be.type('string');
|
||||||
should(sample).have.property('note_id');
|
should(sample).have.property('note_id');
|
||||||
should(sample).have.property('user_id').be.type('string');
|
should(sample).have.property('user_id').be.type('string');
|
||||||
@ -48,17 +57,19 @@ describe('/sample', () => {
|
|||||||
}).end((err, res) => {
|
}).end((err, res) => {
|
||||||
if (err) return done(err);
|
if (err) return done(err);
|
||||||
const json = require('../test/db.json');
|
const json = require('../test/db.json');
|
||||||
should(res.body).have.lengthOf(json.collections.samples.filter(e => e.status === 10).length);
|
should(res.body).have.lengthOf(json.collections.samples.filter(e => e.status ===globals.status.validated).length);
|
||||||
should(res.body).matchEach(material => {
|
should(res.body).matchEach(sample => {
|
||||||
should(material).have.only.keys('_id', 'number', 'type', 'color', 'batch', 'material_id', 'note_id', 'user_id');
|
should(sample).have.only.keys('_id', 'number', 'type', 'color', 'batch', 'condition', 'material_id', 'note_id', 'user_id');
|
||||||
should(material).have.property('_id').be.type('string');
|
should(sample).have.property('_id').be.type('string');
|
||||||
should(material).have.property('number').be.type('string');
|
should(sample).have.property('number').be.type('string');
|
||||||
should(material).have.property('type').be.type('string');
|
should(sample).have.property('type').be.type('string');
|
||||||
should(material).have.property('color').be.type('string');
|
should(sample).have.property('color').be.type('string');
|
||||||
should(material).have.property('batch').be.type('string');
|
should(sample).have.property('batch').be.type('string');
|
||||||
should(material).have.property('material_id').be.type('string');
|
should(sample).have.property('condition').be.type('object');
|
||||||
should(material).have.property('note_id');
|
should(sample.condition).have.property('condition_template').be.type('string');
|
||||||
should(material).have.property('user_id').be.type('string');
|
should(sample).have.property('material_id').be.type('string');
|
||||||
|
should(sample).have.property('note_id');
|
||||||
|
should(sample).have.property('user_id').be.type('string');
|
||||||
});
|
});
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
@ -83,25 +94,28 @@ describe('/sample', () => {
|
|||||||
if (err) return done(err);
|
if (err) return done(err);
|
||||||
const json = require('../test/db.json');
|
const json = require('../test/db.json');
|
||||||
let asyncCounter = res.body.length;
|
let asyncCounter = res.body.length;
|
||||||
should(res.body).have.lengthOf(json.collections.samples.filter(e => e.status === 0).length);
|
should(res.body).have.lengthOf(json.collections.samples.filter(e => e.status ===globals.status.new).length);
|
||||||
should(res.body).matchEach(sample => {
|
should(res.body).matchEach(sample => {
|
||||||
should(sample).have.only.keys('_id', 'number', 'type', 'color', 'batch', 'material_id', 'note_id', 'user_id');
|
should(sample).have.only.keys('_id', 'number', 'type', 'color', 'batch', 'condition', 'material_id', 'note_id', 'user_id');
|
||||||
should(sample).have.property('_id').be.type('string');
|
should(sample).have.property('_id').be.type('string');
|
||||||
should(sample).have.property('number').be.type('string');
|
should(sample).have.property('number').be.type('string');
|
||||||
should(sample).have.property('type').be.type('string');
|
should(sample).have.property('type').be.type('string');
|
||||||
should(sample).have.property('color').be.type('string');
|
should(sample).have.property('color').be.type('string');
|
||||||
should(sample).have.property('batch').be.type('string');
|
should(sample).have.property('batch').be.type('string');
|
||||||
|
should(sample).have.property('condition').be.type('object');
|
||||||
|
if (Object.keys(sample.condition).length > 0) {
|
||||||
|
should(sample.condition).have.property('condition_template').be.type('string');
|
||||||
|
}
|
||||||
should(sample).have.property('material_id').be.type('string');
|
should(sample).have.property('material_id').be.type('string');
|
||||||
should(sample).have.property('note_id');
|
should(sample).have.property('note_id');
|
||||||
should(sample).have.property('user_id').be.type('string');
|
should(sample).have.property('user_id').be.type('string');
|
||||||
SampleModel.findById(sample._id).lean().exec((err, data) => {
|
SampleModel.findById(sample._id).lean().exec((err, data) => {
|
||||||
should(data).have.property('status', 0);
|
should(data).have.property('status',globals.status.new);
|
||||||
if (--asyncCounter === 0) {
|
if (--asyncCounter === 0) {
|
||||||
done();
|
done();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
done();
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
it('returns all deleted samples', done => {
|
it('returns all deleted samples', done => {
|
||||||
@ -116,23 +130,26 @@ describe('/sample', () => {
|
|||||||
let asyncCounter = res.body.length;
|
let asyncCounter = res.body.length;
|
||||||
should(res.body).have.lengthOf(json.collections.samples.filter(e => e.status === -1).length);
|
should(res.body).have.lengthOf(json.collections.samples.filter(e => e.status === -1).length);
|
||||||
should(res.body).matchEach(sample => {
|
should(res.body).matchEach(sample => {
|
||||||
should(sample).have.only.keys('_id', 'number', 'type', 'color', 'batch', 'material_id', 'note_id', 'user_id');
|
should(sample).have.only.keys('_id', 'number', 'type', 'color', 'batch', 'condition', 'material_id', 'note_id', 'user_id');
|
||||||
should(sample).have.property('_id').be.type('string');
|
should(sample).have.property('_id').be.type('string');
|
||||||
should(sample).have.property('number').be.type('string');
|
should(sample).have.property('number').be.type('string');
|
||||||
should(sample).have.property('type').be.type('string');
|
should(sample).have.property('type').be.type('string');
|
||||||
should(sample).have.property('color').be.type('string');
|
should(sample).have.property('color').be.type('string');
|
||||||
should(sample).have.property('batch').be.type('string');
|
should(sample).have.property('batch').be.type('string');
|
||||||
|
should(sample).have.property('condition').be.type('object');
|
||||||
|
should(sample.condition).have.property('condition_template').be.type('string');
|
||||||
|
should(sample.condition).have.property('condition_template').be.type('string');
|
||||||
|
should(sample.condition).have.property('condition_template').be.type('string');
|
||||||
should(sample).have.property('material_id').be.type('string');
|
should(sample).have.property('material_id').be.type('string');
|
||||||
should(sample).have.property('note_id');
|
should(sample).have.property('note_id');
|
||||||
should(sample).have.property('user_id').be.type('string');
|
should(sample).have.property('user_id').be.type('string');
|
||||||
SampleModel.findById(sample._id).lean().exec((err, data) => {
|
SampleModel.findById(sample._id).lean().exec((err, data) => {
|
||||||
should(data).have.property('status', -1);
|
should(data).have.property('status',globals.status.deleted);
|
||||||
if (--asyncCounter === 0) {
|
if (--asyncCounter === 0) {
|
||||||
done();
|
done();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
done();
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
it('rejects requests from a write user', done => {
|
it('rejects requests from a write user', done => {
|
||||||
@ -160,6 +177,73 @@ describe('/sample', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('GET /sample/{id}', () => {
|
||||||
|
it('returns the right sample', done => {
|
||||||
|
TestHelper.request(server, done, {
|
||||||
|
method: 'get',
|
||||||
|
url: '/sample/400000000000000000000003',
|
||||||
|
auth: {basic: 'janedoe'},
|
||||||
|
httpStatus: 200,
|
||||||
|
res: {_id: '400000000000000000000003', number: '33', type: 'part', color: 'black', batch: '1704-005', condition: {material: 'copper', weeks: 3, condition_template: '200000000000000000000001'}, material: {_id: '100000000000000000000005', name: 'Amodel A 1133 HS', supplier: 'Solvay', group: 'PPA', mineral: 0, glass_fiber: 33, carbon_fiber: 0, numbers: [{color: 'black', number: '5514262406'}]}, notes: {comment: '', sample_references: [{sample_id: '400000000000000000000004', relation: 'granulate to sample'}], custom_fields: {'not allowed for new applications': true}}, user: 'admin'}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('works with an API key', done => {
|
||||||
|
TestHelper.request(server, done, {
|
||||||
|
method: 'get',
|
||||||
|
url: '/sample/400000000000000000000003',
|
||||||
|
auth: {key: 'janedoe'},
|
||||||
|
httpStatus: 200,
|
||||||
|
res: {_id: '400000000000000000000003', number: '33', type: 'part', color: 'black', batch: '1704-005', condition: {material: 'copper', weeks: 3, condition_template: '200000000000000000000001'}, material: {_id: '100000000000000000000005', name: 'Amodel A 1133 HS', supplier: 'Solvay', group: 'PPA', mineral: 0, glass_fiber: 33, carbon_fiber: 0, numbers: [{color: 'black', number: '5514262406'}]}, notes: {comment: '', sample_references: [{sample_id: '400000000000000000000004', relation: 'granulate to sample'}], custom_fields: {'not allowed for new applications': true}}, user: 'admin'}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns a deleted sample for a maintain/admin user', done => {
|
||||||
|
TestHelper.request(server, done, {
|
||||||
|
method: 'get',
|
||||||
|
url: '/sample/400000000000000000000005',
|
||||||
|
auth: {basic: 'admin'},
|
||||||
|
httpStatus: 200,
|
||||||
|
res: {_id: '400000000000000000000005', number: 'Rng33', type: 'granulate', color: 'black', batch: '1653000308', condition: {condition_template: '200000000000000000000003'}, material: {_id: '100000000000000000000005', name: 'Amodel A 1133 HS', supplier: 'Solvay', group: 'PPA', mineral: 0, glass_fiber: 33, carbon_fiber: 0, numbers: [{color: 'black', number: '5514262406'}]}, notes: {}, user: 'admin'}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns 403 for a write user when requesting a deleted sample', done => {
|
||||||
|
TestHelper.request(server, done, {
|
||||||
|
method: 'get',
|
||||||
|
url: '/sample/400000000000000000000005',
|
||||||
|
auth: {basic: 'janedoe'},
|
||||||
|
httpStatus: 403
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns 404 for an unknown sample', done => {
|
||||||
|
TestHelper.request(server, done, {
|
||||||
|
method: 'get',
|
||||||
|
url: '/sample/000000000000000000000005',
|
||||||
|
auth: {basic: 'janedoe'},
|
||||||
|
httpStatus: 404
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('rejects an invalid id', done => {
|
||||||
|
TestHelper.request(server, done, {
|
||||||
|
method: 'get',
|
||||||
|
url: '/sample/400000000h00000000000005',
|
||||||
|
auth: {basic: 'janedoe'},
|
||||||
|
httpStatus: 404
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('rejects unauthorized requests', done => {
|
||||||
|
TestHelper.request(server, done, {
|
||||||
|
method: 'get',
|
||||||
|
url: '/sample/400000000000000000000005',
|
||||||
|
httpStatus: 401
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('PUT /sample/{id}', () => {
|
describe('PUT /sample/{id}', () => {
|
||||||
it('returns the right sample', done => {
|
it('returns the right sample', done => {
|
||||||
TestHelper.request(server, done, {
|
TestHelper.request(server, done, {
|
||||||
@ -168,7 +252,7 @@ describe('/sample', () => {
|
|||||||
auth: {basic: 'janedoe'},
|
auth: {basic: 'janedoe'},
|
||||||
httpStatus: 200,
|
httpStatus: 200,
|
||||||
req: {},
|
req: {},
|
||||||
res: {_id: '400000000000000000000001', number: '1', type: 'granulate', color: 'black', batch: '', material_id: '100000000000000000000004', note_id: null, user_id: '000000000000000000000002'}
|
res: {_id: '400000000000000000000001', number: '1', type: 'granulate', color: 'black', batch: '', condition: {material: 'copper', weeks: 3, condition_template: '200000000000000000000001'}, material_id: '100000000000000000000004', note_id: null, user_id: '000000000000000000000002'}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
it('keeps unchanged properties', done => {
|
it('keeps unchanged properties', done => {
|
||||||
@ -177,21 +261,22 @@ describe('/sample', () => {
|
|||||||
url: '/sample/400000000000000000000001',
|
url: '/sample/400000000000000000000001',
|
||||||
auth: {basic: 'janedoe'},
|
auth: {basic: 'janedoe'},
|
||||||
httpStatus: 200,
|
httpStatus: 200,
|
||||||
req: {type: 'granulate', color: 'black', batch: '', material_id: '100000000000000000000004', notes: {}}
|
req: {type: 'granulate', color: 'black', batch: '', condition: {material: 'copper', weeks: 3, condition_template: '200000000000000000000001'}, 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: '', condition: {material: 'copper', weeks: 3, condition_template: '200000000000000000000001'}, material_id: '100000000000000000000004', note_id: null, user_id: '000000000000000000000002'});
|
||||||
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', 'condition', 'material_id', 'note_id', 'user_id', 'status', '__v');
|
||||||
should(data).have.property('_id');
|
should(data).have.property('_id');
|
||||||
should(data).have.property('number', '1');
|
should(data).have.property('number', '1');
|
||||||
should(data).have.property('color', 'black');
|
should(data).have.property('color', 'black');
|
||||||
should(data).have.property('type', 'granulate');
|
should(data).have.property('type', 'granulate');
|
||||||
should(data).have.property('batch', '');
|
should(data).have.property('batch', '');
|
||||||
|
should(data).have.property('condition', {material: 'copper', weeks: 3, condition_template: '200000000000000000000001'});
|
||||||
should(data.material_id.toString()).be.eql('100000000000000000000004');
|
should(data.material_id.toString()).be.eql('100000000000000000000004');
|
||||||
should(data.user_id.toString()).be.eql('000000000000000000000002');
|
should(data.user_id.toString()).be.eql('000000000000000000000002');
|
||||||
should(data).have.property('status', 10);
|
should(data).have.property('status',globals.status.validated);
|
||||||
should(data).have.property('note_id', null);
|
should(data).have.property('note_id', null);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
@ -206,10 +291,27 @@ describe('/sample', () => {
|
|||||||
req: {type: 'granulate'}
|
req: {type: 'granulate'}
|
||||||
}).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: '', condition: {material: 'copper', weeks: 3, condition_template: '200000000000000000000001'}, material_id: '100000000000000000000004', note_id: null, user_id: '000000000000000000000002'});
|
||||||
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.property('status', 10);
|
should(data).have.property('status',globals.status.validated);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it('keeps an unchanged condition', done => {
|
||||||
|
TestHelper.request(server, done, {
|
||||||
|
method: 'put',
|
||||||
|
url: '/sample/400000000000000000000001',
|
||||||
|
auth: {basic: 'janedoe'},
|
||||||
|
httpStatus: 200,
|
||||||
|
req: {condition: {material: 'copper', weeks: 3, condition_template: '200000000000000000000001'}}
|
||||||
|
}).end((err, res) => {
|
||||||
|
if (err) return done(err);
|
||||||
|
should(res.body).be.eql({_id: '400000000000000000000001', number: '1', type: 'granulate', color: 'black', batch: '', condition: {material: 'copper', weeks: 3, condition_template: '200000000000000000000001'}, material_id: '100000000000000000000004', note_id: null, user_id: '000000000000000000000002'});
|
||||||
|
SampleModel.findById('400000000000000000000001').lean().exec((err, data: any) => {
|
||||||
|
if (err) return done (err);
|
||||||
|
should(data).have.property('status',globals.status.validated);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -223,18 +325,21 @@ describe('/sample', () => {
|
|||||||
req: {notes: {comment: 'Stoff gesperrt', sample_references: []}}
|
req: {notes: {comment: 'Stoff gesperrt', sample_references: []}}
|
||||||
}).end((err, res) => {
|
}).end((err, res) => {
|
||||||
if (err) return done(err);
|
if (err) return done(err);
|
||||||
should(res.body).be.eql({_id: '400000000000000000000002', number: '21', type: 'granulate', color: 'natural', batch: '1560237365', material_id: '100000000000000000000001', note_id: '500000000000000000000001', user_id: '000000000000000000000002'});
|
should(res.body).be.eql({_id: '400000000000000000000002', number: '21', type: 'granulate', color: 'natural', batch: '1560237365', condition: {material: 'copper', weeks: 3, condition_template: '200000000000000000000001'}, material_id: '100000000000000000000001', note_id: '500000000000000000000001', user_id: '000000000000000000000002'});
|
||||||
SampleModel.findById('400000000000000000000002').lean().exec((err, data: any) => {
|
SampleModel.findById('400000000000000000000002').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', 'condition', 'material_id', 'note_id', 'user_id', 'status', '__v');
|
||||||
should(data).have.property('_id');
|
should(data).have.property('_id');
|
||||||
should(data).have.property('number', '21');
|
should(data).have.property('number', '21');
|
||||||
should(data).have.property('color', 'natural');
|
should(data).have.property('color', 'natural');
|
||||||
should(data).have.property('type', 'granulate');
|
should(data).have.property('type', 'granulate');
|
||||||
should(data).have.property('batch', '1560237365');
|
should(data).have.property('batch', '1560237365');
|
||||||
|
should(data.condition).have.property('material', 'copper');
|
||||||
|
should(data.condition).have.property('weeks', 3);
|
||||||
|
should(data.condition.condition_template.toString()).be.eql('200000000000000000000001');
|
||||||
should(data.material_id.toString()).be.eql('100000000000000000000001');
|
should(data.material_id.toString()).be.eql('100000000000000000000001');
|
||||||
should(data.user_id.toString()).be.eql('000000000000000000000002');
|
should(data.user_id.toString()).be.eql('000000000000000000000002');
|
||||||
should(data).have.property('status', 10);
|
should(data).have.property('status',globals.status.validated);
|
||||||
should(data.note_id.toString()).be.eql('500000000000000000000001');
|
should(data.note_id.toString()).be.eql('500000000000000000000001');
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
@ -246,20 +351,21 @@ describe('/sample', () => {
|
|||||||
url: '/sample/400000000000000000000001',
|
url: '/sample/400000000000000000000001',
|
||||||
auth: {basic: 'janedoe'},
|
auth: {basic: 'janedoe'},
|
||||||
httpStatus: 200,
|
httpStatus: 200,
|
||||||
req: {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', condition: {condition_template: '200000000000000000000003'}, material_id: '100000000000000000000002', notes: {comment: 'Testcomment', sample_references: [{sample_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', 'condition', 'material_id', 'note_id', 'user_id', 'status', '__v');
|
||||||
should(data).have.property('_id');
|
should(data).have.property('_id');
|
||||||
should(data).have.property('number', '1');
|
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');
|
||||||
|
should(data).have.property('condition', {condition_template: '200000000000000000000003'});
|
||||||
should(data.material_id.toString()).be.eql('100000000000000000000002');
|
should(data.material_id.toString()).be.eql('100000000000000000000002');
|
||||||
should(data.user_id.toString()).be.eql('000000000000000000000002');
|
should(data.user_id.toString()).be.eql('000000000000000000000002');
|
||||||
should(data).have.property('status', 0);
|
should(data).have.property('status',globals.status.new);
|
||||||
should(data).have.property('note_id');
|
should(data).have.property('note_id');
|
||||||
NoteModel.findById(data.note_id).lean().exec((err, data: any) => {
|
NoteModel.findById(data.note_id).lean().exec((err, data: any) => {
|
||||||
if (err) return done (err);
|
if (err) return done (err);
|
||||||
@ -267,7 +373,7 @@ describe('/sample', () => {
|
|||||||
should(data).have.property('comment', 'Testcomment');
|
should(data).have.property('comment', 'Testcomment');
|
||||||
should(data).have.property('sample_references');
|
should(data).have.property('sample_references');
|
||||||
should(data.sample_references).have.lengthOf(1);
|
should(data.sample_references).have.lengthOf(1);
|
||||||
should(data.sample_references[0].id.toString()).be.eql('400000000000000000000003');
|
should(data.sample_references[0].sample_id.toString()).be.eql('400000000000000000000003');
|
||||||
should(data.sample_references[0]).have.property('relation', 'part to this sample');
|
should(data.sample_references[0]).have.property('relation', 'part to this sample');
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
@ -350,7 +456,7 @@ describe('/sample', () => {
|
|||||||
url: '/sample/400000000000000000000001',
|
url: '/sample/400000000000000000000001',
|
||||||
auth: {basic: 'janedoe'},
|
auth: {basic: 'janedoe'},
|
||||||
httpStatus: 400,
|
httpStatus: 400,
|
||||||
req: {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: [{sample_id: '400000000000000000000003', relation: 'part to this sample'}]}},
|
||||||
res: {status: 'Color not available for material'}
|
res: {status: 'Color not available for material'}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -360,7 +466,7 @@ describe('/sample', () => {
|
|||||||
url: '/sample/400000000000000000000001',
|
url: '/sample/400000000000000000000001',
|
||||||
auth: {basic: 'janedoe'},
|
auth: {basic: 'janedoe'},
|
||||||
httpStatus: 400,
|
httpStatus: 400,
|
||||||
req: {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: [{sample_id: '400000000000000000000003', relation: 'part to this sample'}]}},
|
||||||
res: {status: 'Material not available'}
|
res: {status: 'Material not available'}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -370,7 +476,7 @@ describe('/sample', () => {
|
|||||||
url: '/sample/400000000000000000000001',
|
url: '/sample/400000000000000000000001',
|
||||||
auth: {basic: 'janedoe'},
|
auth: {basic: 'janedoe'},
|
||||||
httpStatus: 400,
|
httpStatus: 400,
|
||||||
req: {number: 25, 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: [{sample_id: '400000000000000000000003', relation: 'part to this sample'}]}},
|
||||||
res: {status: 'Invalid body format', details: '"number" is not allowed'}
|
res: {status: 'Invalid body format', details: '"number" is not allowed'}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -380,7 +486,7 @@ describe('/sample', () => {
|
|||||||
url: '/sample/400000000000000000000001',
|
url: '/sample/400000000000000000000001',
|
||||||
auth: {basic: 'janedoe'},
|
auth: {basic: 'janedoe'},
|
||||||
httpStatus: 400,
|
httpStatus: 400,
|
||||||
req: {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: [{sample_id: '000000000000000000000003', relation: 'part to this sample'}]}},
|
||||||
res: {status: 'Sample reference not available'}
|
res: {status: 'Sample reference not available'}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -390,7 +496,7 @@ describe('/sample', () => {
|
|||||||
url: '/sample/400000000000000000000001',
|
url: '/sample/400000000000000000000001',
|
||||||
auth: {basic: 'janedoe'},
|
auth: {basic: 'janedoe'},
|
||||||
httpStatus: 400,
|
httpStatus: 400,
|
||||||
req: {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: [{sample_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}/'}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -400,7 +506,87 @@ describe('/sample', () => {
|
|||||||
url: '/sample/10000000000h000000000001',
|
url: '/sample/10000000000h000000000001',
|
||||||
auth: {basic: 'janedoe'},
|
auth: {basic: 'janedoe'},
|
||||||
httpStatus: 404,
|
httpStatus: 404,
|
||||||
req: {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: [{sample_id: '400000000000000000000003', relation: 'part to this sample'}]}},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it('rejects not specified condition parameters', done => {
|
||||||
|
TestHelper.request(server, done, {
|
||||||
|
method: 'put',
|
||||||
|
url: '/sample/400000000000000000000001',
|
||||||
|
auth: {basic: 'janedoe'},
|
||||||
|
httpStatus: 400,
|
||||||
|
req: {condition: {material: 'copper', weeks: 3, xxx: 44, condition_template: '200000000000000000000001'}},
|
||||||
|
res: {status: 'Invalid body format', details: '"xxx" is not allowed'}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it('rejects a condition parameter not in the value range', done => {
|
||||||
|
TestHelper.request(server, done, {
|
||||||
|
method: 'put',
|
||||||
|
url: '/sample/400000000000000000000001',
|
||||||
|
auth: {basic: 'janedoe'},
|
||||||
|
httpStatus: 400,
|
||||||
|
req: {condition: {material: 'xx', weeks: 3, condition_template: '200000000000000000000001'}},
|
||||||
|
res: {status: 'Invalid body format', details: '"material" must be one of [copper, hot air]'}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it('rejects a condition parameter below minimum range', done => {
|
||||||
|
TestHelper.request(server, done, {
|
||||||
|
method: 'put',
|
||||||
|
url: '/sample/400000000000000000000001',
|
||||||
|
auth: {basic: 'janedoe'},
|
||||||
|
httpStatus: 400,
|
||||||
|
req: {condition: {material: 'copper', weeks: 0, condition_template: '200000000000000000000001'}},
|
||||||
|
res: {status: 'Invalid body format', details: '"weeks" must be larger than or equal to 1'}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it('rejects a condition parameter above maximum range', done => {
|
||||||
|
TestHelper.request(server, done, {
|
||||||
|
method: 'put',
|
||||||
|
url: '/sample/400000000000000000000001',
|
||||||
|
auth: {basic: 'janedoe'},
|
||||||
|
httpStatus: 400,
|
||||||
|
req: {condition: {material: 'copper', weeks: 10.5, condition_template: '200000000000000000000001'}},
|
||||||
|
res: {status: 'Invalid body format', details: '"weeks" must be less than or equal to 10'}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it('rejects an invalid condition template', done => {
|
||||||
|
TestHelper.request(server, done, {
|
||||||
|
method: 'put',
|
||||||
|
url: '/sample/400000000000000000000001',
|
||||||
|
auth: {basic: 'janedoe'},
|
||||||
|
httpStatus: 400,
|
||||||
|
req: {condition: {material: 'copper', weeks: 3, condition_template: '200000000000h00000000001'}},
|
||||||
|
res: {status: 'Condition template not available'}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it('rejects an unknown condition template', done => {
|
||||||
|
TestHelper.request(server, done, {
|
||||||
|
method: 'put',
|
||||||
|
url: '/sample/400000000000000000000001',
|
||||||
|
auth: {basic: 'janedoe'},
|
||||||
|
httpStatus: 400,
|
||||||
|
req: {condition: {material: 'copper', weeks: 3, condition_template: '000000000000000000000001'}},
|
||||||
|
res: {status: 'Condition template not available'}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it('allows keeping an empty condition empty', done => {
|
||||||
|
TestHelper.request(server, done, {
|
||||||
|
method: 'put',
|
||||||
|
url: '/sample/400000000000000000000006',
|
||||||
|
auth: {basic: 'janedoe'},
|
||||||
|
httpStatus: 200,
|
||||||
|
req: {condition: {}},
|
||||||
|
res: {_id: '400000000000000000000006', number: 'Rng36', type: 'granulate', color: 'black', batch: '', condition: {}, material_id: '100000000000000000000004', note_id: null, user_id: '000000000000000000000002'}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it('rejects an changing back to an empty condition', done => {
|
||||||
|
TestHelper.request(server, done, {
|
||||||
|
method: 'put',
|
||||||
|
url: '/sample/400000000000000000000001',
|
||||||
|
auth: {basic: 'janedoe'},
|
||||||
|
httpStatus: 400,
|
||||||
|
req: {condition: {}},
|
||||||
|
res: {status: 'Condition template not available'}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
it('rejects an API key', done => {
|
it('rejects an API key', done => {
|
||||||
@ -409,7 +595,7 @@ describe('/sample', () => {
|
|||||||
url: '/sample/400000000000000000000001',
|
url: '/sample/400000000000000000000001',
|
||||||
auth: {key: 'janedoe'},
|
auth: {key: 'janedoe'},
|
||||||
httpStatus: 401,
|
httpStatus: 401,
|
||||||
req: {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: [{sample_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 => {
|
||||||
@ -428,7 +614,7 @@ describe('/sample', () => {
|
|||||||
auth: {basic: 'admin'},
|
auth: {basic: 'admin'},
|
||||||
httpStatus: 200,
|
httpStatus: 200,
|
||||||
req: {},
|
req: {},
|
||||||
res: {_id: '400000000000000000000001', number: '1', type: 'granulate', color: 'black', batch: '', material_id: '100000000000000000000004', note_id: null, user_id: '000000000000000000000002'}
|
res: {_id: '400000000000000000000001', number: '1', type: 'granulate', color: 'black', batch: '', condition: {condition_template: '200000000000000000000001', material: 'copper', weeks: 3}, material_id: '100000000000000000000004', note_id: null, user_id: '000000000000000000000002'}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
it('rejects requests from a read user', done => {
|
it('rejects requests from a read user', done => {
|
||||||
@ -437,7 +623,7 @@ describe('/sample', () => {
|
|||||||
url: '/sample/400000000000000000000001',
|
url: '/sample/400000000000000000000001',
|
||||||
auth: {basic: 'user'},
|
auth: {basic: 'user'},
|
||||||
httpStatus: 403,
|
httpStatus: 403,
|
||||||
req: {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: [{sample_id: '400000000000000000000003', relation: 'part to this sample'}]}},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
it('returns 404 for an unknown sample', done => {
|
it('returns 404 for an unknown sample', done => {
|
||||||
@ -446,7 +632,7 @@ describe('/sample', () => {
|
|||||||
url: '/sample/000000000000000000000001',
|
url: '/sample/000000000000000000000001',
|
||||||
auth: {basic: 'janedoe'},
|
auth: {basic: 'janedoe'},
|
||||||
httpStatus: 404,
|
httpStatus: 404,
|
||||||
req: {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: [{sample_id: '400000000000000000000003', relation: 'part to this sample'}]}}
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
it('rejects unauthorized requests', done => {
|
it('rejects unauthorized requests', done => {
|
||||||
@ -454,7 +640,7 @@ describe('/sample', () => {
|
|||||||
method: 'put',
|
method: 'put',
|
||||||
url: '/sample/400000000000000000000001',
|
url: '/sample/400000000000000000000001',
|
||||||
httpStatus: 401,
|
httpStatus: 401,
|
||||||
req: {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: [{sample_id: '400000000000000000000003', relation: 'part to this sample'}]}},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -471,15 +657,18 @@ describe('/sample', () => {
|
|||||||
should(res.body).be.eql({status: 'OK'});
|
should(res.body).be.eql({status: 'OK'});
|
||||||
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', 'condition', 'material_id', 'note_id', 'user_id', 'status', '__v');
|
||||||
should(data).have.property('_id');
|
should(data).have.property('_id');
|
||||||
should(data).have.property('number', '1');
|
should(data).have.property('number', '1');
|
||||||
should(data).have.property('color', 'black');
|
should(data).have.property('color', 'black');
|
||||||
should(data).have.property('type', 'granulate');
|
should(data).have.property('type', 'granulate');
|
||||||
should(data).have.property('batch', '');
|
should(data).have.property('batch', '');
|
||||||
|
should(data.condition).have.property('material', 'copper');
|
||||||
|
should(data.condition).have.property('weeks', 3);
|
||||||
|
should(data.condition.condition_template.toString()).be.eql('200000000000000000000001');
|
||||||
should(data.material_id.toString()).be.eql('100000000000000000000004');
|
should(data.material_id.toString()).be.eql('100000000000000000000004');
|
||||||
should(data.user_id.toString()).be.eql('000000000000000000000002');
|
should(data.user_id.toString()).be.eql('000000000000000000000002');
|
||||||
should(data).have.property('status', -1);
|
should(data).have.property('status',globals.status.deleted);
|
||||||
should(data).have.property('note_id', null);
|
should(data).have.property('note_id', null);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
@ -536,7 +725,7 @@ describe('/sample', () => {
|
|||||||
NoteModel.findById('500000000000000000000003').lean().exec((err, data: any) => {
|
NoteModel.findById('500000000000000000000003').lean().exec((err, data: any) => {
|
||||||
if (err) return done(err);
|
if (err) return done(err);
|
||||||
should(data).have.property('sample_references').with.lengthOf(1);
|
should(data).have.property('sample_references').with.lengthOf(1);
|
||||||
should(data.sample_references[0].id.toString()).be.eql('400000000000000000000003');
|
should(data.sample_references[0].sample_id.toString()).be.eql('400000000000000000000003');
|
||||||
should(data.sample_references[0]).have.property('relation', 'part to sample');
|
should(data.sample_references[0]).have.property('relation', 'part to sample');
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
@ -555,7 +744,7 @@ describe('/sample', () => {
|
|||||||
should(res.body).be.eql({status: 'OK'});
|
should(res.body).be.eql({status: 'OK'});
|
||||||
SampleModel.findById('400000000000000000000001').lean().exec((err, data) => {
|
SampleModel.findById('400000000000000000000001').lean().exec((err, data) => {
|
||||||
if (err) return done(err);
|
if (err) return done(err);
|
||||||
should(data).have.property('status', -1);
|
should(data).have.property('status',globals.status.deleted);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -617,15 +806,16 @@ describe('/sample', () => {
|
|||||||
url: '/sample/new',
|
url: '/sample/new',
|
||||||
auth: {basic: 'janedoe'},
|
auth: {basic: 'janedoe'},
|
||||||
httpStatus: 200,
|
httpStatus: 200,
|
||||||
req: {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', condition: {material: 'copper', weeks: 3, condition_template: '200000000000000000000001'}, material_id: '100000000000000000000001', notes: {comment: 'Testcomment', sample_references: [{sample_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', 'condition', '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', 'Rng34');
|
should(res.body).have.property('number', 'Rng37');
|
||||||
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');
|
||||||
|
should(res.body).have.property('condition', {material: 'copper', weeks: 3, condition_template: '200000000000000000000001'});
|
||||||
should(res.body).have.property('material_id', '100000000000000000000001');
|
should(res.body).have.property('material_id', '100000000000000000000001');
|
||||||
should(res.body).have.property('note_id').be.type('string');
|
should(res.body).have.property('note_id').be.type('string');
|
||||||
should(res.body).have.property('user_id', '000000000000000000000002');
|
should(res.body).have.property('user_id', '000000000000000000000002');
|
||||||
@ -638,21 +828,22 @@ describe('/sample', () => {
|
|||||||
url: '/sample/new',
|
url: '/sample/new',
|
||||||
auth: {basic: 'janedoe'},
|
auth: {basic: 'janedoe'},
|
||||||
httpStatus: 200,
|
httpStatus: 200,
|
||||||
req: {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', condition: {material: 'copper', weeks: 3, condition_template: '200000000000000000000001'}, material_id: '100000000000000000000001', notes: {comment: 'Testcomment', sample_references: [{sample_id: '400000000000000000000003', relation: 'part to this sample'}]}}
|
||||||
}).end(err => {
|
}).end(err => {
|
||||||
if (err) return done (err);
|
if (err) return done (err);
|
||||||
SampleModel.find({number: 'Rng34'}).lean().exec((err, data: any) => {
|
SampleModel.find({number: 'Rng37'}).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', 'condition', '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', 'Rng34');
|
should(data[0]).have.property('number', 'Rng37');
|
||||||
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');
|
||||||
|
should(data[0]).have.property('condition', {material: 'copper', weeks: 3, condition_template: '200000000000000000000001'});
|
||||||
should(data[0].material_id.toString()).be.eql('100000000000000000000001');
|
should(data[0].material_id.toString()).be.eql('100000000000000000000001');
|
||||||
should(data[0].user_id.toString()).be.eql('000000000000000000000002');
|
should(data[0].user_id.toString()).be.eql('000000000000000000000002');
|
||||||
should(data[0]).have.property('status', 0);
|
should(data[0]).have.property('status',globals.status.new);
|
||||||
should(data[0]).have.property('note_id');
|
should(data[0]).have.property('note_id');
|
||||||
NoteModel.findById(data[0].note_id).lean().exec((err, data: any) => {
|
NoteModel.findById(data[0].note_id).lean().exec((err, data: any) => {
|
||||||
if (err) return done (err);
|
if (err) return done (err);
|
||||||
@ -660,7 +851,7 @@ describe('/sample', () => {
|
|||||||
should(data).have.property('comment', 'Testcomment');
|
should(data).have.property('comment', 'Testcomment');
|
||||||
should(data).have.property('sample_references');
|
should(data).have.property('sample_references');
|
||||||
should(data.sample_references).have.lengthOf(1);
|
should(data.sample_references).have.lengthOf(1);
|
||||||
should(data.sample_references[0].id.toString()).be.eql('400000000000000000000003');
|
should(data.sample_references[0].sample_id.toString()).be.eql('400000000000000000000003');
|
||||||
should(data.sample_references[0]).have.property('relation', 'part to this sample');
|
should(data.sample_references[0]).have.property('relation', 'part to this sample');
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
@ -710,10 +901,10 @@ describe('/sample', () => {
|
|||||||
url: '/sample/new',
|
url: '/sample/new',
|
||||||
auth: {basic: 'johnnydoe'},
|
auth: {basic: 'johnnydoe'},
|
||||||
httpStatus: 200,
|
httpStatus: 200,
|
||||||
req: {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: [{sample_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', 'condition', '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', 'Fe1');
|
should(res.body).have.property('number', 'Fe1');
|
||||||
should(res.body).have.property('color', 'black');
|
should(res.body).have.property('color', 'black');
|
||||||
@ -725,13 +916,35 @@ describe('/sample', () => {
|
|||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
it('accepts a sample without condition', done => {
|
||||||
|
TestHelper.request(server, done, {
|
||||||
|
method: 'post',
|
||||||
|
url: '/sample/new',
|
||||||
|
auth: {basic: 'janedoe'},
|
||||||
|
httpStatus: 200,
|
||||||
|
req: {color: 'black', type: 'granulate', batch: '1560237365', material_id: '100000000000000000000001', notes: {comment: 'Testcomment', sample_references: [{sample_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', 'condition', 'material_id', 'note_id', 'user_id');
|
||||||
|
should(res.body).have.property('_id').be.type('string');
|
||||||
|
should(res.body).have.property('number', 'Rng37');
|
||||||
|
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('condition', {});
|
||||||
|
should(res.body).have.property('material_id', '100000000000000000000001');
|
||||||
|
should(res.body).have.property('note_id').be.type('string');
|
||||||
|
should(res.body).have.property('user_id', '000000000000000000000002');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
it('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: {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: [{sample_id: '400000000000000000000003', relation: 'part to this sample'}]}},
|
||||||
res: {status: 'Color not available for material'}
|
res: {status: 'Color not available for material'}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -741,7 +954,7 @@ describe('/sample', () => {
|
|||||||
url: '/sample/new',
|
url: '/sample/new',
|
||||||
auth: {basic: 'janedoe'},
|
auth: {basic: 'janedoe'},
|
||||||
httpStatus: 400,
|
httpStatus: 400,
|
||||||
req: {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: [{sample_id: '400000000000000000000003', relation: 'part to this sample'}]}},
|
||||||
res: {status: 'Material not available'}
|
res: {status: 'Material not available'}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -751,7 +964,7 @@ describe('/sample', () => {
|
|||||||
url: '/sample/new',
|
url: '/sample/new',
|
||||||
auth: {basic: 'janedoe'},
|
auth: {basic: 'janedoe'},
|
||||||
httpStatus: 400,
|
httpStatus: 400,
|
||||||
req: {number: 'Rng34', 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: [{sample_id: '400000000000000000000003', relation: 'part to this sample'}]}},
|
||||||
res: {status: 'Invalid body format', details: '"number" is not allowed'}
|
res: {status: 'Invalid body format', details: '"number" is not allowed'}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -761,17 +974,97 @@ describe('/sample', () => {
|
|||||||
url: '/sample/new',
|
url: '/sample/new',
|
||||||
auth: {basic: 'janedoe'},
|
auth: {basic: 'janedoe'},
|
||||||
httpStatus: 400,
|
httpStatus: 400,
|
||||||
req: {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: [{sample_id: '000000000000000000000003', relation: 'part to this sample'}]}},
|
||||||
res: {status: 'Sample reference not available'}
|
res: {status: 'Sample reference not available'}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
it('rejects an invalid condition_template id', done => {
|
||||||
|
TestHelper.request(server, done, {
|
||||||
|
method: 'post',
|
||||||
|
url: '/sample/new',
|
||||||
|
auth: {basic: 'janedoe'},
|
||||||
|
httpStatus: 400,
|
||||||
|
req: {color: 'black', type: 'granulate', batch: '1560237365', condition: {material: 'copper', weeks: 3, condition_template: '20000h000000000000000001'}, material_id: '100000000000000000000001', notes: {comment: 'Testcomment', sample_references: [{sample_id: '400000000000000000000003', relation: 'part to this sample'}]}},
|
||||||
|
res: {status: 'Condition template not available'}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it('rejects a not existing condition_template id', done => {
|
||||||
|
TestHelper.request(server, done, {
|
||||||
|
method: 'post',
|
||||||
|
url: '/sample/new',
|
||||||
|
auth: {basic: 'janedoe'},
|
||||||
|
httpStatus: 400,
|
||||||
|
req: {color: 'black', type: 'granulate', batch: '1560237365', condition: {material: 'copper', weeks: 3, condition_template: '000000000000000000000001'}, material_id: '100000000000000000000001', notes: {comment: 'Testcomment', sample_references: [{sample_id: '400000000000000000000003', relation: 'part to this sample'}]}},
|
||||||
|
res: {status: 'Condition template not available'}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it('rejects not specified condition parameters', done => {
|
||||||
|
TestHelper.request(server, done, {
|
||||||
|
method: 'post',
|
||||||
|
url: '/sample/new',
|
||||||
|
auth: {basic: 'janedoe'},
|
||||||
|
httpStatus: 400,
|
||||||
|
req: {color: 'black', type: 'granulate', batch: '1560237365', condition: {material: 'copper', weeks: 3, xxx: 23, condition_template: '20000000000000000000001'}, material_id: '100000000000000000000001', notes: {comment: 'Testcomment', sample_references: [{sample_id: '400000000000000000000003', relation: 'part to this sample'}]}},
|
||||||
|
res: {status: 'Condition template not available'}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it('rejects missing condition parameters', done => {
|
||||||
|
TestHelper.request(server, done, {
|
||||||
|
method: 'post',
|
||||||
|
url: '/sample/new',
|
||||||
|
auth: {basic: 'janedoe'},
|
||||||
|
httpStatus: 400,
|
||||||
|
req: {color: 'black', type: 'granulate', batch: '1560237365', condition: {material: 'copper', condition_template: '20000000000000000000001'}, material_id: '100000000000000000000001', notes: {comment: 'Testcomment', sample_references: [{sample_id: '400000000000000000000003', relation: 'part to this sample'}]}},
|
||||||
|
res: {status: 'Condition template not available'}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it('rejects condition parameters not in the value range', done => {
|
||||||
|
TestHelper.request(server, done, {
|
||||||
|
method: 'post',
|
||||||
|
url: '/sample/new',
|
||||||
|
auth: {basic: 'janedoe'},
|
||||||
|
httpStatus: 400,
|
||||||
|
req: {color: 'black', type: 'granulate', batch: '1560237365', condition: {material: 'xxx', weeks: 3, condition_template: '20000000000000000000001'}, material_id: '100000000000000000000001', notes: {comment: 'Testcomment', sample_references: [{sample_id: '400000000000000000000003', relation: 'part to this sample'}]}},
|
||||||
|
res: {status: 'Condition template not available'}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it('rejects a condition parameter below minimum range', done => {
|
||||||
|
TestHelper.request(server, done, {
|
||||||
|
method: 'post',
|
||||||
|
url: '/sample/new',
|
||||||
|
auth: {basic: 'janedoe'},
|
||||||
|
httpStatus: 400,
|
||||||
|
req: {color: 'black', type: 'granulate', batch: '1560237365', condition: {material: 'copper', weeks: 0, condition_template: '20000000000000000000001'}, material_id: '100000000000000000000001', notes: {comment: 'Testcomment', sample_references: [{sample_id: '400000000000000000000003', relation: 'part to this sample'}]}},
|
||||||
|
res: {status: 'Condition template not available'}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it('rejects a condition parameter above maximum range', done => {
|
||||||
|
TestHelper.request(server, done, {
|
||||||
|
method: 'post',
|
||||||
|
url: '/sample/new',
|
||||||
|
auth: {basic: 'janedoe'},
|
||||||
|
httpStatus: 400,
|
||||||
|
req: {color: 'black', type: 'granulate', batch: '1560237365', condition: {material: 'copper', weeks: 11, condition_template: '20000000000000000000001'}, material_id: '100000000000000000000001', notes: {comment: 'Testcomment', sample_references: [{sample_id: '400000000000000000000003', relation: 'part to this sample'}]}},
|
||||||
|
res: {status: 'Condition template not available'}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it('rejects a condition without condition template', done => {
|
||||||
|
TestHelper.request(server, done, {
|
||||||
|
method: 'post',
|
||||||
|
url: '/sample/new',
|
||||||
|
auth: {basic: 'janedoe'},
|
||||||
|
httpStatus: 400,
|
||||||
|
req: {color: 'black', type: 'granulate', batch: '1560237365', condition: {material: 'copper', weeks: 3}, material_id: '100000000000000000000001', notes: {comment: 'Testcomment', sample_references: [{sample_id: '400000000000000000000003', relation: 'part to this sample'}]}},
|
||||||
|
res: {status: 'Condition template not available'}
|
||||||
|
});
|
||||||
|
});
|
||||||
it('rejects a missing color', done => {
|
it('rejects a missing color', 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: {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: [{sample_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'}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -781,7 +1074,7 @@ describe('/sample', () => {
|
|||||||
url: '/sample/new',
|
url: '/sample/new',
|
||||||
auth: {basic: 'janedoe'},
|
auth: {basic: 'janedoe'},
|
||||||
httpStatus: 400,
|
httpStatus: 400,
|
||||||
req: {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: [{sample_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'}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -791,7 +1084,7 @@ describe('/sample', () => {
|
|||||||
url: '/sample/new',
|
url: '/sample/new',
|
||||||
auth: {basic: 'janedoe'},
|
auth: {basic: 'janedoe'},
|
||||||
httpStatus: 400,
|
httpStatus: 400,
|
||||||
req: {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: [{sample_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'}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -801,7 +1094,7 @@ describe('/sample', () => {
|
|||||||
url: '/sample/new',
|
url: '/sample/new',
|
||||||
auth: {basic: 'janedoe'},
|
auth: {basic: 'janedoe'},
|
||||||
httpStatus: 400,
|
httpStatus: 400,
|
||||||
req: {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: [{sample_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'}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -811,7 +1104,7 @@ describe('/sample', () => {
|
|||||||
url: '/sample/new',
|
url: '/sample/new',
|
||||||
auth: {basic: 'janedoe'},
|
auth: {basic: 'janedoe'},
|
||||||
httpStatus: 400,
|
httpStatus: 400,
|
||||||
req: {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: [{sample_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}/'}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -821,7 +1114,7 @@ describe('/sample', () => {
|
|||||||
url: '/sample/new',
|
url: '/sample/new',
|
||||||
auth: {key: 'janedoe'},
|
auth: {key: 'janedoe'},
|
||||||
httpStatus: 401,
|
httpStatus: 401,
|
||||||
req: {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: [{sample_id: '400000000000000000000003', relation: 'part to this sample'}]}}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
it('rejects requests from a read user', done => {
|
it('rejects requests from a read user', done => {
|
||||||
@ -830,7 +1123,7 @@ describe('/sample', () => {
|
|||||||
url: '/sample/new',
|
url: '/sample/new',
|
||||||
auth: {basic: 'user'},
|
auth: {basic: 'user'},
|
||||||
httpStatus: 403,
|
httpStatus: 403,
|
||||||
req: {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: [{sample_id: '400000000000000000000003', relation: 'part to this sample'}]}}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
it('rejects unauthorized requests', done => {
|
it('rejects unauthorized requests', done => {
|
||||||
@ -838,7 +1131,7 @@ describe('/sample', () => {
|
|||||||
method: 'post',
|
method: 'post',
|
||||||
url: '/sample/new',
|
url: '/sample/new',
|
||||||
httpStatus: 401,
|
httpStatus: 401,
|
||||||
req: {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: [{sample_id: '400000000000000000000003', relation: 'part to this sample'}]}}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -5,10 +5,15 @@ import SampleValidate from './validate/sample';
|
|||||||
import NoteFieldValidate from './validate/note_field';
|
import NoteFieldValidate from './validate/note_field';
|
||||||
import res400 from './validate/res400';
|
import res400 from './validate/res400';
|
||||||
import SampleModel from '../models/sample'
|
import SampleModel from '../models/sample'
|
||||||
|
import MeasurementModel from '../models/measurement';
|
||||||
import MaterialModel from '../models/material';
|
import MaterialModel from '../models/material';
|
||||||
import NoteModel from '../models/note';
|
import NoteModel from '../models/note';
|
||||||
import NoteFieldModel from '../models/note_field';
|
import NoteFieldModel from '../models/note_field';
|
||||||
import IdValidate from './validate/id';
|
import IdValidate from './validate/id';
|
||||||
|
import mongoose from "mongoose";
|
||||||
|
import ConditionTemplateModel from '../models/condition_template';
|
||||||
|
import ParametersValidate from './validate/parameters';
|
||||||
|
import globals from '../globals';
|
||||||
|
|
||||||
|
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
@ -16,7 +21,7 @@ const router = express.Router();
|
|||||||
router.get('/samples', (req, res, next) => {
|
router.get('/samples', (req, res, next) => {
|
||||||
if (!req.auth(res, ['read', 'write', 'maintain', 'dev', 'admin'], 'all')) return;
|
if (!req.auth(res, ['read', 'write', 'maintain', 'dev', 'admin'], 'all')) return;
|
||||||
|
|
||||||
SampleModel.find({status: 10}).lean().exec((err, data) => {
|
SampleModel.find({status: globals.status.validated}).lean().exec((err, data) => {
|
||||||
if (err) return next(err);
|
if (err) return next(err);
|
||||||
res.json(_.compact(data.map(e => SampleValidate.output(e)))); // validate all and filter null values from validation errors
|
res.json(_.compact(data.map(e => SampleValidate.output(e)))); // validate all and filter null values from validation errors
|
||||||
})
|
})
|
||||||
@ -25,17 +30,32 @@ router.get('/samples', (req, res, next) => {
|
|||||||
router.get('/samples/:group(new|deleted)', (req, res, next) => {
|
router.get('/samples/:group(new|deleted)', (req, res, next) => {
|
||||||
if (!req.auth(res, ['maintain', 'admin'], 'basic')) return;
|
if (!req.auth(res, ['maintain', 'admin'], 'basic')) return;
|
||||||
|
|
||||||
let status;
|
SampleModel.find({status: globals.status[req.params.group]}).lean().exec((err, data) => {
|
||||||
switch (req.params.group) {
|
|
||||||
case 'new': status = 0;
|
|
||||||
break;
|
|
||||||
case 'deleted': status = -1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
SampleModel.find({status: status}).lean().exec((err, data) => {
|
|
||||||
if (err) return next(err);
|
if (err) return next(err);
|
||||||
res.json(_.compact(data.map(e => SampleValidate.output(e)))); // validate all and filter null values from validation errors
|
res.json(_.compact(data.map(e => SampleValidate.output(e)))); // validate all and filter null values from validation errors
|
||||||
})
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
router.get('/sample/' + IdValidate.parameter(), (req, res, next) => {
|
||||||
|
if (!req.auth(res, ['read', 'write', 'maintain', 'dev', 'admin'], 'all')) return;
|
||||||
|
|
||||||
|
SampleModel.findById(req.params.id).populate('material_id').populate('user_id', 'name').populate('note_id').lean().exec((err, sampleData: any) => {
|
||||||
|
if (err) return next(err);
|
||||||
|
|
||||||
|
if (sampleData) {
|
||||||
|
if (sampleData.status ===globals.status.deleted && !req.auth(res, ['maintain', 'admin'], 'all')) return; // deleted samples only available for maintain/admin
|
||||||
|
sampleData.material = sampleData.material_id; // map data to right keys
|
||||||
|
sampleData.user = sampleData.user_id.name;
|
||||||
|
sampleData.notes = sampleData.note_id ? sampleData.note_id : {};
|
||||||
|
MeasurementModel.find({sample_id: mongoose.Types.ObjectId(req.params.id)}).lean().exec((err, data) => {
|
||||||
|
sampleData.measurements = data;
|
||||||
|
res.json(SampleValidate.output(sampleData, 'details'));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
res.status(404).json({status: 'Not found'});
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
router.put('/sample/' + IdValidate.parameter(), (req, res, next) => {
|
router.put('/sample/' + IdValidate.parameter(), (req, res, next) => {
|
||||||
@ -60,6 +80,10 @@ router.put('/sample/' + IdValidate.parameter(), (req, res, next) => {
|
|||||||
if (!await materialCheck(sample, res, next, sampleData.material_id)) return;
|
if (!await materialCheck(sample, res, next, sampleData.material_id)) return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (sample.hasOwnProperty('condition') && !(_.isEmpty(sample.condition) && _.isEmpty(sampleData.condition))) { // do not execute check if condition is and was empty
|
||||||
|
if (!await conditionCheck(sample.condition, 'change', res, next)) return;
|
||||||
|
}
|
||||||
|
|
||||||
if (sample.hasOwnProperty('notes')) {
|
if (sample.hasOwnProperty('notes')) {
|
||||||
let newNotes = true;
|
let newNotes = true;
|
||||||
if (sampleData.note_id !== null) { // old notes data exists
|
if (sampleData.note_id !== null) { // old notes data exists
|
||||||
@ -89,10 +113,10 @@ router.put('/sample/' + IdValidate.parameter(), (req, res, next) => {
|
|||||||
|
|
||||||
// check for changes
|
// check for changes
|
||||||
if (!_.isEqual(_.pick(IdValidate.stringify(sampleData), _.keys(sample)), _.omit(sample, ['notes']))) {
|
if (!_.isEqual(_.pick(IdValidate.stringify(sampleData), _.keys(sample)), _.omit(sample, ['notes']))) {
|
||||||
sample.status = 0;
|
sample.status = globals.status.new;
|
||||||
}
|
}
|
||||||
|
|
||||||
await SampleModel.findByIdAndUpdate(req.params.id, sample, {new: true}).lean().exec((err, data) => {
|
await SampleModel.findByIdAndUpdate(req.params.id, sample, {new: true}).lean().exec((err, data: any) => {
|
||||||
if (err) return next(err);
|
if (err) return next(err);
|
||||||
res.json(SampleValidate.output(data));
|
res.json(SampleValidate.output(data));
|
||||||
});
|
});
|
||||||
@ -112,7 +136,7 @@ router.delete('/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;
|
||||||
|
|
||||||
await SampleModel.findByIdAndUpdate(req.params.id, {status: -1}).lean().exec(err => { // set sample status
|
await SampleModel.findByIdAndUpdate(req.params.id, {status:globals.status.deleted}).lean().exec(err => { // set sample status
|
||||||
if (err) return next(err);
|
if (err) return next(err);
|
||||||
if (sampleData.note_id !== null) { // handle notes
|
if (sampleData.note_id !== null) { // handle notes
|
||||||
NoteModel.findById(sampleData.note_id).lean().exec((err, data: any) => { // find notes to update note_fields
|
NoteModel.findById(sampleData.note_id).lean().exec((err, data: any) => { // find notes to update note_fields
|
||||||
@ -133,6 +157,10 @@ router.delete('/sample/' + IdValidate.parameter(), (req, res, next) => {
|
|||||||
router.post('/sample/new', async (req, res, next) => {
|
router.post('/sample/new', async (req, res, next) => {
|
||||||
if (!req.auth(res, ['write', 'maintain', 'dev', 'admin'], 'basic')) return;
|
if (!req.auth(res, ['write', 'maintain', 'dev', 'admin'], 'basic')) return;
|
||||||
|
|
||||||
|
if (!req.body.hasOwnProperty('condition')) { // add empty condition if not specified
|
||||||
|
req.body.condition = {};
|
||||||
|
}
|
||||||
|
|
||||||
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);
|
||||||
|
|
||||||
@ -143,7 +171,11 @@ router.post('/sample/new', async (req, res, next) => {
|
|||||||
customFieldsChange(Object.keys(sample.notes.custom_fields), 1);
|
customFieldsChange(Object.keys(sample.notes.custom_fields), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
sample.status = 0; // set status to new
|
if (!_.isEmpty(sample.condition)) { // do not execute check if condition is empty
|
||||||
|
if (!await conditionCheck(sample.condition, 'change', res, next)) return;
|
||||||
|
}
|
||||||
|
|
||||||
|
sample.status = globals.status.new; // set status to new
|
||||||
sample.number = await numberGenerate(sample, req, res, next);
|
sample.number = await numberGenerate(sample, req, res, next);
|
||||||
if (!sample.number) return;
|
if (!sample.number) return;
|
||||||
|
|
||||||
@ -152,6 +184,7 @@ router.post('/sample/new', async (req, res, next) => {
|
|||||||
delete sample.notes;
|
delete sample.notes;
|
||||||
sample.note_id = data._id;
|
sample.note_id = data._id;
|
||||||
sample.user_id = req.authDetails.id;
|
sample.user_id = req.authDetails.id;
|
||||||
|
|
||||||
new SampleModel(sample).save((err, data) => {
|
new SampleModel(sample).save((err, data) => {
|
||||||
if (err) return next(err);
|
if (err) return next(err);
|
||||||
res.json(SampleValidate.output(data.toObject()));
|
res.json(SampleValidate.output(data.toObject()));
|
||||||
@ -172,14 +205,15 @@ router.get('/sample/notes/fields', (req, res, next) => {
|
|||||||
module.exports = router;
|
module.exports = router;
|
||||||
|
|
||||||
|
|
||||||
async function numberGenerate (sample, req, res, next) { // generate number, returns false on error
|
async function numberGenerate (sample, req, res, next) { // generate number in format Location32, returns false on error
|
||||||
const sampleData = await SampleModel
|
const sampleData = await SampleModel
|
||||||
.find({number: new RegExp('^' + req.authDetails.location + '[0-9]+$', 'm')})
|
.findOne({number: new RegExp('^' + req.authDetails.location + '[0-9]+$', 'm')})
|
||||||
|
.sort({number: -1})
|
||||||
.lean()
|
.lean()
|
||||||
.exec()
|
.exec()
|
||||||
.catch(err => next(err));
|
.catch(err => next(err));
|
||||||
if (sampleData instanceof Error) return false;
|
if (sampleData instanceof Error) return false;
|
||||||
return req.authDetails.location + (sampleData.length > 0 ? Number(sampleData[0].number.replace(/[^0-9]+/g, '')) + 1 : 1);
|
return req.authDetails.location + (sampleData ? Number(sampleData.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
|
||||||
@ -196,13 +230,31 @@ async function materialCheck (sample, res, next, id = sample.material_id) { //
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function conditionCheck (condition, param, res, next) { // validate treatment template, returns false if invalid, otherwise template data
|
||||||
|
if (!condition.condition_template || !IdValidate.valid(condition.condition_template)) { // template id not found
|
||||||
|
res.status(400).json({status: 'Condition template not available'});
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const conditionData = await ConditionTemplateModel.findById(condition.condition_template).lean().exec().catch(err => next(err)) as any;
|
||||||
|
if (conditionData instanceof Error) return false;
|
||||||
|
if (!conditionData) { // template not found
|
||||||
|
res.status(400).json({status: 'Condition template not available'});
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// validate parameters
|
||||||
|
const {error, value: ignore} = ParametersValidate.input(_.omit(condition, 'condition_template'), conditionData.parameters, param);
|
||||||
|
if (error) {res400(error, res); return false;}
|
||||||
|
return conditionData;
|
||||||
|
}
|
||||||
|
|
||||||
function sampleRefCheck (sample, res, next) { // validate sample_references, resolves false for invalid reference
|
function sampleRefCheck (sample, res, next) { // validate sample_references, resolves false for invalid reference
|
||||||
return new Promise(resolve => {
|
return new Promise(resolve => {
|
||||||
if (sample.notes.sample_references.length > 0) { // there are sample_references
|
if (sample.notes.sample_references.length > 0) { // there are sample_references
|
||||||
let referencesCount = sample.notes.sample_references.length; // count to keep track of running async operations
|
let referencesCount = sample.notes.sample_references.length; // count to keep track of running async operations
|
||||||
|
|
||||||
sample.notes.sample_references.forEach(reference => {
|
sample.notes.sample_references.forEach(reference => {
|
||||||
SampleModel.findById(reference.id).lean().exec((err, data) => {
|
SampleModel.findById(reference.sample_id).lean().exec((err, data) => {
|
||||||
if (err) {next(err); resolve(false)}
|
if (err) {next(err); resolve(false)}
|
||||||
if (!data) {
|
if (!data) {
|
||||||
res.status(400).json({status: 'Sample reference not available'});
|
res.status(400).json({status: 'Sample reference not available'});
|
||||||
@ -230,7 +282,7 @@ function customFieldsChange (fields, amount) { // update custom_fields and resp
|
|||||||
if (err) return console.error(err);
|
if (err) return console.error(err);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
else if (data.qty <= 0) {
|
else if (data.qty <= 0) { // delete document if field is not used anymore
|
||||||
NoteFieldModel.findOneAndDelete({name: field}).lean().exec(err => {
|
NoteFieldModel.findOneAndDelete({name: field}).lean().exec(err => {
|
||||||
if (err) return console.error(err);
|
if (err) return console.error(err);
|
||||||
});
|
});
|
||||||
|
@ -1,36 +1,38 @@
|
|||||||
import should from 'should/as-function';
|
import should from 'should/as-function';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import TemplateTreatmentModel from '../models/treatment_template';
|
import TemplateConditionModel from '../models/condition_template';
|
||||||
import TemplateMeasurementModel from '../models/measurement_template';
|
import TemplateMeasurementModel from '../models/measurement_template';
|
||||||
import TestHelper from "../test/helper";
|
import TestHelper from "../test/helper";
|
||||||
|
|
||||||
// TODO: do not allow usage of old templates for new samples
|
// TODO: do not allow usage of old templates for new samples
|
||||||
|
// TODO: remove number_prefix
|
||||||
|
// TODO: template parameters are not allowed to be condition_template
|
||||||
|
|
||||||
describe('/template', () => {
|
describe('/template', () => {
|
||||||
let server;
|
let server;
|
||||||
before(done => TestHelper.before(done));
|
before(done => TestHelper.before(done));
|
||||||
beforeEach(done => server = TestHelper.beforeEach(server, done));
|
beforeEach(done => server = TestHelper.beforeEach(server, done));
|
||||||
afterEach(done => TestHelper.afterEach(server, done));
|
afterEach(done => TestHelper.afterEach(server, done));
|
||||||
|
after(done => TestHelper.after(done));
|
||||||
|
|
||||||
describe('/template/treatment', () => {
|
describe('/template/condition', () => {
|
||||||
describe('GET /template/treatments', () => {
|
describe('GET /template/conditions', () => {
|
||||||
it('returns all treatment templates', done => {
|
it('returns all condition templates', done => {
|
||||||
TestHelper.request(server, done, {
|
TestHelper.request(server, done, {
|
||||||
method: 'get',
|
method: 'get',
|
||||||
url: '/template/treatments',
|
url: '/template/conditions',
|
||||||
auth: {basic: 'janedoe'},
|
auth: {basic: 'janedoe'},
|
||||||
httpStatus: 200
|
httpStatus: 200
|
||||||
}).end((err, res) => {
|
}).end((err, res) => {
|
||||||
if (err) return done(err);
|
if (err) return done(err);
|
||||||
const json = require('../test/db.json');
|
const json = require('../test/db.json');
|
||||||
should(res.body).have.lengthOf(json.collections.treatment_templates.length);
|
should(res.body).have.lengthOf(json.collections.condition_templates.length);
|
||||||
should(res.body).matchEach(treatment => {
|
should(res.body).matchEach(condition => {
|
||||||
should(treatment).have.only.keys('_id', 'name', 'version', 'parameters', 'number_prefix');
|
should(condition).have.only.keys('_id', 'name', 'version', 'parameters');
|
||||||
should(treatment).have.property('_id').be.type('string');
|
should(condition).have.property('_id').be.type('string');
|
||||||
should(treatment).have.property('name').be.type('string');
|
should(condition).have.property('name').be.type('string');
|
||||||
should(treatment).have.property('version').be.type('number');
|
should(condition).have.property('version').be.type('number');
|
||||||
should(treatment).have.property('number_prefix').be.type('string');
|
should(condition.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');
|
||||||
should(number).have.property('range').be.type('object');
|
should(number).have.property('range').be.type('object');
|
||||||
@ -42,7 +44,7 @@ describe('/template', () => {
|
|||||||
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/treatments',
|
url: '/template/conditions',
|
||||||
auth: {key: 'janedoe'},
|
auth: {key: 'janedoe'},
|
||||||
httpStatus: 401
|
httpStatus: 401
|
||||||
});
|
});
|
||||||
@ -50,26 +52,26 @@ 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/treatments',
|
url: '/template/conditions',
|
||||||
httpStatus: 401
|
httpStatus: 401
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('GET /template/treatment/{id}', () => {
|
describe('GET /template/condition/{id}', () => {
|
||||||
it('returns the right treatment template', done => {
|
it('returns the right condition template', done => {
|
||||||
TestHelper.request(server, done, {
|
TestHelper.request(server, done, {
|
||||||
method: 'get',
|
method: 'get',
|
||||||
url: '/template/treatment/200000000000000000000001',
|
url: '/template/condition/200000000000000000000001',
|
||||||
auth: {basic: 'janedoe'},
|
auth: {basic: 'janedoe'},
|
||||||
httpStatus: 200,
|
httpStatus: 200,
|
||||||
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}}]}
|
res: {_id: '200000000000000000000001', name: 'heat treatment', version: 1, 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/200000000000000000000001',
|
url: '/template/condition/200000000000000000000001',
|
||||||
auth: {key: 'janedoe'},
|
auth: {key: 'janedoe'},
|
||||||
httpStatus: 401
|
httpStatus: 401
|
||||||
});
|
});
|
||||||
@ -77,7 +79,7 @@ describe('/template', () => {
|
|||||||
it('rejects an unknown id', done => {
|
it('rejects an unknown id', done => {
|
||||||
TestHelper.request(server, done, {
|
TestHelper.request(server, done, {
|
||||||
method: 'get',
|
method: 'get',
|
||||||
url: '/template/treatment/000000000000000000000001',
|
url: '/template/condition/000000000000000000000001',
|
||||||
auth: {basic: 'janedoe'},
|
auth: {basic: 'janedoe'},
|
||||||
httpStatus: 404
|
httpStatus: 404
|
||||||
});
|
});
|
||||||
@ -85,58 +87,57 @@ 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/200000000000000000000001',
|
url: '/template/condition/200000000000000000000001',
|
||||||
httpStatus: 401
|
httpStatus: 401
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('PUT /template/treatment/{name}', () => {
|
describe('PUT /template/condition/{name}', () => {
|
||||||
it('returns the right treatment template', done => {
|
it('returns the right condition template', done => {
|
||||||
TestHelper.request(server, done, {
|
TestHelper.request(server, done, {
|
||||||
method: 'put',
|
method: 'put',
|
||||||
url: '/template/treatment/200000000000000000000001',
|
url: '/template/condition/200000000000000000000001',
|
||||||
auth: {basic: 'admin'},
|
auth: {basic: 'admin'},
|
||||||
httpStatus: 200,
|
httpStatus: 200,
|
||||||
req: {},
|
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}}]}
|
res: {_id: '200000000000000000000001', name: 'heat treatment', version: 1, 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/200000000000000000000001',
|
url: '/template/condition/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', version: 1, number_prefix: 'A', parameters: [{name: 'material', range: {values: ['copper', 'hot air']}}, {name: 'weeks', range: {min: 1, max: 10}}]}
|
res: {_id: '200000000000000000000001', name: 'heat treatment', version: 1, parameters: [{name: 'material', range: {values: ['copper', 'hot air']}}, {name: 'weeks', range: {min: 1, max: 10}}]}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
it('keeps only one unchanged property', done => {
|
it('keeps only one unchanged property', done => {
|
||||||
TestHelper.request(server, done, {
|
TestHelper.request(server, done, {
|
||||||
method: 'put',
|
method: 'put',
|
||||||
url: '/template/treatment/200000000000000000000001',
|
url: '/template/condition/200000000000000000000001',
|
||||||
auth: {basic: 'admin'},
|
auth: {basic: 'admin'},
|
||||||
httpStatus: 200,
|
httpStatus: 200,
|
||||||
req: {name: 'heat treatment'},
|
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}}]}
|
res: {_id: '200000000000000000000001', name: 'heat treatment', version: 1, 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/200000000000000000000001',
|
url: '/template/condition/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);
|
||||||
TemplateTreatmentModel.findById(res.body._id).lean().exec((err, data:any) => {
|
TemplateConditionModel.findById(res.body._id).lean().exec((err, data:any) => {
|
||||||
if (err) return done(err);
|
if (err) return done(err);
|
||||||
should(data).have.only.keys('_id', 'name', 'version', 'number_prefix', 'parameters', '__v');
|
should(data).have.only.keys('_id', 'name', 'version', 'parameters', '__v');
|
||||||
should(data).have.property('name', 'heat aging');
|
should(data).have.property('name', 'heat aging');
|
||||||
should(data).have.property('version', 2);
|
should(data).have.property('version', 2);
|
||||||
should(data).have.property('number_prefix', 'A');
|
|
||||||
should(data).have.property('parameters').have.lengthOf(1);
|
should(data).have.property('parameters').have.lengthOf(1);
|
||||||
should(data.parameters[0]).have.property('name', 'time');
|
should(data.parameters[0]).have.property('name', 'time');
|
||||||
should(data.parameters[0]).have.property('range');
|
should(data.parameters[0]).have.property('range');
|
||||||
@ -148,18 +149,17 @@ describe('/template', () => {
|
|||||||
it('allows changing only one property', done => {
|
it('allows changing only one property', done => {
|
||||||
TestHelper.request(server, done, {
|
TestHelper.request(server, done, {
|
||||||
method: 'put',
|
method: 'put',
|
||||||
url: '/template/treatment/200000000000000000000001',
|
url: '/template/condition/200000000000000000000001',
|
||||||
auth: {basic: 'admin'},
|
auth: {basic: 'admin'},
|
||||||
httpStatus: 200,
|
httpStatus: 200,
|
||||||
req: {name: 'heat aging'}
|
req: {name: 'heat aging'}
|
||||||
}).end((err, res) => {
|
}).end((err, res) => {
|
||||||
if (err) return done(err);
|
if (err) return done(err);
|
||||||
TemplateTreatmentModel.findById(res.body._id).lean().exec((err, data:any) => {
|
TemplateConditionModel.findById(res.body._id).lean().exec((err, data:any) => {
|
||||||
if (err) return done(err);
|
if (err) return done(err);
|
||||||
should(data).have.only.keys('_id', 'name', 'version', 'number_prefix', 'parameters', '__v');
|
should(data).have.only.keys('_id', 'name', 'version', 'parameters', '__v');
|
||||||
should(data).have.property('name', 'heat aging');
|
should(data).have.property('name', 'heat aging');
|
||||||
should(data).have.property('version', 2);
|
should(data).have.property('version', 2);
|
||||||
should(data).have.property('number_prefix', 'A');
|
|
||||||
should(data).have.property('parameters').have.lengthOf(2);
|
should(data).have.property('parameters').have.lengthOf(2);
|
||||||
should(data.parameters[0]).have.property('name', 'material');
|
should(data.parameters[0]).have.property('name', 'material');
|
||||||
should(data.parameters[1]).have.property('name', 'weeks');
|
should(data.parameters[1]).have.property('name', 'weeks');
|
||||||
@ -170,59 +170,59 @@ describe('/template', () => {
|
|||||||
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/200000000000000000000001',
|
url: '/template/condition/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]}}]}
|
||||||
}).end((err, res) => {
|
}).end((err, res) => {
|
||||||
if (err) return done(err);
|
if (err) return done(err);
|
||||||
should(_.omit(res.body, '_id')).be.eql({name: 'heat treatment', version: 2, number_prefix: 'A', parameters: [{name: 'time', range: {values: [1, 2, 5]}}]});
|
should(_.omit(res.body, '_id')).be.eql({name: 'heat treatment', version: 2, parameters: [{name: 'time', range: {values: [1, 2, 5]}}]});
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
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/200000000000000000000001',
|
url: '/template/condition/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}}]}
|
||||||
}).end((err, res) => {
|
}).end((err, res) => {
|
||||||
if (err) return done(err);
|
if (err) return done(err);
|
||||||
should(_.omit(res.body, '_id')).be.eql({name: 'heat treatment', version: 2, number_prefix: 'A', parameters: [{name: 'time', range: {min: 1, max: 11}}]});
|
should(_.omit(res.body, '_id')).be.eql({name: 'heat treatment', version: 2, parameters: [{name: 'time', range: {min: 1, max: 11}}]});
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
it('supports array type ranges', done => {
|
it('supports array type ranges', done => {
|
||||||
TestHelper.request(server, done, {
|
TestHelper.request(server, done, {
|
||||||
method: 'put',
|
method: 'put',
|
||||||
url: '/template/treatment/200000000000000000000001',
|
url: '/template/condition/200000000000000000000001',
|
||||||
auth: {basic: 'admin'},
|
auth: {basic: 'admin'},
|
||||||
httpStatus: 200,
|
httpStatus: 200,
|
||||||
req: {parameters: [{name: 'time', range: {type: 'array'}}]}
|
req: {parameters: [{name: 'time', range: {type: 'array'}}]}
|
||||||
}).end((err, res) => {
|
}).end((err, res) => {
|
||||||
if (err) return done(err);
|
if (err) return done(err);
|
||||||
should(_.omit(res.body, '_id')).be.eql({name: 'heat treatment', version: 2, number_prefix: 'A', parameters: [{name: 'time', range: {type: 'array'}}]});
|
should(_.omit(res.body, '_id')).be.eql({name: 'heat treatment', version: 2, parameters: [{name: 'time', range: {type: 'array'}}]});
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
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/200000000000000000000001',
|
url: '/template/condition/200000000000000000000001',
|
||||||
auth: {basic: 'admin'},
|
auth: {basic: 'admin'},
|
||||||
httpStatus: 200,
|
httpStatus: 200,
|
||||||
req: {parameters: [{name: 'time', range: {}}]}
|
req: {parameters: [{name: 'time', range: {}}]}
|
||||||
}).end((err, res) => {
|
}).end((err, res) => {
|
||||||
if (err) return done(err);
|
if (err) return done(err);
|
||||||
should(_.omit(res.body, '_id')).be.eql({name: 'heat treatment', version: 2, number_prefix: 'A', parameters: [{name: 'time', range: {}}]});
|
should(_.omit(res.body, '_id')).be.eql({name: 'heat treatment', version: 2, parameters: [{name: 'time', range: {}}]});
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
it('rejects not specified parameters', done => {
|
it('rejects not specified parameters', done => {
|
||||||
TestHelper.request(server, done, {
|
TestHelper.request(server, done, {
|
||||||
method: 'put',
|
method: 'put',
|
||||||
url: '/template/treatment/200000000000000000000001',
|
url: '/template/condition/200000000000000000000001',
|
||||||
auth: {basic: 'admin'},
|
auth: {basic: 'admin'},
|
||||||
httpStatus: 400,
|
httpStatus: 400,
|
||||||
req: {name: 'heat treatment', parameters: [{name: 'material', range: {xx: 5}}]},
|
req: {name: 'heat treatment', parameters: [{name: 'material', range: {xx: 5}}]},
|
||||||
@ -232,7 +232,7 @@ describe('/template', () => {
|
|||||||
it('rejects an invalid id', done => {
|
it('rejects an invalid id', done => {
|
||||||
TestHelper.request(server, done, {
|
TestHelper.request(server, done, {
|
||||||
method: 'put',
|
method: 'put',
|
||||||
url: '/template/treatment/2000000000h0000000000001',
|
url: '/template/condition/2000000000h0000000000001',
|
||||||
auth: {basic: 'admin'},
|
auth: {basic: 'admin'},
|
||||||
httpStatus: 404,
|
httpStatus: 404,
|
||||||
req: {name: 'heat aging', parameters: [{name: 'time', range: {min: 1}}]}
|
req: {name: 'heat aging', parameters: [{name: 'time', range: {min: 1}}]}
|
||||||
@ -241,26 +241,16 @@ describe('/template', () => {
|
|||||||
it('rejects an unknown id', done => {
|
it('rejects an unknown id', done => {
|
||||||
TestHelper.request(server, done, {
|
TestHelper.request(server, done, {
|
||||||
method: 'put',
|
method: 'put',
|
||||||
url: '/template/treatment/000000000000000000000001',
|
url: '/template/condition/000000000000000000000001',
|
||||||
auth: {basic: 'admin'},
|
auth: {basic: 'admin'},
|
||||||
httpStatus: 404,
|
httpStatus: 404,
|
||||||
req: {name: 'heat aging', parameters: [{name: 'time', range: {min: 1}}]}
|
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 => {
|
it('rejects an API key', done => {
|
||||||
TestHelper.request(server, done, {
|
TestHelper.request(server, done, {
|
||||||
method: 'put',
|
method: 'put',
|
||||||
url: '/template/treatment/200000000000000000000001',
|
url: '/template/condition/200000000000000000000001',
|
||||||
auth: {key: 'admin'},
|
auth: {key: 'admin'},
|
||||||
httpStatus: 401,
|
httpStatus: 401,
|
||||||
req: {}
|
req: {}
|
||||||
@ -269,7 +259,7 @@ describe('/template', () => {
|
|||||||
it('rejects requests from a write user', done => {
|
it('rejects requests from a write user', done => {
|
||||||
TestHelper.request(server, done, {
|
TestHelper.request(server, done, {
|
||||||
method: 'put',
|
method: 'put',
|
||||||
url: '/template/treatment/200000000000000000000001',
|
url: '/template/condition/200000000000000000000001',
|
||||||
auth: {basic: 'janedoe'},
|
auth: {basic: 'janedoe'},
|
||||||
httpStatus: 403,
|
httpStatus: 403,
|
||||||
req: {}
|
req: {}
|
||||||
@ -278,27 +268,26 @@ describe('/template', () => {
|
|||||||
it('rejects unauthorized requests', done => {
|
it('rejects unauthorized requests', done => {
|
||||||
TestHelper.request(server, done, {
|
TestHelper.request(server, done, {
|
||||||
method: 'put',
|
method: 'put',
|
||||||
url: '/template/treatment/200000000000000000000001',
|
url: '/template/condition/200000000000000000000001',
|
||||||
httpStatus: 401,
|
httpStatus: 401,
|
||||||
req: {}
|
req: {}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('POST /template/treatment/new', () => {
|
describe('POST /template/condition/new', () => {
|
||||||
it('returns the right treatment template', done => {
|
it('returns the right condition template', done => {
|
||||||
TestHelper.request(server, done, {
|
TestHelper.request(server, done, {
|
||||||
method: 'post',
|
method: 'post',
|
||||||
url: '/template/treatment/new',
|
url: '/template/condition/new',
|
||||||
auth: {basic: 'admin'},
|
auth: {basic: 'admin'},
|
||||||
httpStatus: 200,
|
httpStatus: 200,
|
||||||
req: {name: 'heat treatment3', number_prefix: 'C', parameters: [{name: 'material', range: {values: ['copper']}}]}
|
req: {name: 'heat treatment3', parameters: [{name: 'material', range: {values: ['copper']}}]}
|
||||||
}).end((err, res) => {
|
}).end((err, res) => {
|
||||||
if (err) return done(err);
|
if (err) return done(err);
|
||||||
should(res.body).have.only.keys('_id', 'name', 'version', 'number_prefix', 'parameters');
|
should(res.body).have.only.keys('_id', 'name', 'version', 'parameters');
|
||||||
should(res.body).have.property('name', 'heat treatment3');
|
should(res.body).have.property('name', 'heat treatment3');
|
||||||
should(res.body).have.property('version', 1);
|
should(res.body).have.property('version', 1);
|
||||||
should(res.body).have.property('number_prefix', 'C');
|
|
||||||
should(res.body).have.property('parameters').have.lengthOf(1);
|
should(res.body).have.property('parameters').have.lengthOf(1);
|
||||||
should(res.body.parameters[0]).have.property('name', 'material');
|
should(res.body.parameters[0]).have.property('name', 'material');
|
||||||
should(res.body.parameters[0]).have.property('range');
|
should(res.body.parameters[0]).have.property('range');
|
||||||
@ -310,18 +299,17 @@ describe('/template', () => {
|
|||||||
it('stores the template', done => {
|
it('stores the template', done => {
|
||||||
TestHelper.request(server, done, {
|
TestHelper.request(server, done, {
|
||||||
method: 'post',
|
method: 'post',
|
||||||
url: '/template/treatment/new',
|
url: '/template/condition/new',
|
||||||
auth: {basic: 'admin'},
|
auth: {basic: 'admin'},
|
||||||
httpStatus: 200,
|
httpStatus: 200,
|
||||||
req: {name: 'heat aging', number_prefix: 'C', 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);
|
||||||
TemplateTreatmentModel.findById(res.body._id).lean().exec((err, data:any) => {
|
TemplateConditionModel.findById(res.body._id).lean().exec((err, data:any) => {
|
||||||
if (err) return done(err);
|
if (err) return done(err);
|
||||||
should(data).have.only.keys('_id', 'name', 'version', 'number_prefix', 'parameters', '__v');
|
should(data).have.only.keys('_id', 'name', 'version', 'parameters', '__v');
|
||||||
should(data).have.property('name', 'heat aging');
|
should(data).have.property('name', 'heat aging');
|
||||||
should(data).have.property('version', 1);
|
should(data).have.property('version', 1);
|
||||||
should(data).have.property('number_prefix', 'C');
|
|
||||||
should(data).have.property('parameters').have.lengthOf(1);
|
should(data).have.property('parameters').have.lengthOf(1);
|
||||||
should(data.parameters[0]).have.property('name', 'time');
|
should(data.parameters[0]).have.property('name', 'time');
|
||||||
should(data.parameters[0]).have.property('range');
|
should(data.parameters[0]).have.property('range');
|
||||||
@ -333,117 +321,97 @@ describe('/template', () => {
|
|||||||
it('rejects a missing name', done => {
|
it('rejects a missing name', done => {
|
||||||
TestHelper.request(server, done, {
|
TestHelper.request(server, done, {
|
||||||
method: 'post',
|
method: 'post',
|
||||||
url: '/template/treatment/new',
|
url: '/template/condition/new',
|
||||||
auth: {basic: 'admin'},
|
auth: {basic: 'admin'},
|
||||||
httpStatus: 400,
|
httpStatus: 400,
|
||||||
req: {number_prefix: 'C', parameters: [{name: 'time', range: {min: 1}}]},
|
req: {parameters: [{name: 'time', range: {min: 1}}]},
|
||||||
res: {status: 'Invalid body format', details: '"name" is required'}
|
res: {status: 'Invalid body format', details: '"name" is required'}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
it('rejects a missing number prefix', done => {
|
it('rejects a number prefix', done => {
|
||||||
TestHelper.request(server, done, {
|
TestHelper.request(server, done, {
|
||||||
method: 'post',
|
method: 'post',
|
||||||
url: '/template/treatment/new',
|
url: '/template/condition/new',
|
||||||
auth: {basic: 'admin'},
|
auth: {basic: 'admin'},
|
||||||
httpStatus: 400,
|
httpStatus: 400,
|
||||||
req: {name: 'heat aging', parameters: [{name: 'time', range: {min: 1}}]},
|
req: {name: 'heat aging', number_prefix: 'C', parameters: [{name: 'time', range: {min: 1}}]},
|
||||||
res: {status: 'Invalid body format', details: '"number_prefix" is required'}
|
res: {status: 'Invalid body format', details: '"number_prefix" is not allowed'}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
it('rejects missing parameters', done => {
|
it('rejects missing parameters', done => {
|
||||||
TestHelper.request(server, done, {
|
TestHelper.request(server, done, {
|
||||||
method: 'post',
|
method: 'post',
|
||||||
url: '/template/treatment/new',
|
url: '/template/condition/new',
|
||||||
auth: {basic: 'admin'},
|
auth: {basic: 'admin'},
|
||||||
httpStatus: 400,
|
httpStatus: 400,
|
||||||
req: {name: 'heat aging', number_prefix: 'C'},
|
req: {name: 'heat aging'},
|
||||||
res: {status: 'Invalid body format', details: '"parameters" is required'}
|
res: {status: 'Invalid body format', details: '"parameters" is required'}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
it('rejects a missing parameter name', done => {
|
it('rejects a missing parameter name', done => {
|
||||||
TestHelper.request(server, done, {
|
TestHelper.request(server, done, {
|
||||||
method: 'post',
|
method: 'post',
|
||||||
url: '/template/treatment/new',
|
url: '/template/condition/new',
|
||||||
auth: {basic: 'admin'},
|
auth: {basic: 'admin'},
|
||||||
httpStatus: 400,
|
httpStatus: 400,
|
||||||
req: {name: 'heat aging', number_prefix: 'C', parameters: [{range: {min: 1}}]},
|
req: {name: 'heat aging', parameters: [{range: {min: 1}}]},
|
||||||
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 number prefix containing numbers', done => {
|
|
||||||
TestHelper.request(server, done, {
|
|
||||||
method: 'post',
|
|
||||||
url: '/template/treatment/new',
|
|
||||||
auth: {basic: 'admin'},
|
|
||||||
httpStatus: 400,
|
|
||||||
req: {name: 'heat aging', number_prefix: 'AB5', parameters: [{name: 'time', range: {min: 1}}]},
|
|
||||||
res: {status: 'Invalid body format', details: '"number_prefix" with value "AB5" fails to match the required pattern: /^[a-zA-Z]+$/'}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
it('rejects a missing parameter range', done => {
|
it('rejects a missing parameter range', done => {
|
||||||
TestHelper.request(server, done, {
|
TestHelper.request(server, done, {
|
||||||
method: 'post',
|
method: 'post',
|
||||||
url: '/template/treatment/new',
|
url: '/template/condition/new',
|
||||||
auth: {basic: 'admin'},
|
auth: {basic: 'admin'},
|
||||||
httpStatus: 400,
|
httpStatus: 400,
|
||||||
req: {name: 'heat aging', number_prefix: 'C', parameters: [{name: 'time'}]},
|
req: {name: 'heat aging', parameters: [{name: 'time'}]},
|
||||||
res: {status: 'Invalid body format', details: '"parameters[0].range" is required'}
|
res: {status: 'Invalid body format', details: '"parameters[0].range" is required'}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
it('rejects an invalid parameter range property', done => {
|
it('rejects an invalid parameter range property', done => {
|
||||||
TestHelper.request(server, done, {
|
TestHelper.request(server, done, {
|
||||||
method: 'post',
|
method: 'post',
|
||||||
url: '/template/treatment/new',
|
url: '/template/condition/new',
|
||||||
auth: {basic: 'admin'},
|
auth: {basic: 'admin'},
|
||||||
httpStatus: 400,
|
httpStatus: 400,
|
||||||
req: {name: 'heat aging', number_prefix: 'C', parameters: [{name: 'time', range: {xx: 1}}]},
|
req: {name: 'heat aging', parameters: [{name: 'time', range: {xx: 1}}]},
|
||||||
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 wrong properties', done => {
|
it('rejects wrong properties', done => {
|
||||||
TestHelper.request(server, done, {
|
TestHelper.request(server, done, {
|
||||||
method: 'post',
|
method: 'post',
|
||||||
url: '/template/treatment/new',
|
url: '/template/condition/new',
|
||||||
auth: {basic: 'admin'},
|
auth: {basic: 'admin'},
|
||||||
httpStatus: 400,
|
httpStatus: 400,
|
||||||
req: {name: 'heat aging', number_prefix: 'C', parameters: [{name: 'time', range: {}}], xx: 33},
|
req: {name: 'heat aging', parameters: [{name: 'time', range: {}}], xx: 33},
|
||||||
res: {status: 'Invalid body format', details: '"xx" is not allowed'}
|
res: {status: 'Invalid body format', details: '"xx" is not allowed'}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
it('rejects already existing number prefixes', done => {
|
|
||||||
TestHelper.request(server, done, {
|
|
||||||
method: 'post',
|
|
||||||
url: '/template/treatment/new',
|
|
||||||
auth: {basic: 'admin'},
|
|
||||||
httpStatus: 400,
|
|
||||||
req: {name: 'heat aging', number_prefix: 'B', parameters: [{name: 'time', range: {min: 1}}]},
|
|
||||||
res: {status: 'Number prefix already taken'}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
it('rejects an API key', done => {
|
it('rejects an API key', done => {
|
||||||
TestHelper.request(server, done, {
|
TestHelper.request(server, done, {
|
||||||
method: 'post',
|
method: 'post',
|
||||||
url: '/template/treatment/new',
|
url: '/template/condition/new',
|
||||||
auth: {key: 'admin'},
|
auth: {key: 'admin'},
|
||||||
httpStatus: 401,
|
httpStatus: 401,
|
||||||
req: {name: 'heat aging', number_prefix: 'C', parameters: [{name: 'time', range: {min: 1}}]}
|
req: {name: 'heat aging', parameters: [{name: 'time', range: {min: 1}}]}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
it('rejects requests from a write user', done => {
|
it('rejects requests from a write user', done => {
|
||||||
TestHelper.request(server, done, {
|
TestHelper.request(server, done, {
|
||||||
method: 'post',
|
method: 'post',
|
||||||
url: '/template/treatment/new',
|
url: '/template/condition/new',
|
||||||
auth: {basic: 'janedoe'},
|
auth: {basic: 'janedoe'},
|
||||||
httpStatus: 403,
|
httpStatus: 403,
|
||||||
req: {name: 'heat aging', number_prefix: 'C', parameters: [{name: 'time', range: {min: 1}}]}
|
req: {name: 'heat aging', parameters: [{name: 'time', range: {min: 1}}]}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
it('rejects unauthorized requests', done => {
|
it('rejects unauthorized requests', done => {
|
||||||
TestHelper.request(server, done, {
|
TestHelper.request(server, done, {
|
||||||
method: 'post',
|
method: 'post',
|
||||||
url: '/template/treatment/new',
|
url: '/template/condition/new',
|
||||||
httpStatus: 401,
|
httpStatus: 401,
|
||||||
req: {name: 'heat aging', number_prefix: 'C', parameters: [{name: 'time', range: {min: 1}}]}
|
req: {name: 'heat aging', parameters: [{name: 'time', range: {min: 1}}]}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -2,8 +2,8 @@ import express from 'express';
|
|||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
|
|
||||||
import TemplateValidate from './validate/template';
|
import TemplateValidate from './validate/template';
|
||||||
import TemplateTreatmentModel from '../models/treatment_template';
|
import ConditionTemplateModel from '../models/condition_template';
|
||||||
import TemplateMeasurementModel from '../models/measurement_template';
|
import MeasurementTemplateModel from '../models/measurement_template';
|
||||||
import res400 from './validate/res400';
|
import res400 from './validate/res400';
|
||||||
import IdValidate from './validate/id';
|
import IdValidate from './validate/id';
|
||||||
|
|
||||||
@ -11,23 +11,23 @@ import IdValidate from './validate/id';
|
|||||||
|
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
|
|
||||||
router.get('/template/:collection(measurements|treatments)', (req, res, next) => {
|
router.get('/template/:collection(measurements|conditions)', (req, res, next) => {
|
||||||
if (!req.auth(res, ['read', 'write', 'maintain', 'dev', 'admin'], 'basic')) return;
|
if (!req.auth(res, ['read', 'write', 'maintain', 'dev', 'admin'], 'basic')) return;
|
||||||
|
|
||||||
req.params.collection = req.params.collection.replace(/s$/g, ''); // remove trailing s
|
req.params.collection = req.params.collection.replace(/s$/g, ''); // remove trailing s
|
||||||
model(req).find({}).lean().exec((err, data) => {
|
model(req).find({}).lean().exec((err, data) => {
|
||||||
if (err) next (err);
|
if (err) next (err);
|
||||||
res.json(_.compact(data.map(e => TemplateValidate.output(e, req.params.collection)))); // validate all and filter null values from validation errors
|
res.json(_.compact(data.map(e => TemplateValidate.output(e)))); // validate all and filter null values from validation errors
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
router.get('/template/:collection(measurement|treatment)/' + IdValidate.parameter(), (req, res, next) => {
|
router.get('/template/:collection(measurement|condition)/' + IdValidate.parameter(), (req, res, next) => {
|
||||||
if (!req.auth(res, ['read', 'write', 'maintain', 'dev', 'admin'], 'basic')) return;
|
if (!req.auth(res, ['read', 'write', 'maintain', 'dev', 'admin'], 'basic')) return;
|
||||||
|
|
||||||
model(req).findById(req.params.id).lean().exec((err, data) => {
|
model(req).findById(req.params.id).lean().exec((err, data) => {
|
||||||
if (err) next (err);
|
if (err) next (err);
|
||||||
if (data) {
|
if (data) {
|
||||||
res.json(TemplateValidate.output(data, req.params.collection));
|
res.json(TemplateValidate.output(data));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
res.status(404).json({status: 'Not found'});
|
res.status(404).json({status: 'Not found'});
|
||||||
@ -35,64 +35,46 @@ router.get('/template/:collection(measurement|treatment)/' + IdValidate.paramete
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
router.put('/template/:collection(measurement|treatment)/' + IdValidate.parameter(), async (req, res, next) => {
|
router.put('/template/:collection(measurement|condition)/' + IdValidate.parameter(), async (req, res, next) => {
|
||||||
if (!req.auth(res, ['maintain', 'admin'], 'basic')) return;
|
if (!req.auth(res, ['maintain', 'admin'], 'basic')) return;
|
||||||
|
|
||||||
const {error, value: template} = TemplateValidate.input(req.body, 'change', req.params.collection);
|
const {error, value: template} = TemplateValidate.input(req.body, 'change');
|
||||||
if (error) return res400(error, res);
|
if (error) return res400(error, res);
|
||||||
|
|
||||||
const templateData = await model(req).findById(req.params.id).lean().exec().catch(err => {next(err);}) as any;
|
const templateData = await model(req).findById(req.params.id).lean().exec().catch(err => {next(err);}) as any;
|
||||||
if (templateData instanceof Error) return;
|
if (templateData instanceof Error) return;
|
||||||
if (!templateData) {
|
if (!templateData) {
|
||||||
res.status(404).json({status: 'Not found'});
|
return res.status(404).json({status: 'Not found'});
|
||||||
}
|
|
||||||
|
|
||||||
if (_.has(template, 'number_prefix') && template.number_prefix !== templateData.number_prefix) { // got new number_prefix
|
|
||||||
if (!await numberPrefixCheck(template, req, res, next)) return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_.isEqual(_.pick(templateData, _.keys(template)), template)) { // data was changed
|
if (!_.isEqual(_.pick(templateData, _.keys(template)), template)) { // data was changed
|
||||||
template.version = templateData.version + 1; // increase version
|
template.version = templateData.version + 1; // increase version
|
||||||
await new (model(req))(_.assign({}, _.omit(templateData, ['_id', '__v']), template)).save((err, data) => { // save new template, fill with old properties
|
await new (model(req))(_.assign({}, _.omit(templateData, ['_id', '__v']), template)).save((err, data) => { // save new template, fill with old properties
|
||||||
if (err) next (err);
|
if (err) next (err);
|
||||||
res.json(TemplateValidate.output(data.toObject(), req.params.collection));
|
res.json(TemplateValidate.output(data.toObject()));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
res.json(TemplateValidate.output(templateData, req.params.collection));
|
res.json(TemplateValidate.output(templateData));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
router.post('/template/:collection(measurement|treatment)/new', async (req, res, next) => {
|
router.post('/template/:collection(measurement|condition)/new', async (req, res, next) => {
|
||||||
if (!req.auth(res, ['maintain', 'admin'], 'basic')) return;
|
if (!req.auth(res, ['maintain', 'admin'], 'basic')) return;
|
||||||
|
|
||||||
const {error, value: template} = TemplateValidate.input(req.body, 'new', req.params.collection);
|
const {error, value: template} = TemplateValidate.input(req.body, 'new');
|
||||||
if (error) return res400(error, res);
|
if (error) return res400(error, res);
|
||||||
|
|
||||||
if (_.has(template, 'number_prefix')) { // got number_prefix
|
|
||||||
if (!await numberPrefixCheck(template, req, res, next)) return;
|
|
||||||
}
|
|
||||||
|
|
||||||
template.version = 1; // set template version
|
template.version = 1; // set template version
|
||||||
await new (model(req))(template).save((err, data) => {
|
await new (model(req))(template).save((err, data) => {
|
||||||
if (err) next (err);
|
if (err) next (err);
|
||||||
res.json(TemplateValidate.output(data.toObject(), req.params.collection));
|
res.json(TemplateValidate.output(data.toObject()));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
module.exports = router;
|
module.exports = router;
|
||||||
|
|
||||||
|
|
||||||
async function numberPrefixCheck (template, req, res, next) { // check if number_prefix is available
|
|
||||||
const data = await model(req).findOne({number_prefix: template.number_prefix}).lean().exec().catch(err => {next(err); return false;}) as any;
|
|
||||||
if (data) {
|
|
||||||
res.status(400).json({status: 'Number prefix already taken'});
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
function model (req) { // return right template model
|
function model (req) { // return right template model
|
||||||
return req.params.collection === 'treatment' ? TemplateTreatmentModel : TemplateMeasurementModel;
|
return req.params.collection === 'condition' ? ConditionTemplateModel : MeasurementTemplateModel;
|
||||||
}
|
}
|
@ -9,6 +9,7 @@ describe('/user', () => {
|
|||||||
before(done => TestHelper.before(done));
|
before(done => TestHelper.before(done));
|
||||||
beforeEach(done => server = TestHelper.beforeEach(server, done));
|
beforeEach(done => server = TestHelper.beforeEach(server, done));
|
||||||
afterEach(done => TestHelper.afterEach(server, done));
|
afterEach(done => TestHelper.afterEach(server, done));
|
||||||
|
after(done => TestHelper.after(done));
|
||||||
|
|
||||||
describe('GET /users', () => {
|
describe('GET /users', () => {
|
||||||
it('returns all users', done => {
|
it('returns all users', done => {
|
||||||
@ -288,7 +289,7 @@ describe('/user', () => {
|
|||||||
auth: {basic: 'admin'},
|
auth: {basic: 'admin'},
|
||||||
httpStatus: 400,
|
httpStatus: 400,
|
||||||
req: {pass: 'password'},
|
req: {pass: 'password'},
|
||||||
res: {status: 'Invalid body format', details: '"pass" with value "password" fails to match the required pattern: /^(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[!"#%&\'()*+,-.\\/:;<=>?@[\\]^_`{|}~])(?=\\S+$).{8,}$/'}
|
res: {status: 'Invalid body format', details: '"pass" with value "password" fails to match the required pattern: /^(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[!"#%&\'()*+,-.\\/:;<=>?@[\\]^_`{|}~])(?=\\S+$)[a-zA-Z0-9!"#%&\'()*+,\\-.\\/:;<=>?@[\\]^_`{|}~]{8,}$/'}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
it('rejects requests from non-admins for another user', done => {
|
it('rejects requests from non-admins for another user', done => {
|
||||||
@ -546,7 +547,7 @@ describe('/user', () => {
|
|||||||
auth: {basic: 'admin'},
|
auth: {basic: 'admin'},
|
||||||
httpStatus: 400,
|
httpStatus: 400,
|
||||||
req: {email: 'john.doe@bosch.com', name: 'johndoe', pass: 'password', level: 'read', location: 'Rng', device_name: 'Alpha II'},
|
req: {email: 'john.doe@bosch.com', name: 'johndoe', pass: 'password', level: 'read', location: 'Rng', device_name: 'Alpha II'},
|
||||||
res: {status: 'Invalid body format', details: '"pass" with value "password" fails to match the required pattern: /^(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[!"#%&\'()*+,-.\\/:;<=>?@[\\]^_`{|}~])(?=\\S+$).{8,}$/'}
|
res: {status: 'Invalid body format', details: '"pass" with value "password" fails to match the required pattern: /^(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[!"#%&\'()*+,-.\\/:;<=>?@[\\]^_`{|}~])(?=\\S+$)[a-zA-Z0-9!"#%&\'()*+,\\-.\\/:;<=>?@[\\]^_`{|}~]{8,}$/'}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
it('rejects requests from non-admins', done => {
|
it('rejects requests from non-admins', done => {
|
||||||
|
@ -40,7 +40,6 @@ router.put('/user:username([/](?!key|new).?*|/?)', async (req, res, next) => {
|
|||||||
|
|
||||||
const username = getUsername(req, res);
|
const username = getUsername(req, res);
|
||||||
if (!username) return;
|
if (!username) return;
|
||||||
console.log(username);
|
|
||||||
|
|
||||||
const {error, value: user} = UserValidate.input(req.body, 'change' + (req.authDetails.level === 'admin'? 'admin' : ''));
|
const {error, value: user} = UserValidate.input(req.body, 'change' + (req.authDetails.level === 'admin'? 'admin' : ''));
|
||||||
if (error) return res400(error, res);
|
if (error) return res400(error, res);
|
||||||
@ -154,8 +153,6 @@ function getUsername (req, res) { // returns username or false if action is not
|
|||||||
async function usernameCheck (name, res, next) { // check if username is already taken
|
async function usernameCheck (name, res, next) { // check if username is already taken
|
||||||
const userData = await UserModel.findOne({name: name}).lean().exec().catch(err => next(err)) as any;
|
const userData = await UserModel.findOne({name: name}).lean().exec().catch(err => next(err)) as any;
|
||||||
if (userData instanceof Error) return false;
|
if (userData instanceof Error) return false;
|
||||||
console.log(userData);
|
|
||||||
console.log(UserValidate.isSpecialName(name));
|
|
||||||
if (userData || UserValidate.isSpecialName(name)) {
|
if (userData || UserValidate.isSpecialName(name)) {
|
||||||
res.status(400).json({status: 'Username already taken'});
|
res.status(400).json({status: 'Username already taken'});
|
||||||
return false;
|
return false;
|
||||||
|
@ -1,50 +0,0 @@
|
|||||||
import Joi from '@hapi/joi';
|
|
||||||
|
|
||||||
import IdValidate from './id';
|
|
||||||
|
|
||||||
export default class ConditionValidate {
|
|
||||||
private static condition = {
|
|
||||||
number: Joi.string()
|
|
||||||
.max(128),
|
|
||||||
|
|
||||||
parameters: Joi.object()
|
|
||||||
.pattern(/.*/, Joi.alternatives()
|
|
||||||
.try(
|
|
||||||
Joi.string().max(128),
|
|
||||||
Joi.number(),
|
|
||||||
Joi.boolean(),
|
|
||||||
Joi.array()
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
static input (data, param) { // validate input, set param to 'new' to make all attributes required
|
|
||||||
if (param === 'new') {
|
|
||||||
return Joi.object({
|
|
||||||
sample_id: IdValidate.get().required(),
|
|
||||||
parameters: this.condition.parameters.required(),
|
|
||||||
treatment_template: IdValidate.get().required()
|
|
||||||
}).validate(data);
|
|
||||||
}
|
|
||||||
else if (param === 'change') {
|
|
||||||
return Joi.object({
|
|
||||||
parameters: this.condition.parameters
|
|
||||||
}).validate(data);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return{error: 'No parameter specified!', value: {}};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static output (data) { // validate output and strip unwanted properties, returns null if not valid
|
|
||||||
data = IdValidate.stringify(data);
|
|
||||||
const {value, error} = Joi.object({
|
|
||||||
_id: IdValidate.get(),
|
|
||||||
sample_id: IdValidate.get(),
|
|
||||||
number: this.condition.number,
|
|
||||||
parameters: this.condition.parameters,
|
|
||||||
treatment_template: IdValidate.get()
|
|
||||||
}).validate(data, {stripUnknown: true});
|
|
||||||
return error !== undefined? null : value;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,39 +1,39 @@
|
|||||||
import joi from '@hapi/joi';
|
import Joi from '@hapi/joi';
|
||||||
|
|
||||||
import IdValidate from './id';
|
import IdValidate from './id';
|
||||||
|
|
||||||
export default class MaterialValidate { // validate input for material
|
export default class MaterialValidate { // validate input for material
|
||||||
private static material = {
|
private static material = {
|
||||||
name: joi.string()
|
name: Joi.string()
|
||||||
.max(128),
|
.max(128),
|
||||||
|
|
||||||
supplier: joi.string()
|
supplier: Joi.string()
|
||||||
.max(128),
|
.max(128),
|
||||||
|
|
||||||
group: joi.string()
|
group: Joi.string()
|
||||||
.max(128),
|
.max(128),
|
||||||
|
|
||||||
mineral: joi.number()
|
mineral: Joi.number()
|
||||||
.integer()
|
.integer()
|
||||||
.min(0)
|
.min(0)
|
||||||
.max(100),
|
.max(100),
|
||||||
|
|
||||||
glass_fiber: joi.number()
|
glass_fiber: Joi.number()
|
||||||
.integer()
|
.integer()
|
||||||
.min(0)
|
.min(0)
|
||||||
.max(100),
|
.max(100),
|
||||||
|
|
||||||
carbon_fiber: joi.number()
|
carbon_fiber: Joi.number()
|
||||||
.integer()
|
.integer()
|
||||||
.min(0)
|
.min(0)
|
||||||
.max(100),
|
.max(100),
|
||||||
|
|
||||||
numbers: joi.array()
|
numbers: Joi.array()
|
||||||
.items(joi.object({
|
.items(Joi.object({
|
||||||
color: joi.string()
|
color: Joi.string()
|
||||||
.max(128)
|
.max(128)
|
||||||
.required(),
|
.required(),
|
||||||
number: joi.string()
|
number: Joi.string()
|
||||||
.max(128)
|
.max(128)
|
||||||
.allow('')
|
.allow('')
|
||||||
.required()
|
.required()
|
||||||
@ -42,7 +42,7 @@ export default class MaterialValidate { // validate input for material
|
|||||||
|
|
||||||
static input (data, param) { // validate input, set param to 'new' to make all attributes required
|
static input (data, param) { // validate input, set param to 'new' to make all attributes required
|
||||||
if (param === 'new') {
|
if (param === 'new') {
|
||||||
return joi.object({
|
return Joi.object({
|
||||||
name: this.material.name.required(),
|
name: this.material.name.required(),
|
||||||
supplier: this.material.supplier.required(),
|
supplier: this.material.supplier.required(),
|
||||||
group: this.material.group.required(),
|
group: this.material.group.required(),
|
||||||
@ -53,7 +53,7 @@ export default class MaterialValidate { // validate input for material
|
|||||||
}).validate(data);
|
}).validate(data);
|
||||||
}
|
}
|
||||||
else if (param === 'change') {
|
else if (param === 'change') {
|
||||||
return joi.object({
|
return Joi.object({
|
||||||
name: this.material.name,
|
name: this.material.name,
|
||||||
supplier: this.material.supplier,
|
supplier: this.material.supplier,
|
||||||
group: this.material.group,
|
group: this.material.group,
|
||||||
@ -70,7 +70,7 @@ export default class MaterialValidate { // validate input for material
|
|||||||
|
|
||||||
static output (data) { // validate output and strip unwanted properties, returns null if not valid
|
static output (data) { // validate output and strip unwanted properties, returns null if not valid
|
||||||
data = IdValidate.stringify(data);
|
data = IdValidate.stringify(data);
|
||||||
const {value, error} = joi.object({
|
const {value, error} = Joi.object({
|
||||||
_id: IdValidate.get(),
|
_id: IdValidate.get(),
|
||||||
name: this.material.name,
|
name: this.material.name,
|
||||||
supplier: this.material.supplier,
|
supplier: this.material.supplier,
|
||||||
@ -82,4 +82,17 @@ export default class MaterialValidate { // validate input for material
|
|||||||
}).validate(data, {stripUnknown: true});
|
}).validate(data, {stripUnknown: true});
|
||||||
return error !== undefined? null : value;
|
return error !== undefined? null : value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static outputV() { // return output validator
|
||||||
|
return Joi.object({
|
||||||
|
_id: IdValidate.get(),
|
||||||
|
name: this.material.name,
|
||||||
|
supplier: this.material.supplier,
|
||||||
|
group: this.material.group,
|
||||||
|
mineral: this.material.mineral,
|
||||||
|
glass_fiber: this.material.glass_fiber,
|
||||||
|
carbon_fiber: this.material.carbon_fiber,
|
||||||
|
numbers: this.material.numbers
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
@ -12,13 +12,14 @@ export default class MeasurementValidate {
|
|||||||
Joi.boolean(),
|
Joi.boolean(),
|
||||||
Joi.array()
|
Joi.array()
|
||||||
)
|
)
|
||||||
|
.allow(null)
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
static input (data, param) { // validate input, set param to 'new' to make all attributes required
|
static input (data, param) { // validate input, set param to 'new' to make all attributes required
|
||||||
if (param === 'new') {
|
if (param === 'new') {
|
||||||
return Joi.object({
|
return Joi.object({
|
||||||
condition_id: IdValidate.get().required(),
|
sample_id: IdValidate.get().required(),
|
||||||
values: this.measurement.values.required(),
|
values: this.measurement.values.required(),
|
||||||
measurement_template: IdValidate.get().required()
|
measurement_template: IdValidate.get().required()
|
||||||
}).validate(data);
|
}).validate(data);
|
||||||
@ -37,7 +38,7 @@ export default class MeasurementValidate {
|
|||||||
data = IdValidate.stringify(data);
|
data = IdValidate.stringify(data);
|
||||||
const {value, error} = Joi.object({
|
const {value, error} = Joi.object({
|
||||||
_id: IdValidate.get(),
|
_id: IdValidate.get(),
|
||||||
condition_id: IdValidate.get(),
|
sample_id: IdValidate.get(),
|
||||||
values: this.measurement.values,
|
values: this.measurement.values,
|
||||||
measurement_template: IdValidate.get()
|
measurement_template: IdValidate.get()
|
||||||
}).validate(data, {stripUnknown: true});
|
}).validate(data, {stripUnknown: true});
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import Joi from '@hapi/joi';
|
import Joi from '@hapi/joi';
|
||||||
|
|
||||||
export default class ParametersValidate {
|
export default class ParametersValidate {
|
||||||
static input (data, parameters, param) { // data to validate, parameters from template, param: 'new', 'change'
|
static input (data, parameters, param) { // data to validate, parameters from template, param: 'new', 'change', 'null'(null values are allowed)
|
||||||
let joiObject = {};
|
let joiObject = {};
|
||||||
parameters.forEach(parameter => {
|
parameters.forEach(parameter => {
|
||||||
if (parameter.range.hasOwnProperty('values')) { // append right validation method according to parameter
|
if (parameter.range.hasOwnProperty('values')) { // append right validation method according to parameter
|
||||||
@ -39,6 +39,9 @@ export default class ParametersValidate {
|
|||||||
if (param === 'new') {
|
if (param === 'new') {
|
||||||
joiObject[parameter.name] = joiObject[parameter.name].required()
|
joiObject[parameter.name] = joiObject[parameter.name].required()
|
||||||
}
|
}
|
||||||
|
else if (param === 'null') {
|
||||||
|
joiObject[parameter.name] = joiObject[parameter.name].allow(null)
|
||||||
|
}
|
||||||
});
|
});
|
||||||
return Joi.object(joiObject).validate(data);
|
return Joi.object(joiObject).validate(data);
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
import Joi from '@hapi/joi';
|
import Joi from '@hapi/joi';
|
||||||
|
|
||||||
import IdValidate from './id';
|
import IdValidate from './id';
|
||||||
|
import UserValidate from './user';
|
||||||
|
import MaterialValidate from './material';
|
||||||
|
|
||||||
export default class SampleValidate {
|
export default class SampleValidate {
|
||||||
private static sample = {
|
private static sample = {
|
||||||
@ -17,13 +19,16 @@ export default class SampleValidate {
|
|||||||
.max(128)
|
.max(128)
|
||||||
.allow(''),
|
.allow(''),
|
||||||
|
|
||||||
|
condition: Joi.object(),
|
||||||
|
|
||||||
notes: Joi.object({
|
notes: Joi.object({
|
||||||
comment: Joi.string()
|
comment: Joi.string()
|
||||||
.max(512),
|
.max(512)
|
||||||
|
.allow(''),
|
||||||
|
|
||||||
sample_references: Joi.array()
|
sample_references: Joi.array()
|
||||||
.items(Joi.object({
|
.items(Joi.object({
|
||||||
id: IdValidate.get(),
|
sample_id: IdValidate.get(),
|
||||||
|
|
||||||
relation: Joi.string()
|
relation: Joi.string()
|
||||||
.max(128)
|
.max(128)
|
||||||
@ -47,6 +52,7 @@ export default class SampleValidate {
|
|||||||
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(),
|
||||||
|
condition: this.sample.condition.required(),
|
||||||
material_id: IdValidate.get().required(),
|
material_id: IdValidate.get().required(),
|
||||||
notes: this.sample.notes.required()
|
notes: this.sample.notes.required()
|
||||||
}).validate(data);
|
}).validate(data);
|
||||||
@ -56,6 +62,7 @@ export default class SampleValidate {
|
|||||||
color: this.sample.color,
|
color: this.sample.color,
|
||||||
type: this.sample.type,
|
type: this.sample.type,
|
||||||
batch: this.sample.batch,
|
batch: this.sample.batch,
|
||||||
|
condition: this.sample.condition,
|
||||||
material_id: IdValidate.get(),
|
material_id: IdValidate.get(),
|
||||||
notes: this.sample.notes,
|
notes: this.sample.notes,
|
||||||
}).validate(data);
|
}).validate(data);
|
||||||
@ -65,18 +72,39 @@ export default class SampleValidate {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static output (data) { // validate output and strip unwanted properties, returns null if not valid
|
static output (data, param = 'refs') { // validate output and strip unwanted properties, returns null if not valid
|
||||||
data = IdValidate.stringify(data);
|
data = IdValidate.stringify(data);
|
||||||
const {value, error} = Joi.object({
|
let joiObject;
|
||||||
|
if (param === 'refs') {
|
||||||
|
joiObject = {
|
||||||
_id: IdValidate.get(),
|
_id: IdValidate.get(),
|
||||||
number: this.sample.number,
|
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,
|
||||||
|
condition: this.sample.condition,
|
||||||
material_id: IdValidate.get(),
|
material_id: IdValidate.get(),
|
||||||
note_id: IdValidate.get().allow(null),
|
note_id: IdValidate.get().allow(null),
|
||||||
user_id: IdValidate.get()
|
user_id: IdValidate.get()
|
||||||
}).validate(data, {stripUnknown: true});
|
};
|
||||||
|
}
|
||||||
|
else if(param === 'details') {
|
||||||
|
joiObject = {
|
||||||
|
_id: IdValidate.get(),
|
||||||
|
number: this.sample.number,
|
||||||
|
color: this.sample.color,
|
||||||
|
type: this.sample.type,
|
||||||
|
batch: this.sample.batch,
|
||||||
|
condition: this.sample.condition,
|
||||||
|
material: MaterialValidate.outputV(),
|
||||||
|
notes: this.sample.notes,
|
||||||
|
user: UserValidate.username()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const {value, error} = Joi.object(joiObject).validate(data, {stripUnknown: true});
|
||||||
return error !== undefined? null : value;
|
return error !== undefined? null : value;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -9,13 +9,7 @@ export default class TemplateValidate {
|
|||||||
version: Joi.number()
|
version: Joi.number()
|
||||||
.min(1),
|
.min(1),
|
||||||
|
|
||||||
number_prefix: Joi.string()
|
|
||||||
.pattern(/^[a-zA-Z]+$/)
|
|
||||||
.min(1)
|
|
||||||
.max(16),
|
|
||||||
|
|
||||||
parameters: Joi.array()
|
parameters: Joi.array()
|
||||||
.min(1)
|
|
||||||
.items(
|
.items(
|
||||||
Joi.object({
|
Joi.object({
|
||||||
name: Joi.string()
|
name: Joi.string()
|
||||||
@ -43,63 +37,32 @@ export default class TemplateValidate {
|
|||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
static input (data, param, template) { // validate input, set param to 'new' to make all attributes required
|
static input (data, param) { // validate input, set param to 'new' to make all attributes required
|
||||||
if (param === 'new') {
|
if (param === 'new') {
|
||||||
if (template === 'treatment') {
|
|
||||||
return Joi.object({
|
|
||||||
name: this.template.name.required(),
|
|
||||||
number_prefix: this.template.number_prefix.required(),
|
|
||||||
parameters: this.template.parameters.required()
|
|
||||||
}).validate(data);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return Joi.object({
|
return Joi.object({
|
||||||
name: this.template.name.required(),
|
name: this.template.name.required(),
|
||||||
parameters: this.template.parameters.required()
|
parameters: this.template.parameters.required()
|
||||||
}).validate(data);
|
}).validate(data);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else if (param === 'change') {
|
else if (param === 'change') {
|
||||||
if (template === 'treatment') {
|
|
||||||
return Joi.object({
|
|
||||||
name: this.template.name,
|
|
||||||
number_prefix: this.template.number_prefix,
|
|
||||||
parameters: this.template.parameters
|
|
||||||
}).validate(data);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return Joi.object({
|
return Joi.object({
|
||||||
name: this.template.name,
|
name: this.template.name,
|
||||||
parameters: this.template.parameters
|
parameters: this.template.parameters
|
||||||
}).validate(data);
|
}).validate(data);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else {
|
else {
|
||||||
return{error: 'No parameter specified!', value: {}};
|
return{error: 'No parameter specified!', value: {}};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static output (data, template) { // validate output and strip unwanted properties, returns null if not valid
|
static output (data) { // validate output and strip unwanted properties, returns null if not valid
|
||||||
data = IdValidate.stringify(data);
|
data = IdValidate.stringify(data);
|
||||||
let joiObject;
|
const {value, error} = Joi.object({
|
||||||
if (template === 'treatment') { // differentiate between measurement and treatment (has number_prefix) template
|
|
||||||
joiObject = {
|
|
||||||
_id: IdValidate.get(),
|
|
||||||
name: this.template.name,
|
|
||||||
version: this.template.version,
|
|
||||||
number_prefix: this.template.number_prefix,
|
|
||||||
parameters: this.template.parameters
|
|
||||||
};
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
joiObject = {
|
|
||||||
_id: IdValidate.get(),
|
_id: IdValidate.get(),
|
||||||
name: this.template.name,
|
name: this.template.name,
|
||||||
version: this.template.version,
|
version: this.template.version,
|
||||||
parameters: this.template.parameters
|
parameters: this.template.parameters
|
||||||
};
|
}).validate(data, {stripUnknown: true});
|
||||||
}
|
|
||||||
const {value, error} = Joi.object(joiObject).validate(data, {stripUnknown: true});
|
|
||||||
return error !== undefined? null : value;
|
return error !== undefined? null : value;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -84,4 +84,8 @@ export default class UserValidate { // validate input for user
|
|||||||
static isSpecialName (name) { // true if name belongs to special names
|
static isSpecialName (name) { // true if name belongs to special names
|
||||||
return this.specialUsernames.indexOf(name) > -1;
|
return this.specialUsernames.indexOf(name) > -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static username() {
|
||||||
|
return this.user.name;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
131
src/test/db.json
131
src/test/db.json
@ -7,6 +7,11 @@
|
|||||||
"type": "granulate",
|
"type": "granulate",
|
||||||
"color": "black",
|
"color": "black",
|
||||||
"batch": "",
|
"batch": "",
|
||||||
|
"condition": {
|
||||||
|
"material": "copper",
|
||||||
|
"weeks": 3,
|
||||||
|
"condition_template": {"$oid":"200000000000000000000001"}
|
||||||
|
},
|
||||||
"material_id": {"$oid":"100000000000000000000004"},
|
"material_id": {"$oid":"100000000000000000000004"},
|
||||||
"note_id": null,
|
"note_id": null,
|
||||||
"user_id": {"$oid":"000000000000000000000002"},
|
"user_id": {"$oid":"000000000000000000000002"},
|
||||||
@ -19,6 +24,11 @@
|
|||||||
"type": "granulate",
|
"type": "granulate",
|
||||||
"color": "natural",
|
"color": "natural",
|
||||||
"batch": "1560237365",
|
"batch": "1560237365",
|
||||||
|
"condition": {
|
||||||
|
"material": "copper",
|
||||||
|
"weeks": 3,
|
||||||
|
"condition_template": {"$oid":"200000000000000000000001"}
|
||||||
|
},
|
||||||
"material_id": {"$oid":"100000000000000000000001"},
|
"material_id": {"$oid":"100000000000000000000001"},
|
||||||
"note_id": {"$oid":"500000000000000000000001"},
|
"note_id": {"$oid":"500000000000000000000001"},
|
||||||
"user_id": {"$oid":"000000000000000000000002"},
|
"user_id": {"$oid":"000000000000000000000002"},
|
||||||
@ -31,6 +41,11 @@
|
|||||||
"type": "part",
|
"type": "part",
|
||||||
"color": "black",
|
"color": "black",
|
||||||
"batch": "1704-005",
|
"batch": "1704-005",
|
||||||
|
"condition": {
|
||||||
|
"material": "copper",
|
||||||
|
"weeks": 3,
|
||||||
|
"condition_template": {"$oid":"200000000000000000000001"}
|
||||||
|
},
|
||||||
"material_id": {"$oid":"100000000000000000000005"},
|
"material_id": {"$oid":"100000000000000000000005"},
|
||||||
"note_id": {"$oid":"500000000000000000000002"},
|
"note_id": {"$oid":"500000000000000000000002"},
|
||||||
"user_id": {"$oid":"000000000000000000000003"},
|
"user_id": {"$oid":"000000000000000000000003"},
|
||||||
@ -43,6 +58,11 @@
|
|||||||
"type": "granulate",
|
"type": "granulate",
|
||||||
"color": "black",
|
"color": "black",
|
||||||
"batch": "1653000308",
|
"batch": "1653000308",
|
||||||
|
"condition": {
|
||||||
|
"material": "hot air",
|
||||||
|
"weeks": 5,
|
||||||
|
"condition_template": {"$oid":"200000000000000000000001"}
|
||||||
|
},
|
||||||
"material_id": {"$oid":"100000000000000000000005"},
|
"material_id": {"$oid":"100000000000000000000005"},
|
||||||
"note_id": {"$oid":"500000000000000000000003"},
|
"note_id": {"$oid":"500000000000000000000003"},
|
||||||
"user_id": {"$oid":"000000000000000000000003"},
|
"user_id": {"$oid":"000000000000000000000003"},
|
||||||
@ -55,11 +75,27 @@
|
|||||||
"type": "granulate",
|
"type": "granulate",
|
||||||
"color": "black",
|
"color": "black",
|
||||||
"batch": "1653000308",
|
"batch": "1653000308",
|
||||||
|
"condition": {
|
||||||
|
"condition_template": {"$oid":"200000000000000000000003"}
|
||||||
|
},
|
||||||
"material_id": {"$oid":"100000000000000000000005"},
|
"material_id": {"$oid":"100000000000000000000005"},
|
||||||
"note_id": {"$oid":"500000000000000000000003"},
|
"note_id": null,
|
||||||
"user_id": {"$oid":"000000000000000000000003"},
|
"user_id": {"$oid":"000000000000000000000003"},
|
||||||
"status": -1,
|
"status": -1,
|
||||||
"__v": 0
|
"__v": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"_id": {"$oid":"400000000000000000000006"},
|
||||||
|
"number": "Rng36",
|
||||||
|
"type": "granulate",
|
||||||
|
"color": "black",
|
||||||
|
"batch": "",
|
||||||
|
"condition": {},
|
||||||
|
"material_id": {"$oid":"100000000000000000000004"},
|
||||||
|
"note_id": null,
|
||||||
|
"user_id": {"$oid":"000000000000000000000002"},
|
||||||
|
"status": 0,
|
||||||
|
"__v": 0
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"notes": [
|
"notes": [
|
||||||
@ -73,7 +109,7 @@
|
|||||||
"_id": {"$oid":"500000000000000000000002"},
|
"_id": {"$oid":"500000000000000000000002"},
|
||||||
"comment": "",
|
"comment": "",
|
||||||
"sample_references": [{
|
"sample_references": [{
|
||||||
"id": {"$oid":"400000000000000000000004"},
|
"sample_id": {"$oid":"400000000000000000000004"},
|
||||||
"relation": "granulate to sample"
|
"relation": "granulate to sample"
|
||||||
}],
|
}],
|
||||||
"custom_fields": {
|
"custom_fields": {
|
||||||
@ -85,7 +121,7 @@
|
|||||||
"_id": {"$oid":"500000000000000000000003"},
|
"_id": {"$oid":"500000000000000000000003"},
|
||||||
"comment": "",
|
"comment": "",
|
||||||
"sample_references": [{
|
"sample_references": [{
|
||||||
"id": {"$oid":"400000000000000000000003"},
|
"sample_id": {"$oid":"400000000000000000000003"},
|
||||||
"relation": "part to sample"
|
"relation": "part to sample"
|
||||||
}],
|
}],
|
||||||
"custom_fields": {
|
"custom_fields": {
|
||||||
@ -234,60 +270,10 @@
|
|||||||
"__v": 0
|
"__v": 0
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"conditions": [
|
|
||||||
{
|
|
||||||
"_id": {"$oid":"700000000000000000000001"},
|
|
||||||
"sample_id": {"$oid":"400000000000000000000001"},
|
|
||||||
"number": "A1",
|
|
||||||
"parameters": {
|
|
||||||
"material": "copper",
|
|
||||||
"weeks": 3
|
|
||||||
},
|
|
||||||
"treatment_template": {"$oid":"200000000000000000000001"},
|
|
||||||
"status": 10,
|
|
||||||
"__v": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"_id": {"$oid":"700000000000000000000002"},
|
|
||||||
"sample_id": {"$oid":"400000000000000000000002"},
|
|
||||||
"number": "A1",
|
|
||||||
"parameters": {
|
|
||||||
"material": "copper",
|
|
||||||
"weeks": 3
|
|
||||||
},
|
|
||||||
"treatment_template": {"$oid":"200000000000000000000001"},
|
|
||||||
"status": 10,
|
|
||||||
"__v": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"_id": {"$oid":"700000000000000000000003"},
|
|
||||||
"sample_id": {"$oid":"400000000000000000000004"},
|
|
||||||
"number": "A1",
|
|
||||||
"parameters": {
|
|
||||||
"material": "copper",
|
|
||||||
"weeks": 3
|
|
||||||
},
|
|
||||||
"treatment_template": {"$oid":"200000000000000000000001"},
|
|
||||||
"status": 10,
|
|
||||||
"__v": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"_id": {"$oid":"700000000000000000000004"},
|
|
||||||
"sample_id": {"$oid":"400000000000000000000001"},
|
|
||||||
"number": "A2",
|
|
||||||
"parameters": {
|
|
||||||
"material": "hot air",
|
|
||||||
"weeks": 5
|
|
||||||
},
|
|
||||||
"treatment_template": {"$oid":"200000000000000000000001"},
|
|
||||||
"status": 10,
|
|
||||||
"__v": 0
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"measurements": [
|
"measurements": [
|
||||||
{
|
{
|
||||||
"_id": {"$oid":"800000000000000000000001"},
|
"_id": {"$oid":"800000000000000000000001"},
|
||||||
"condition_id": {"$oid":"700000000000000000000001"},
|
"sample_id": {"$oid":"400000000000000000000001"},
|
||||||
"values": {
|
"values": {
|
||||||
"dpt": [
|
"dpt": [
|
||||||
[3997.12558,98.00555],
|
[3997.12558,98.00555],
|
||||||
@ -301,7 +287,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"_id": {"$oid":"800000000000000000000002"},
|
"_id": {"$oid":"800000000000000000000002"},
|
||||||
"condition_id": {"$oid":"700000000000000000000002"},
|
"sample_id": {"$oid":"400000000000000000000002"},
|
||||||
"values": {
|
"values": {
|
||||||
"weight %": 0.5,
|
"weight %": 0.5,
|
||||||
"standard deviation": 0.2
|
"standard deviation": 0.2
|
||||||
@ -312,21 +298,41 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"_id": {"$oid":"800000000000000000000003"},
|
"_id": {"$oid":"800000000000000000000003"},
|
||||||
"condition_id": {"$oid":"700000000000000000000003"},
|
"sample_id": {"$oid":"400000000000000000000003"},
|
||||||
"values": {
|
"values": {
|
||||||
"val1": 1
|
"val1": 1
|
||||||
},
|
},
|
||||||
"status": 0,
|
"status": 0,
|
||||||
"measurement_template": {"$oid":"300000000000000000000003"},
|
"measurement_template": {"$oid":"300000000000000000000003"},
|
||||||
"__v": 0
|
"__v": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"_id": {"$oid":"800000000000000000000004"},
|
||||||
|
"sample_id": {"$oid":"400000000000000000000003"},
|
||||||
|
"values": {
|
||||||
|
"val1": 1
|
||||||
|
},
|
||||||
|
"status": -1,
|
||||||
|
"measurement_template": {"$oid":"300000000000000000000003"},
|
||||||
|
"__v": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"_id": {"$oid":"800000000000000000000005"},
|
||||||
|
"sample_id": {"$oid":"400000000000000000000002"},
|
||||||
|
"values": {
|
||||||
|
"weight %": 0.5,
|
||||||
|
"standard deviation":null
|
||||||
|
},
|
||||||
|
"status": 10,
|
||||||
|
"measurement_template": {"$oid":"300000000000000000000002"},
|
||||||
|
"__v": 0
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"treatment_templates": [
|
"condition_templates": [
|
||||||
{
|
{
|
||||||
"_id": {"$oid":"200000000000000000000001"},
|
"_id": {"$oid":"200000000000000000000001"},
|
||||||
"name": "heat treatment",
|
"name": "heat treatment",
|
||||||
"version": 1,
|
"version": 1,
|
||||||
"number_prefix": "A",
|
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
"name": "material",
|
"name": "material",
|
||||||
@ -351,7 +357,6 @@
|
|||||||
"_id": {"$oid":"200000000000000000000002"},
|
"_id": {"$oid":"200000000000000000000002"},
|
||||||
"name": "heat treatment 2",
|
"name": "heat treatment 2",
|
||||||
"version": 2,
|
"version": 2,
|
||||||
"number_prefix": "B",
|
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
"name": "material",
|
"name": "material",
|
||||||
@ -359,6 +364,14 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"__v": 0
|
"__v": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"_id": {"$oid":"200000000000000000000003"},
|
||||||
|
"name": "raw material",
|
||||||
|
"version": 1,
|
||||||
|
"parameters": [
|
||||||
|
],
|
||||||
|
"__v": 0
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"measurement_templates": [
|
"measurement_templates": [
|
||||||
|
@ -10,6 +10,7 @@ export default class TestHelper {
|
|||||||
user: {pass: 'Xyz890*)', key: '000000000000000000001001'},
|
user: {pass: 'Xyz890*)', key: '000000000000000000001001'},
|
||||||
johnnydoe: {pass: 'Xyz890*)', key: '000000000000000000001004'}
|
johnnydoe: {pass: 'Xyz890*)', key: '000000000000000000001004'}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static res = { // default responses
|
public static res = { // default responses
|
||||||
400: {status: 'Bad request'},
|
400: {status: 'Bad request'},
|
||||||
401: {status: 'Unauthorized'},
|
401: {status: 'Unauthorized'},
|
||||||
@ -38,7 +39,11 @@ export default class TestHelper {
|
|||||||
server.close(done);
|
server.close(done);
|
||||||
}
|
}
|
||||||
|
|
||||||
static request (server, done, options) { // options in form: {method, url, auth: {key/basic: 'name' or 'key'/{name, pass}}, httpStatus, req, res}
|
static after(done) {
|
||||||
|
db.disconnect(done);
|
||||||
|
}
|
||||||
|
|
||||||
|
static request (server, done, options) { // options in form: {method, url, auth: {key/basic: 'name' or 'key'/{name, pass}}, httpStatus, req, res, default (set to false if you want to dismiss default .end handling)}
|
||||||
let st = supertest(server);
|
let st = supertest(server);
|
||||||
if (options.hasOwnProperty('auth') && options.auth.hasOwnProperty('key')) { // resolve API key
|
if (options.hasOwnProperty('auth') && options.auth.hasOwnProperty('key')) { // resolve API key
|
||||||
options.url += '?key=' + (this.auth.hasOwnProperty(options.auth.key)? this.auth[options.auth.key].key : options.auth.key);
|
options.url += '?key=' + (this.auth.hasOwnProperty(options.auth.key)? this.auth[options.auth.key].key : options.auth.key);
|
||||||
@ -57,6 +62,9 @@ export default class TestHelper {
|
|||||||
st = st.delete(options.url)
|
st = st.delete(options.url)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if (options.hasOwnProperty('reqType')) { // request body
|
||||||
|
st = st.type(options.reqType);
|
||||||
|
}
|
||||||
if (options.hasOwnProperty('req')) { // request body
|
if (options.hasOwnProperty('req')) { // request body
|
||||||
st = st.send(options.req);
|
st = st.send(options.req);
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user