diff --git a/.idea/dictionaries/VLE2FE.xml b/.idea/dictionaries/VLE2FE.xml
index 2d3f5ec..16f4de3 100644
--- a/.idea/dictionaries/VLE2FE.xml
+++ b/.idea/dictionaries/VLE2FE.xml
@@ -18,6 +18,7 @@
frameguard
functionlink
glassfibrecontent
+ isin
janedoe
johnnydoe
kfingew
diff --git a/api/api.yaml b/api/api.yaml
index 7089f4a..45be8c4 100644
--- a/api/api.yaml
+++ b/api/api.yaml
@@ -5,28 +5,35 @@ info:
title: Digital fingerprint of plastics - API
version: 1.0.0
description: |
- This API gives access to the project database.
+ This **API** gives access to the project database.
+
Access is restricted. Authentication can be obtained with HTTP Basic Auth using username and password.
- Data access methods can also be accessed using an API key at the URL ending like ?key=xxx
+ Data access methods can also be accessed using an API key at the URL ending like ?key=xxx
+
The description lists available authentication methods, also the locks of each method close correspondingly
- if the entered authentication is allowed.
- There are a number of different user levels:
-
- - read: read access to the samples database
- - write: write access to the samples database, users can change only the values they created
- - maintain: functions like changing templates, validating data, changing values of others
- - dev: handling machine learning models
- - admin: user administration
-
+ if the entered authentication is allowed.
+
+
+ There are a number of different user levels:
+
+ | | read sample data | add samples/edit own | read spectral data | edit other's data | maintain templates | edit users |
+ |:-----:|:----------------:|:--------------------:|:------------------:|:-----------------:|:------------------:|:----------:|
+ | read | yes | no | no | no | no | no |
+ | write | yes | yes | no | no | no | no |
+ | dev | yes | yes | yes | yes | yes | no |
+ | admin | yes | yes | yes | yes | yes | yes |
+
Password policy:
-
- - at least one digit
- - at least one lower case letter
- - at least one upper case letter
- - at least one of the following special characters: !"#%&'()*+,-./:;<=>?@[\]^_`{|}~
- - no whitespace
- - at least 8 characters
-
+
+ - at least one digit
+ - at least one lower case letter
+ - at least one upper case letter
+ - at least one of the following special characters: !"#%&'()*+,-./:;<=>?@[\]^_`{|}~
+ - no whitespace
+ - at least 8 characters
+
+
+
x-doc: |
status:
diff --git a/api/material.yaml b/api/material.yaml
index 593afb1..548bce8 100644
--- a/api/material.yaml
+++ b/api/material.yaml
@@ -1,7 +1,7 @@
/materials:
get:
summary: lists all materials
- description: 'Auth: all, levels: read, write, maintain, dev, admin'
+ description: 'Auth: all, levels: read, write, dev, admin'
x-doc: returns only materials with status 10
tags:
- /material
@@ -31,7 +31,7 @@
- $ref: 'api.yaml#/components/parameters/State'
get:
summary: lists all new/deleted materials
- description: 'Auth: basic, levels: maintain, admin'
+ description: 'Auth: basic, levels: dev, admin'
x-doc: returns materials with status 0/-1
tags:
- /material
@@ -54,8 +54,8 @@
- $ref: 'api.yaml#/components/parameters/Id'
get:
summary: get material details
- description: 'Auth: all, levels: read, write, maintain, dev, admin'
- x-doc: deleted samples are available only for maintain/admin
+ description: 'Auth: all, levels: read, write, dev, admin'
+ x-doc: deleted samples are available only for dev/admin
tags:
- /material
responses:
@@ -73,7 +73,7 @@
$ref: 'api.yaml#/components/responses/500'
put:
summary: change material
- description: 'Auth: basic, levels: write, maintain, dev, admin'
+ description: 'Auth: basic, levels: write, dev, admin'
x-doc: status is reset to 0 on any changes, deleted samples cannot be changed
tags:
- /material
@@ -104,7 +104,7 @@
$ref: 'api.yaml#/components/responses/500'
delete:
summary: delete material
- description: 'Auth: basic, levels: write, maintain, dev, admin'
+ description: 'Auth: basic, levels: write, dev, admin'
x-doc: sets status to -1
tags:
- /material
@@ -129,7 +129,7 @@
- $ref: 'api.yaml#/components/parameters/Id'
put:
summary: restore material
- description: 'Auth: basic, levels: maintain, admin'
+ description: 'Auth: basic, levels: dev, admin'
x-doc: status is set to 0
tags:
- /material
@@ -152,7 +152,7 @@
- $ref: 'api.yaml#/components/parameters/Id'
put:
summary: restore material
- description: 'Auth: basic, levels: maintain, admin'
+ description: 'Auth: basic, levels: dev, admin'
x-doc: status is set to 10
tags:
- /material
@@ -173,7 +173,7 @@
/material/new:
post:
summary: add material
- description: 'Auth: basic, levels: write, maintain, dev, admin'
+ description: 'Auth: basic, levels: write, dev, admin'
x-doc: 'Adds status: 0 automatically'
tags:
- /material
@@ -204,7 +204,7 @@
/material/groups:
get:
summary: list all existing material groups
- description: 'Auth: all, levels: read, write, maintain, dev, admin'
+ description: 'Auth: all, levels: read, write, dev, admin'
tags:
- /material
responses:
@@ -227,7 +227,7 @@
/material/suppliers:
get:
summary: list all existing material suppliers
- description: 'Auth: all, levels: read, write, maintain, dev, admin'
+ description: 'Auth: all, levels: read, write, dev, admin'
tags:
- /material
responses:
diff --git a/api/measurement.yaml b/api/measurement.yaml
index 0c29e77..453b5e6 100644
--- a/api/measurement.yaml
+++ b/api/measurement.yaml
@@ -3,8 +3,8 @@
- $ref: 'api.yaml#/components/parameters/Id'
get:
summary: measurement values by id
- description: 'Auth: all, levels: read, write, maintain, dev, admin'
- x-doc: deleted samples are available only for maintain/admin
+ description: 'Auth: all, levels: read, write, dev, admin, spectral data can only be accessed by dev and admin'
+ x-doc: deleted samples are available only for dev/admin
tags:
- /measurement
responses:
@@ -24,7 +24,7 @@
$ref: 'api.yaml#/components/responses/500'
put:
summary: change measurement
- description: 'Auth: basic, levels: write, maintain, dev, admin'
+ description: 'Auth: basic, levels: write, dev, admin'
x-doc: status is reset to 0 on any changes, deleted measurements cannot be edited
tags:
- /measurement
@@ -57,7 +57,7 @@
$ref: 'api.yaml#/components/responses/500'
delete:
summary: delete measurement
- description: 'Auth: basic, levels: write, maintain, dev, admin'
+ description: 'Auth: basic, levels: write, dev, admin'
x-doc: sets status to -1
tags:
- /measurement
@@ -82,7 +82,7 @@
- $ref: 'api.yaml#/components/parameters/Id'
put:
summary: restore measurement
- description: 'Auth: basic, levels: maintain, admin'
+ description: 'Auth: basic, levels: dev, admin'
x-doc: status is set to 0
tags:
- /measurement
@@ -105,7 +105,7 @@
- $ref: 'api.yaml#/components/parameters/Id'
put:
summary: set measurement status to validated
- description: 'Auth: basic, levels: maintain, admin'
+ description: 'Auth: basic, levels: dev, admin'
x-doc: status is set to 10
tags:
- /measurement
@@ -126,7 +126,7 @@
/measurement/new:
post:
summary: add measurement
- description: 'Auth: basic, levels: write, maintain, dev, admin'
+ description: 'Auth: basic, levels: write, dev, admin'
x-doc: 'Adds status: 0 automatically'
tags:
- /measurement
diff --git a/api/root.yaml b/api/root.yaml
index 6727c17..49a1a50 100644
--- a/api/root.yaml
+++ b/api/root.yaml
@@ -21,7 +21,7 @@
/authorized:
get:
summary: Checks authorization
- description: 'Auth: all, levels: read, write, maintain, dev, admin'
+ description: 'Auth: all, levels: read, write, dev, admin'
tags:
- /
responses:
@@ -69,7 +69,9 @@
example: 30
get:
summary: get changelog
- description: 'Auth: basic, levels: maintain, admin
Displays all logs older than timestamp, sorted by date descending, page defaults to 0, pagesize defaults to 25
Avoid using high page numbers for older logs, better use an older timestamp'
+ description: 'Auth: basic, levels: dev, admin
Displays all logs older than timestamp, sorted by date descending,
+ page defaults to 0, pagesize defaults to 25
Avoid using high page numbers for older logs, better use an older
+ timestamp'
tags:
- /
responses:
diff --git a/api/sample.yaml b/api/sample.yaml
index 82d6c7c..b6689d9 100644
--- a/api/sample.yaml
+++ b/api/sample.yaml
@@ -1,8 +1,9 @@
/samples:
get:
summary: all samples in overview
- description: 'Auth: all, levels: read, write, maintain, dev, admin'
- x-doc: 'Limitations: paging and csv output does not work when including the spectrum measurement fields as well as the returned number of total samples'
+ description: 'Auth: all, levels: read, write, dev, admin, spectral data can only be accessed by dev and admin'
+ x-doc: 'Limitations: paging and csv output does not work when including the spectrum measurement fields as well as
+ the returned number of total samples'
tags:
- /sample
parameters:
@@ -19,7 +20,8 @@
type: string
example: 5ea0450ed851c30a90e70894
- name: to-page
- description: relative change of pages, use negative values to get back, defaults to 0, works only together with page-size
+ description: 'relative change of pages, use negative values to get back, defaults to 0, works only together with
+ page-size'
in: query
schema:
type: string
@@ -43,7 +45,8 @@
type: boolean
example: false
- name: fields[]
- description: the fields to include in the output as array, defaults to ['_id','number','type','batch','material_id','color','condition','note_id','user_id','added']
+ description: "the fields to include in the output as array, defaults to ['_id', 'number', 'type',
+ 'batch', 'material_id', 'color', 'condition', 'note_id', 'user_id', 'added']"
in: query
schema:
type: array
@@ -51,19 +54,23 @@
type: string
example: ['number', 'batch']
- name: filters[]
- description: "the filters to apply as an array of URIComponent encoded objects in the form {mode: 'eq/ne/lt/lte/gt/gte/in/nin', field: 'material.m', values: ['15']} using encodeURIComponent(JSON.stringify({}))"
+ description: "the filters to apply as an array of URIComponent encoded objects in the form {mode:
+ 'eq/ne/lt/lte/gt/gte/in/nin', field: 'material.m', values: ['15']} using encodeURIComponent(JSON.stringify({}))"
in: query
schema:
type: array
items:
type: string
- example: ["%7B%22mode%22%3A%22eq%22%2C%22field%22%3A%22material.m%22%2C%22values%22%3A%5B%2215%22%5D%7D", "%7B%22mode%22%3A%22isin%22%2C%22field%22%3A%22material.supplier%22%2C%22values%22%3A%5B%22BASF%22%2C%22DSM%22%5D%7D"]
+ example: '["%7B%22mode%22%3A%22eq%22%2C%22field%22%3A%22material.m%22%2C%22values%22%3A%5B%2215%22%5D%7D",
+ "%7B%22mode%22%3A%22isin%22%2C%22field%22%3A%22material.supplier%22%2C%22values%22%3A%5B%22BASF%22%2C%22DSM%22
+ %5D%7D"]'
responses:
200:
description: samples overview (if the csv parameter is set, this is in CSV instead of JSON format)
headers:
x-total-items:
- description: Total number of available items when from-id is not specified and spectrum field is not included
+ description: Total number of available items when from-id is not specified and spectrum field is not
+ included
schema:
type: integer
example: 243
@@ -87,7 +94,7 @@
- $ref: 'api.yaml#/components/parameters/State'
get:
summary: all new/deleted samples in overview
- description: 'Auth: basic, levels: maintain, admin'
+ description: 'Auth: basic, levels: admin'
x-doc: returns only samples with status 0/-1
tags:
- /sample
@@ -108,7 +115,7 @@
/samples/count:
get:
summary: total number of samples
- description: 'Auth: all, levels: read, write, maintain, dev, admin'
+ description: 'Auth: all, levels: read, write, dev, admin'
tags:
- /sample
responses:
@@ -129,8 +136,9 @@
- $ref: 'api.yaml#/components/parameters/Id'
get:
summary: sample details
- description: 'Auth: all, levels: read, write, maintain, dev, admin
Returns validated as well as new measurements'
- x-doc: deleted samples are available only for maintain/admin
+ description: 'Auth: all, levels: read, write, dev, admin, spectral data can only be accessed by dev and admin
+ Returns validated as well as new measurements'
+ x-doc: deleted samples are available only for dev/admin
tags:
- /sample
responses:
@@ -150,7 +158,8 @@
$ref: 'api.yaml#/components/responses/500'
put:
summary: change sample
- description: 'Auth: basic, levels: write, maintain, dev, admin
Only maintain and admin are allowed to edit samples created by another user'
+ description: 'Auth: basic, levels: write, dev, admin
+ Only dev and admin are allowed to edit samples created by another user'
x-doc: status is reset to 0 on any changes, deleted samples cannot be changed
tags:
- /sample
@@ -181,8 +190,10 @@
$ref: 'api.yaml#/components/responses/500'
delete:
summary: delete sample
- description: 'Auth: basic, levels: write, maintain, dev, admin
Only maintain and admin are allowed to edit samples created by another user'
- x-doc: sets status to -1, notes and references to this sample are also kept, only note_fields are updated accordingly
+ description: 'Auth: basic, levels: write, dev, admin
+ Only dev and admin are allowed to edit samples created by another user'
+ x-doc: sets status to -1, notes and references to this sample are also kept, only note_fields are updated
+ accordingly
tags:
- /sample
security:
@@ -206,8 +217,9 @@
- $ref: 'api.yaml#/components/parameters/Number'
get:
summary: sample details
- description: 'Auth: all, levels: read, write, maintain, dev, admin
Returns validated as well as new measurements'
- x-doc: deleted samples are available only for maintain/admin
+ description: 'Auth: all, levels: read, write, dev, admin, spectral data can only be accessed by dev and admin
+ Returns validated as well as new measurements'
+ x-doc: deleted samples are available only for dev/admin
tags:
- /sample
responses:
@@ -231,7 +243,7 @@
- $ref: 'api.yaml#/components/parameters/Id'
put:
summary: restore sample
- description: 'Auth: basic, levels: maintain, admin'
+ description: 'Auth: basic, levels: dev, admin'
x-doc: status is set to 0
tags:
- /sample
@@ -254,7 +266,7 @@
- $ref: 'api.yaml#/components/parameters/Id'
put:
summary: set sample status to validated
- description: 'Auth: basic, levels: maintain, admin'
+ description: 'Auth: basic, levels: dev, admin'
x-doc: status is set to 10
tags:
- /sample
@@ -277,7 +289,8 @@
/sample/new:
post:
summary: add sample
- description: 'Auth: basic, levels: write, maintain, dev, admin. Number property is only for admin when adding existing samples'
+ description: 'Auth: basic, levels: write, dev, admin. Number property is only for admin when adding existing
+ samples'
x-doc: 'Adds status: 0 automatically'
tags:
- /sample
@@ -313,7 +326,7 @@
/sample/notes/fields:
get:
summary: list all existing field names for custom notes fields
- description: 'Auth: all, levels: read, write, maintain, dev, admin'
+ description: 'Auth: all, levels: read, write, dev, admin'
x-doc: integrity has to be ensured
tags:
- /sample
diff --git a/api/template.yaml b/api/template.yaml
index 6af1294..2306749 100644
--- a/api/template.yaml
+++ b/api/template.yaml
@@ -3,7 +3,7 @@
- $ref: 'api.yaml#/components/parameters/Collection'
get:
summary: all available templates
- description: 'Auth: basic, levels: read, write, maintain, dev, admin'
+ description: 'Auth: basic, levels: read, write, dev, admin'
tags:
- /template
security:
@@ -28,7 +28,7 @@
- $ref: 'api.yaml#/components/parameters/Id'
get:
summary: template details
- description: 'Auth: basic, levels: read, write, maintain, admin'
+ description: 'Auth: basic, levels: read, write, dev, admin'
tags:
- /template
security:
@@ -48,7 +48,7 @@
$ref: 'api.yaml#/components/responses/500'
put:
summary: change template
- description: 'Auth: basic, levels: maintain, admin'
+ description: 'Auth: basic, levels: dev, admin'
x-doc: With a change a new version is set, resulting in a new template with a new id
tags:
- /template
@@ -83,7 +83,7 @@
- $ref: 'api.yaml#/components/parameters/Collection'
post:
summary: add template
- description: 'Auth: basic, levels: maintain, admin'
+ description: 'Auth: basic, levels: dev, admin'
tags:
- /template
security:
diff --git a/api/user.yaml b/api/user.yaml
index 757ebf0..0d08408 100644
--- a/api/user.yaml
+++ b/api/user.yaml
@@ -24,7 +24,7 @@
/user:
get:
summary: list own user details
- description: 'Auth: basic, levels: read, write, maintain, admin'
+ description: 'Auth: basic, levels: read, write, dev, admin'
tags:
- /user
security:
@@ -44,7 +44,7 @@
$ref: 'api.yaml#/components/responses/500'
put:
summary: change user details
- description: 'Auth: basic, levels: read, write, maintain, admin'
+ description: 'Auth: basic, levels: read, write, dev, admin'
tags:
- /user
security:
@@ -86,7 +86,7 @@
$ref: 'api.yaml#/components/responses/500'
delete:
summary: delete user
- description: 'Auth: basic, levels: read, write, maintain, admin'
+ description: 'Auth: basic, levels: read, write, dev, admin'
tags:
- /user
security:
@@ -174,7 +174,7 @@
/user/key:
get:
summary: get API key for the user
- description: 'Auth: basic, levels: read, write, maintain, dev, admin'
+ description: 'Auth: basic, levels: read, write, dev, admin'
tags:
- /user
security:
diff --git a/data_import/import.js b/data_import/import.js
index 4c5d031..6add295 100644
--- a/data_import/import.js
+++ b/data_import/import.js
@@ -217,27 +217,34 @@ async function allDpts() {
res.data.forEach(sample => {
sampleIds[sample.number] = sample._id;
});
- const dptRegex = /(.*?)_(.*?)_(\d+|[a-zA-Z0-9]+[_.]\d+)(_JDX)?[.]{1,2}(DPT|csv|CSV)/;
+ const dptRegex = /(.*?)_(.*?)_(\d+|[a-zA-Z0-9]+[_.]\d+)(_JDX)?[.]{1,2}(DPT|csv|CSV|JDX)/;
const dpts = fs.readdirSync(dptFiles);
for (let i in dpts) {
let regexInput;
const bjRes = /^(Bj[FT]?)\s?([a-z0-9_]*)_JDX.DPT/.exec(dpts[i]);
- if (bjRes) {
+ if (bjRes) { // correct Bj numbers with space
regexInput = `Bj01_${bjRes[1]}${bjRes[2]}_0.DPT`;
}
- else {
+ else { // remove _JDX from name
regexInput = dpts[i].replace(/_JDX.*\./, '.');
}
const regexRes = dptRegex.exec(regexInput);
if (regexRes && !sampleIds[regexRes[2]]) { // when sample number includes an additional _x instead of having _x_x for spectrum description
regexRes[2] = `${regexRes[2]}_${regexRes[3].split('_')[0]}`;
}
- if (regexRes && !sampleIds[regexRes[2]] && sampleIds[regexRes[2].split('_')[0]]) { // when number_abx does not exist but number
- dptSampleAddLog.push(`Trying to find ${regexRes[2].split('_')[0]}`);
- dptSampleAddLog.push(host + '/sample/' + sampleIds[regexRes[2].split('_')[0]]);
- res = await axios({
+ let baseSample = null;
+ if (regexRes) {
+ baseSample = regexRes[2].split('_')[0];
+ if (baseSample === 'Wa11') { // as Wa11 samples use all the same material
+ baseSample = 'Wa11_B0_1';
+ }
+ }
+ if (regexRes && !sampleIds[regexRes[2]] && sampleIds[baseSample]) { // when number_abx does not exist but number
+ dptSampleAddLog.push(`Trying to find ${baseSample}`);
+ dptSampleAddLog.push(host + '/sample/' + sampleIds[baseSample]);
+ res = await axios({ // get base sample
method: 'get',
- url: host + '/sample/number/' + sampleIds[regexRes[2].split('_')[0]],
+ url: host + '/sample/' + stripSpaces(sampleIds[baseSample]),
auth: {
username: 'admin',
password: 'Abc123!#'
@@ -245,14 +252,14 @@ async function allDpts() {
}).catch(err => {
if (err.response) {
console.error(err.response.data);
- errors.push(`DPT Could not fetch sample ${regexRes[2].split('_')[0]}: ${err.response.data}`);
+ errors.push(`DPT Could not fetch sample ${baseSample}: ${JSON.stringify(err.response.data)}`);
}
});
- if (res.data) {
- dptSampleAddLog.push(JSON.stringify(res.data));
- const data = _.merge(_.pick(res.data, ['color', 'type', 'batch', 'material_id']), {number: regexRes[2], condition: {}, notes: {}});
+ if (res) {
+ const data = _.merge(_.pick(res.data, ['color', 'type', 'batch']),
+ {number: regexRes[2], condition: {}, notes: {}, material_id: res.data.material._id});
res = await axios({
- method: 'get',
+ method: 'post',
url: host + '/sample/new',
auth: {
username: res.data.user,
@@ -265,16 +272,10 @@ async function allDpts() {
errors.push(`DPT Could not save sample ${data}: ${err.response.data}`);
}
});
- console.error(res);
- console.error(data);
if (res.data) {
- dptSampleAddLog.push(`${regexRes[2]} from ${regexRes[2].split('_')[0]}`)
+ dptSampleAddLog.push(`${regexRes[2]} from ${baseSample}`)
sampleIds[regexRes[2]] = res.data._id;
}
- else {
- console.error(res);
- console.error(data);
- }
}
}
if (regexRes && sampleIds[regexRes[2]]) { // found matching sample
@@ -287,6 +288,7 @@ async function allDpts() {
measurement_template
};
data.values.device = regexRes[1];
+ data.values.filename = dpts[i];
data.values.dpt = f.split('\r\n').map(e => e.split(',').map(e => parseFloat(e)));
let rescale = false;
for (let i in data.values.dpt) {
@@ -321,7 +323,7 @@ async function allDpts() {
else {
console.log(`Could not find sample for ${dpts[i]}`);
if (regexRes) {
- errors.push(`Could not find sample for ${dpts[i]}; [DEBUG] ${regexRes[2]}, ${!sampleIds[regexRes[2]]}, ${sampleIds[regexRes[2].split('_')[0]]}`);
+ errors.push(`Could not find sample for ${dpts[i]}; [DEBUG] ${regexRes[2]}, ${!sampleIds[regexRes[2]]}, ${sampleIds[baseSample]}`);
}
else {
errors.push(`Could not find sample for ${dpts[i]} (did not match RegEx)`);
@@ -953,11 +955,12 @@ function customFields (comment, sampleNumber) {
}
function sampleType (type) {
- const allowedTypes = ['tension rod', 'part', 'granulate'];
- if (allowedTypes.indexOf(type) < 0) {
+ type = stripSpaces(type).toLowerCase();
+ const allowedTypes = {'tension rod': 'tension rod', 'Zugstab': 'tension rod', 'part': 'part', 'granulate': 'granulate'};
+ if (!allowedTypes[type]) {
typeLog.push(type);
}
- return allowedTypes.indexOf(type) >= 0 ? type : 'part';
+ return allowedTypes[type] ? allowedTypes[type] : 'part';
}
function stripSpaces(s) {
diff --git a/src/globals.ts b/src/globals.ts
index 81f80b8..f51bf57 100644
--- a/src/globals.ts
+++ b/src/globals.ts
@@ -1,8 +1,7 @@
const globals = {
- levels: [ // access levels
+ levels: [ // access levels, sorted asc by rights
'read',
'write',
- 'maintain',
'dev',
'admin'
],
diff --git a/src/routes/material.spec.ts b/src/routes/material.spec.ts
index 789f6e5..5d60983 100644
--- a/src/routes/material.spec.ts
+++ b/src/routes/material.spec.ts
@@ -208,7 +208,7 @@ describe('/material', () => {
res: {_id: '100000000000000000000007', name: 'Ultramid A4H', supplier: 'BASF', group: 'PA66', properties: {material_template: '130000000000000000000003', mineral: 0, glass_fiber: 0, carbon_fiber: 0}, numbers: []}
});
});
- it('returns a deleted material for a maintain/admin user', done => {
+ it('returns a deleted material for a dev/admin user', done => {
TestHelper.request(server, done, {
method: 'get',
url: '/material/100000000000000000000008',
diff --git a/src/routes/material.ts b/src/routes/material.ts
index 54a49ab..dfd7cbf 100644
--- a/src/routes/material.ts
+++ b/src/routes/material.ts
@@ -19,7 +19,7 @@ import ParametersValidate from './validate/parameters';
const router = express.Router();
router.get('/materials', (req, res, next) => {
- if (!req.auth(res, ['read', 'write', 'maintain', 'dev', 'admin'], 'all')) return;
+ if (!req.auth(res, ['read', 'write', 'dev', 'admin'], 'all')) return;
const {error, value: filters} = MaterialValidate.query(req.query);
if (error) return res400(error, res);
@@ -41,22 +41,25 @@ router.get('/materials', (req, res, next) => {
MaterialModel.find(conditions).populate('group_id').populate('supplier_id').lean().exec((err, data) => {
if (err) return next(err);
- res.json(_.compact(data.map(e => MaterialValidate.output(e)))); // validate all and filter null values from validation errors
+ // validate all and filter null values from validation errors
+ res.json(_.compact(data.map(e => MaterialValidate.output(e))));
});
});
router.get('/materials/:state(new|deleted)', (req, res, next) => {
- if (!req.auth(res, ['maintain', 'admin'], 'basic')) return;
+ if (!req.auth(res, ['dev', 'admin'], 'basic')) return;
- MaterialModel.find({status: globals.status[req.params.state]}).populate('group_id').populate('supplier_id').lean().exec((err, data) => {
+ MaterialModel.find({status: globals.status[req.params.state]}).populate('group_id').populate('supplier_id')
+ .lean().exec((err, data) => {
if (err) return next(err);
- res.json(_.compact(data.map(e => MaterialValidate.output(e)))); // validate all and filter null values from validation errors
+ // validate all and filter null values from validation errors
+ res.json(_.compact(data.map(e => MaterialValidate.output(e))));
});
});
router.get('/material/' + IdValidate.parameter(), (req, res, next) => {
- if (!req.auth(res, ['read', 'write', 'maintain', 'dev', 'admin'], 'all')) return;
+ if (!req.auth(res, ['read', 'write', 'dev', 'admin'], 'all')) return;
MaterialModel.findById(req.params.id).populate('group_id').populate('supplier_id').lean().exec((err, data: any) => {
if (err) return next(err);
@@ -65,13 +68,14 @@ router.get('/material/' + IdValidate.parameter(), (req, res, next) => {
return res.status(404).json({status: 'Not found'});
}
- if (data.status === globals.status.deleted && !req.auth(res, ['maintain', 'admin'], 'all')) return; // deleted materials only available for maintain/admin
+ // deleted materials only available for dev/admin
+ if (data.status === globals.status.deleted && !req.auth(res, ['dev', 'admin'], 'all')) return;
res.json(MaterialValidate.output(data));
});
});
router.put('/material/' + IdValidate.parameter(), (req, res, next) => {
- if (!req.auth(res, ['write', 'maintain', 'dev', 'admin'], 'basic')) return;
+ if (!req.auth(res, ['write', 'dev', 'admin'], 'basic')) return;
let {error, value: material} = MaterialValidate.input(req.body, 'change');
if (error) return res400(error, res);
@@ -95,7 +99,8 @@ router.put('/material/' + IdValidate.parameter(), (req, res, next) => {
if (!material) return;
}
if (material.hasOwnProperty('properties')) {
- if (!await propertiesCheck(material.properties, 'change', res, next, materialData.properties.material_template.toString() !== material.properties.material_template)) return;
+ if (!await propertiesCheck(material.properties, 'change', res, next,
+ materialData.properties.material_template.toString() !== material.properties.material_template)) return;
}
// check for changes
@@ -103,7 +108,8 @@ router.put('/material/' + IdValidate.parameter(), (req, res, next) => {
material.status = globals.status.new; // set status to new
}
- await MaterialModel.findByIdAndUpdate(req.params.id, material, {new: true}).log(req).populate('group_id').populate('supplier_id').lean().exec((err, data) => {
+ await MaterialModel.findByIdAndUpdate(req.params.id, material, {new: true})
+ .log(req).populate('group_id').populate('supplier_id').lean().exec((err, data) => {
if (err) return next(err);
res.json(MaterialValidate.output(data));
});
@@ -111,7 +117,7 @@ router.put('/material/' + IdValidate.parameter(), (req, res, next) => {
});
router.delete('/material/' + IdValidate.parameter(), (req, res, next) => {
- if (!req.auth(res, ['write', 'maintain', 'dev', 'admin'], 'basic')) return;
+ if (!req.auth(res, ['write', 'dev', 'admin'], 'basic')) return;
// check if there are still samples referencing this material
SampleModel.find({'material_id': new mongoose.Types.ObjectId(req.params.id)}).lean().exec((err, data) => {
@@ -119,7 +125,8 @@ router.delete('/material/' + IdValidate.parameter(), (req, res, next) => {
if (data.length) {
return res.status(400).json({status: 'Material still in use'});
}
- MaterialModel.findByIdAndUpdate(req.params.id, {status:globals.status.deleted}).log(req).populate('group_id').populate('supplier_id').lean().exec((err, data) => {
+ MaterialModel.findByIdAndUpdate(req.params.id, {status:globals.status.deleted})
+ .log(req).populate('group_id').populate('supplier_id').lean().exec((err, data) => {
if (err) return next(err);
if (data) {
res.json({status: 'OK'});
@@ -132,19 +139,19 @@ router.delete('/material/' + IdValidate.parameter(), (req, res, next) => {
});
router.put('/material/restore/' + IdValidate.parameter(), (req, res, next) => {
- if (!req.auth(res, ['maintain', 'admin'], 'basic')) return;
+ if (!req.auth(res, ['dev', 'admin'], 'basic')) return;
setStatus(globals.status.new, req, res, next);
});
router.put('/material/validate/' + IdValidate.parameter(), (req, res, next) => {
- if (!req.auth(res, ['maintain', 'admin'], 'basic')) return;
+ if (!req.auth(res, ['dev', 'admin'], 'basic')) return;
setStatus(globals.status.validated, req, res, next);
});
router.post('/material/new', async (req, res, next) => {
- if (!req.auth(res, ['write', 'maintain', 'dev', 'admin'], 'basic')) return;
+ if (!req.auth(res, ['write', 'dev', 'admin'], 'basic')) return;
let {error, value: material} = MaterialValidate.input(req.body, 'new');
if (error) return res400(error, res);
@@ -167,22 +174,24 @@ router.post('/material/new', async (req, res, next) => {
});
router.get('/material/groups', (req, res, next) => {
- if (!req.auth(res, ['read', 'write', 'maintain', 'dev', 'admin'], 'all')) return;
+ if (!req.auth(res, ['read', 'write', 'dev', 'admin'], 'all')) return;
MaterialGroupModel.find().lean().exec((err, data: any) => {
if (err) return next(err);
- res.json(_.compact(data.map(e => MaterialValidate.outputGroups(e.name)))); // validate all and filter null values from validation errors
+ // validate all and filter null values from validation errors
+ res.json(_.compact(data.map(e => MaterialValidate.outputGroups(e.name))));
});
});
router.get('/material/suppliers', (req, res, next) => {
- if (!req.auth(res, ['read', 'write', 'maintain', 'dev', 'admin'], 'all')) return;
+ if (!req.auth(res, ['read', 'write', 'dev', 'admin'], 'all')) return;
MaterialSupplierModel.find().lean().exec((err, data: any) => {
if (err) return next(err);
- res.json(_.compact(data.map(e => MaterialValidate.outputSuppliers(e.name)))); // validate all and filter null values from validation errors
+ // validate all and filter null values from validation errors
+ res.json(_.compact(data.map(e => MaterialValidate.outputSuppliers(e.name))));
});
});
@@ -201,7 +210,11 @@ async function nameCheck (material, res, next) { // check if name was already t
}
async function groupResolve (material, req, next) {
- const groupData = await MaterialGroupModel.findOneAndUpdate({name: material.group}, {name: material.group}, {upsert: true, new: true}).log(req).lean().exec().catch(err => next(err)) as any;
+ const groupData = await MaterialGroupModel.findOneAndUpdate(
+ {name: material.group},
+ {name: material.group},
+ {upsert: true, new: true}
+ ).log(req).lean().exec().catch(err => next(err)) as any;
if (groupData instanceof Error) return false;
material.group_id = groupData._id;
delete material.group;
@@ -209,19 +222,25 @@ async function groupResolve (material, req, next) {
}
async function supplierResolve (material, req, next) {
- const supplierData = await MaterialSupplierModel.findOneAndUpdate({name: material.supplier}, {name: material.supplier}, {upsert: true, new: true}).log(req).lean().exec().catch(err => next(err)) as any;
+ const supplierData = await MaterialSupplierModel.findOneAndUpdate(
+ {name: material.supplier},
+ {name: material.supplier},
+ {upsert: true, new: true}
+ ).log(req).lean().exec().catch(err => next(err)) as any;
if (supplierData instanceof Error) return false;
material.supplier_id = supplierData._id;
delete material.supplier;
return material;
}
-async function propertiesCheck (properties, param, res, next, checkVersion = true) { // validate material properties, returns false if invalid, otherwise template data
+// validate material properties, returns false if invalid, otherwise template data
+async function propertiesCheck (properties, param, res, next, checkVersion = true) {
if (!properties.material_template || !IdValidate.valid(properties.material_template)) { // template id not found
res.status(400).json({status: 'Material template not available'});
return false;
}
- const materialData = await MaterialTemplateModel.findById(properties.material_template).lean().exec().catch(err => next(err)) as any;
+ const materialData = await MaterialTemplateModel.findById(properties.material_template)
+ .lean().exec().catch(err => next(err)) as any;
if (materialData instanceof Error) return false;
if (!materialData) { // template not found
res.status(400).json({status: 'Material template not available'});
@@ -230,7 +249,8 @@ async function propertiesCheck (properties, param, res, next, checkVersion = tru
if (checkVersion) {
// get all template versions and check if given is latest
- const materialVersions = await MaterialTemplateModel.find({first_id: materialData.first_id}).sort({version: -1}).lean().exec().catch(err => next(err)) as any;
+ const materialVersions = await MaterialTemplateModel.find({first_id: materialData.first_id}).sort({version: -1})
+ .lean().exec().catch(err => next(err)) as any;
if (materialVersions instanceof Error) return false;
if (properties.material_template !== materialVersions[0]._id.toString()) { // template not latest
res.status(400).json({status: 'Old template version not allowed'});
@@ -239,7 +259,8 @@ async function propertiesCheck (properties, param, res, next, checkVersion = tru
}
// validate parameters
- const {error, value} = ParametersValidate.input(_.omit(properties, 'material_template'), materialData.parameters, param);
+ const {error, value} = ParametersValidate
+ .input(_.omit(properties, 'material_template'), materialData.parameters, param);
if (error) {res400(error, res); return false;}
Object.keys(value).forEach(key => {
properties[key] = value[key];
diff --git a/src/routes/measurement.spec.ts b/src/routes/measurement.spec.ts
index 180f3ce..cf01acb 100644
--- a/src/routes/measurement.spec.ts
+++ b/src/routes/measurement.spec.ts
@@ -16,7 +16,7 @@ describe('/measurement', () => {
TestHelper.request(server, done, {
method: 'get',
url: '/measurement/800000000000000000000001',
- auth: {basic: 'janedoe'},
+ auth: {basic: 'admin'},
httpStatus: 200,
res: {_id: '800000000000000000000001', sample_id: '400000000000000000000001', values: {dpt: [[3997.12558,98.00555],[3995.08519,98.03253],[3993.04480,98.02657]], device: 'Alpha I'}, measurement_template: '300000000000000000000001'}
});
@@ -25,12 +25,21 @@ describe('/measurement', () => {
TestHelper.request(server, done, {
method: 'get',
url: '/measurement/800000000000000000000001',
- auth: {key: 'janedoe'},
+ auth: {key: 'admin'},
httpStatus: 200,
res: {_id: '800000000000000000000001', sample_id: '400000000000000000000001', values: {dpt: [[3997.12558,98.00555],[3995.08519,98.03253],[3993.04480,98.02657]], device: 'Alpha I'}, measurement_template: '300000000000000000000001'}
});
});
- it('returns deleted measurements for a maintain/admin user', done => {
+ it('filters out spectral data for a write user', done => {
+ TestHelper.request(server, done, {
+ method: 'get',
+ url: '/measurement/800000000000000000000001',
+ auth: {basic: 'janedoe'},
+ httpStatus: 200,
+ res: {_id: '800000000000000000000001', sample_id: '400000000000000000000001', values: {device: 'Alpha I'}, measurement_template: '300000000000000000000001'}
+ });
+ });
+ it('returns deleted measurements for a dev/admin user', done => {
TestHelper.request(server, done, {
method: 'get',
url: '/measurement/800000000000000000000004',
@@ -77,7 +86,7 @@ describe('/measurement', () => {
TestHelper.request(server, done, {
method: 'put',
url: '/measurement/800000000000000000000001',
- auth: {basic: 'janedoe'},
+ auth: {basic: 'admin'},
httpStatus: 200,
req: {},
res: {_id: '800000000000000000000001', sample_id: '400000000000000000000001', values: {dpt: [[3997.12558,98.00555],[3995.08519,98.03253],[3993.04480,98.02657]], device: 'Alpha I'}, measurement_template: '300000000000000000000001'}
@@ -87,7 +96,7 @@ describe('/measurement', () => {
TestHelper.request(server, done, {
method: 'put',
url: '/measurement/800000000000000000000001',
- auth: {basic: 'janedoe'},
+ auth: {basic: 'admin'},
httpStatus: 200,
req: {values: {dpt: [[3997.12558,98.00555],[3995.08519,98.03253],[3993.04480,98.02657]], device: 'Alpha I'}}
}).end((err, res) => {
@@ -121,7 +130,7 @@ describe('/measurement', () => {
TestHelper.request(server, done, {
method: 'put',
url: '/measurement/800000000000000000000001',
- auth: {basic: 'janedoe'},
+ auth: {basic: 'admin'},
httpStatus: 200,
req: {values: {dpt: [[1,2],[3,4],[5,6]]}}
}).end((err, res) => {
@@ -244,7 +253,7 @@ describe('/measurement', () => {
req: {values: {val1: 2}}
});
});
- it('accepts editing a measurement of another user for a maintain/admin user', done => {
+ it('accepts editing a measurement of another user for a dev/admin user', done => {
TestHelper.request(server, done, {
method: 'put',
url: '/measurement/800000000000000000000002',
@@ -362,7 +371,7 @@ describe('/measurement', () => {
httpStatus: 403,
});
});
- it('accepts deleting a measurement of another user for a maintain/admin user', done => {
+ it('accepts deleting a measurement of another user for a dev/admin user', done => {
TestHelper.request(server, done, {
method: 'delete',
url: '/measurement/800000000000000000000001',
@@ -731,7 +740,7 @@ describe('/measurement', () => {
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 dev/admin user', done => {
TestHelper.request(server, done, {
method: 'post',
url: '/measurement/new',
diff --git a/src/routes/measurement.ts b/src/routes/measurement.ts
index 47af305..5078379 100644
--- a/src/routes/measurement.ts
+++ b/src/routes/measurement.ts
@@ -15,21 +15,22 @@ import db from '../db';
const router = express.Router();
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', 'dev', 'admin'], 'all')) return;
MeasurementModel.findById(req.params.id).lean().exec((err, data: any) => {
if (err) return next(err);
if (!data) {
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
+ // deleted measurements only available for dev/admin
+ if (data.status === globals.status.deleted && !req.auth(res, ['dev', 'admin'], 'all')) return;
- res.json(MeasurementValidate.output(data));
+ res.json(MeasurementValidate.output(data, req));
});
});
router.put('/measurement/' + IdValidate.parameter(), async (req, res, next) => {
- if (!req.auth(res, ['write', 'maintain', 'dev', 'admin'], 'basic')) return;
+ if (!req.auth(res, ['write', 'dev', 'admin'], 'basic')) return;
const {error, value: measurement} = MeasurementValidate.input(req.body, 'change');
if (error) return res400(error, res);
@@ -57,14 +58,15 @@ router.put('/measurement/' + IdValidate.parameter(), async (req, res, next) => {
}
if (!await templateCheck(measurement, 'change', res, next)) return;
- await MeasurementModel.findByIdAndUpdate(req.params.id, measurement, {new: true}).log(req).lean().exec((err, data) => {
+ await MeasurementModel.findByIdAndUpdate(req.params.id, measurement, {new: true})
+ .log(req).lean().exec((err, data) => {
if (err) return next(err);
- res.json(MeasurementValidate.output(data));
+ res.json(MeasurementValidate.output(data, req));
});
});
router.delete('/measurement/' + IdValidate.parameter(), (req, res, next) => {
- if (!req.auth(res, ['write', 'maintain', 'dev', 'admin'], 'basic')) return;
+ if (!req.auth(res, ['write', 'dev', 'admin'], 'basic')) return;
MeasurementModel.findById(req.params.id).lean().exec(async (err, data) => {
if (err) return next(err);
@@ -72,7 +74,8 @@ router.delete('/measurement/' + IdValidate.parameter(), (req, res, next) => {
return res.status(404).json({status: 'Not found'});
}
if (!await sampleIdCheck(data, req, res, next)) return;
- await MeasurementModel.findByIdAndUpdate(req.params.id, {status:globals.status.deleted}).log(req).lean().exec(err => {
+ await MeasurementModel.findByIdAndUpdate(req.params.id, {status:globals.status.deleted})
+ .log(req).lean().exec(err => {
if (err) return next(err);
return res.json({status: 'OK'});
});
@@ -80,19 +83,19 @@ router.delete('/measurement/' + IdValidate.parameter(), (req, res, next) => {
});
router.put('/measurement/restore/' + IdValidate.parameter(), (req, res, next) => {
- if (!req.auth(res, ['maintain', 'admin'], 'basic')) return;
+ if (!req.auth(res, ['dev', 'admin'], 'basic')) return;
setStatus(globals.status.new, req, res, next);
});
router.put('/measurement/validate/' + IdValidate.parameter(), (req, res, next) => {
- if (!req.auth(res, ['maintain', 'admin'], 'basic')) return;
+ if (!req.auth(res, ['dev', 'admin'], 'basic')) return;
setStatus(globals.status.validated, req, res, next);
});
router.post('/measurement/new', async (req, res, next) => {
- if (!req.auth(res, ['write', 'maintain', 'dev', 'admin'], 'basic')) return;
+ if (!req.auth(res, ['write', 'dev', 'admin'], 'basic')) return;
const {error, value: measurement} = MeasurementValidate.input(req.body, 'new');
if (error) return res400(error, res);
@@ -105,7 +108,7 @@ router.post('/measurement/new', async (req, res, next) => {
await new MeasurementModel(measurement).save((err, data) => {
if (err) return next(err);
db.log(req, 'measurements', {_id: data._id}, data.toObject());
- res.json(MeasurementValidate.output(data.toObject()));
+ res.json(MeasurementValidate.output(data.toObject(), req));
});
});
@@ -113,18 +116,23 @@ router.post('/measurement/new', async (req, res, next) => {
module.exports = router;
-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 SampleModel.findById(measurement.sample_id).lean().exec().catch(err => {next(err); return false;}) as any;
+// validate sample_id, returns false if invalid or user has no access for this sample
+async function sampleIdCheck (measurement, req, res, next) {
+ const sampleData = await SampleModel.findById(measurement.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;
+ // sample does not belong to user
+ return !(sampleData.user_id.toString() !== req.authDetails.id && !req.auth(res, ['dev', 'admin'], 'basic'));
}
-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;
+// validate measurement_template and values, returns values, true if values are {} or false if invalid,
+// param for 'new'/'change'
+async function templateCheck (measurement, param, res, next) {
+ const templateData = await MeasurementTemplateModel.findById(measurement.measurement_template)
+ .lean().exec().catch(err => {next(err); return false;}) as any;
if (!templateData) { // template not found
res.status(400).json({status: 'Measurement template not available'});
return false
@@ -133,7 +141,8 @@ async function templateCheck (measurement, param, res, next) { // validate meas
// fill not given values for new measurements
if (param === 'new') {
// get all template versions and check if given is latest
- const templateVersions = await MeasurementTemplateModel.find({first_id: templateData.first_id}).sort({version: -1}).lean().exec().catch(err => next(err)) as any;
+ const templateVersions = await MeasurementTemplateModel.find({first_id: templateData.first_id}).sort({version: -1})
+ .lean().exec().catch(err => next(err)) as any;
if (templateVersions instanceof Error) return false;
if (measurement.measurement_template !== templateVersions[0]._id.toString()) { // template not latest
res.status(400).json({status: 'Old template version not allowed'});
diff --git a/src/routes/root.ts b/src/routes/root.ts
index 348d660..bc0fc98 100644
--- a/src/routes/root.ts
+++ b/src/routes/root.ts
@@ -24,7 +24,7 @@ router.get('/authorized', (req, res) => {
// TODO: evaluate exact changelog functionality (restoring, deleting after time, etc.)
router.get('/changelog/:timestamp/:page?/:pagesize?', (req, res, next) => {
- if (!req.auth(res, ['maintain', 'admin'], 'basic')) return;
+ if (!req.auth(res, ['dev', 'admin'], 'basic')) return;
const {error, value: options} = RootValidate.changelogParams({
timestamp: req.params.timestamp,
diff --git a/src/routes/sample.spec.ts b/src/routes/sample.spec.ts
index c49e462..a7cd2d5 100644
--- a/src/routes/sample.spec.ts
+++ b/src/routes/sample.spec.ts
@@ -262,7 +262,7 @@ describe('/sample', () => {
TestHelper.request(server, done, {
method: 'get',
url: '/samples?status=all&fields[]=number&fields[]=measurements.spectrum.dpt',
- auth: {basic: 'janedoe'},
+ auth: {basic: 'admin'},
httpStatus: 200
}).end((err, res) => {
if (err) return done(err);
@@ -379,6 +379,14 @@ describe('/sample', () => {
done();
});
});
+ it('rejects returning spectral data for a write user', done => {
+ TestHelper.request(server, done, {
+ method: 'get',
+ url: '/samples?status=all&fields[]=number&fields[]=measurements.spectrum.dpt',
+ auth: {basic: 'janedoe'},
+ httpStatus: 403
+ });
+ });
it('rejects an invalid JSON string as a filters parameter', done => {
TestHelper.request(server, done, {
method: 'get',
@@ -681,7 +689,25 @@ describe('/sample', () => {
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', properties: {material_template: '130000000000000000000003', mineral: 0, glass_fiber: 33, carbon_fiber: 0}, numbers: ['5514262406']}, notes: {comment: '', sample_references: [{sample_id: '400000000000000000000004', relation: 'granulate to sample'}], custom_fields: {'not allowed for new applications': true}}, measurements: [{_id: '800000000000000000000003', sample_id: '400000000000000000000003', values: {val1: 1}, measurement_template: '300000000000000000000003'}], user: 'admin'}
});
});
- it('returns a deleted sample for a maintain/admin user', done => {
+ it ('filters out spectral data for a write user', done => {
+ TestHelper.request(server, done, {
+ method: 'get',
+ url: '/sample/400000000000000000000001',
+ auth: {basic: 'janedoe'},
+ httpStatus: 200,
+ res: {_id: '400000000000000000000001', number: '1', type: 'granulate', color: 'black', batch: '', condition: {material: 'copper', weeks: 3, condition_template: '200000000000000000000001'}, material: {numbers: ['5513933405'], _id: '100000000000000000000004', name: 'Schulamid 66 GF 25 H', properties: {material_template: '130000000000000000000003', mineral: 0, glass_fiber: 25, carbon_fiber: 0}, group: 'PA66', supplier: 'Schulmann'}, user: 'janedoe', notes: {}, measurements: [{_id: '800000000000000000000001', sample_id: '400000000000000000000001', values: {device: 'Alpha I'}, measurement_template: '300000000000000000000001'}, {_id: '800000000000000000000007', sample_id: '400000000000000000000001', values: {device: 'Alpha II'}, measurement_template: '300000000000000000000001'}]}
+ });
+ });
+ it ('returns spectral data for an admin user', done => {
+ TestHelper.request(server, done, {
+ method: 'get',
+ url: '/sample/400000000000000000000001',
+ auth: {basic: 'admin'},
+ httpStatus: 200,
+ res: {_id: '400000000000000000000001', number: '1', type: 'granulate', color: 'black', batch: '', condition: {material: 'copper', weeks: 3, condition_template: '200000000000000000000001'}, material: {numbers: ['5513933405'], _id: '100000000000000000000004', name: 'Schulamid 66 GF 25 H', properties: {material_template: '130000000000000000000003', mineral: 0, glass_fiber: 25, carbon_fiber: 0}, group: 'PA66', supplier: 'Schulmann'}, user: 'janedoe', notes: {}, measurements: [{_id: '800000000000000000000001', sample_id: '400000000000000000000001', values: {dpt: [[ 3997.12558, 98.00555 ], [ 3995.08519, 98.03253 ], [ 3993.0448, 98.02657 ]],device: 'Alpha I'}, measurement_template: '300000000000000000000001'}, {_id: '800000000000000000000007', sample_id: '400000000000000000000001', values: {dpt: [[ 3996.12558, 98.00555 ], [ 3995.08519, 98.03253 ], [ 3993.0448, 98.02657 ]], device: 'Alpha II'}, measurement_template: '300000000000000000000001'}]}
+ });
+ });
+ it('returns a deleted sample for a dev/admin user', done => {
TestHelper.request(server, done, {
method: 'get',
url: '/sample/400000000000000000000005',
@@ -830,7 +856,7 @@ describe('/sample', () => {
url: '/sample/400000000000000000000001',
auth: {basic: 'janedoe'},
httpStatus: 200,
- req: {type: 'other', color: 'signalviolet', batch: '114531', condition: {condition_template: '200000000000000000000003'}, material_id: '100000000000000000000002', notes: {comment: 'Testcomment', sample_references: [{sample_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 => {
if (err) return done (err);
SampleModel.findById('400000000000000000000001').lean().exec((err, data: any) => {
@@ -839,7 +865,7 @@ describe('/sample', () => {
should(data).have.property('_id');
should(data).have.property('number', '1');
should(data).have.property('color', 'signalviolet');
- should(data).have.property('type', 'other');
+ should(data).have.property('type', 'part');
should(data).have.property('batch', '114531');
should(data).have.property('condition', {condition_template: '200000000000000000000003'});
should(data.material_id.toString()).be.eql('100000000000000000000002');
@@ -1061,7 +1087,7 @@ describe('/sample', () => {
auth: {basic: 'janedoe'},
httpStatus: 400,
req: {type: 'xx'},
- res: {status: 'Invalid body format', details: '"type" must be one of [granulate, part, tension rod, other]'}
+ res: {status: 'Invalid body format', details: '"type" must be one of [granulate, part, tension rod]'}
});
});
it('allows keeping an empty condition empty', done => {
@@ -1131,7 +1157,7 @@ describe('/sample', () => {
req: {}
});
});
- it('accepts changes for samples from another user for a maintain/admin user', done => {
+ it('accepts changes for samples from another user for a dev/admin user', done => {
TestHelper.request(server, done, {
method: 'put',
url: '/sample/400000000000000000000001',
@@ -1270,7 +1296,7 @@ describe('/sample', () => {
});
});
- it('lets admin/maintain users delete samples of other users', done => {
+ it('lets admin/dev users delete samples of other users', done => {
TestHelper.request(server, done, {
method: 'delete',
url: '/sample/400000000000000000000001',
@@ -1372,7 +1398,7 @@ describe('/sample', () => {
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', properties: {material_template: '130000000000000000000003', mineral: 0, glass_fiber: 33, carbon_fiber: 0}, numbers: ['5514262406']}, notes: {comment: '', sample_references: [{sample_id: '400000000000000000000004', relation: 'granulate to sample'}], custom_fields: {'not allowed for new applications': true}}, measurements: [{_id: '800000000000000000000003', sample_id: '400000000000000000000003', values: {val1: 1}, measurement_template: '300000000000000000000003'}], user: 'admin'}
});
});
- it('returns a deleted sample for a maintain/admin user', done => {
+ it('returns a deleted sample for a dev/admin user', done => {
TestHelper.request(server, done, {
method: 'get',
url: '/sample/number/Rng33',
@@ -1381,6 +1407,24 @@ describe('/sample', () => {
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', properties: {material_template: '130000000000000000000003', mineral: 0, glass_fiber: 33, carbon_fiber: 0}, numbers: ['5514262406']}, notes: {}, measurements: [], user: 'admin'}
});
});
+ it ('filters out spectral data for a write user', done => {
+ TestHelper.request(server, done, {
+ method: 'get',
+ url: '/sample/number/1',
+ auth: {basic: 'janedoe'},
+ httpStatus: 200,
+ res: {_id: '400000000000000000000001', number: '1', type: 'granulate', color: 'black', batch: '', condition: {material: 'copper', weeks: 3, condition_template: '200000000000000000000001'}, material: {numbers: ['5513933405'], _id: '100000000000000000000004', name: 'Schulamid 66 GF 25 H', properties: {material_template: '130000000000000000000003', mineral: 0, glass_fiber: 25, carbon_fiber: 0}, group: 'PA66', supplier: 'Schulmann'}, user: 'janedoe', notes: {}, measurements: [{_id: '800000000000000000000001', sample_id: '400000000000000000000001', values: {device: 'Alpha I'}, measurement_template: '300000000000000000000001'}, {_id: '800000000000000000000007', sample_id: '400000000000000000000001', values: {device: 'Alpha II'}, measurement_template: '300000000000000000000001'}]}
+ });
+ });
+ it ('returns spectral data for an admin user', done => {
+ TestHelper.request(server, done, {
+ method: 'get',
+ url: '/sample/number/1',
+ auth: {basic: 'admin'},
+ httpStatus: 200,
+ res: {_id: '400000000000000000000001', number: '1', type: 'granulate', color: 'black', batch: '', condition: {material: 'copper', weeks: 3, condition_template: '200000000000000000000001'}, material: {numbers: ['5513933405'], _id: '100000000000000000000004', name: 'Schulamid 66 GF 25 H', properties: {material_template: '130000000000000000000003', mineral: 0, glass_fiber: 25, carbon_fiber: 0}, group: 'PA66', supplier: 'Schulmann'}, user: 'janedoe', notes: {}, measurements: [{_id: '800000000000000000000001', sample_id: '400000000000000000000001', values: {dpt: [[ 3997.12558, 98.00555 ], [ 3995.08519, 98.03253 ], [ 3993.0448, 98.02657 ]],device: 'Alpha I'}, measurement_template: '300000000000000000000001'}, {_id: '800000000000000000000007', sample_id: '400000000000000000000001', values: {dpt: [[ 3996.12558, 98.00555 ], [ 3995.08519, 98.03253 ], [ 3993.0448, 98.02657 ]], device: 'Alpha II'}, measurement_template: '300000000000000000000001'}]}
+ });
+ });
it('returns 403 for a write user when requesting a deleted sample', done => {
TestHelper.request(server, done, {
method: 'get',
@@ -1523,24 +1567,38 @@ describe('/sample', () => {
}
});
});
- it('rejects validating a sample without condition', done => {
+ it('allows validating a sample without condition', done => {
TestHelper.request(server, done, {
method: 'put',
url: '/sample/validate/400000000000000000000006',
auth: {basic: 'admin'},
- httpStatus: 400,
- req: {},
- res: {status: 'Sample without condition cannot be valid'}
+ httpStatus: 200,
+ req: {}
+ }).end((err, res) => {
+ if (err) return done (err);
+ should(res.body).be.eql({status: 'OK'});
+ SampleModel.findById('400000000000000000000006').lean().exec((err, data: any) => {
+ if (err) return done(err);
+ should(data).have.property('status',globals.status.validated);
+ done();
+ });
});
});
- it('rejects validating a sample without measurements', done => {
+ it('allows validating a sample without measurements', done => {
TestHelper.request(server, done, {
method: 'put',
url: '/sample/validate/400000000000000000000004',
auth: {basic: 'admin'},
- httpStatus: 400,
- req: {},
- res: {status: 'Sample without measurements cannot be valid'}
+ httpStatus: 200,
+ req: {}
+ }).end((err, res) => {
+ if (err) return done (err);
+ should(res.body).be.eql({status: 'OK'});
+ SampleModel.findById('400000000000000000000004').lean().exec((err, data: any) => {
+ if (err) return done(err);
+ should(data).have.property('status',globals.status.validated);
+ done();
+ });
});
});
it('rejects an API key', done => {
@@ -1954,7 +2012,7 @@ describe('/sample', () => {
auth: {basic: 'janedoe'},
httpStatus: 400,
req: {color: 'black', type: 'xx', batch: '1560237365', material_id: '100000000000000000000001', notes: {comment: 'Testcomment'}},
- res: {status: 'Invalid body format', details: '"type" must be one of [granulate, part, tension rod, other]'}
+ res: {status: 'Invalid body format', details: '"type" must be one of [granulate, part, tension rod]'}
});
});
it('rejects an API key', done => {
diff --git a/src/routes/sample.ts b/src/routes/sample.ts
index 47e3aa5..9b93aaa 100644
--- a/src/routes/sample.ts
+++ b/src/routes/sample.ts
@@ -30,11 +30,14 @@ const router = express.Router();
router.get('/samples', async (req, res, next) => {
- if (!req.auth(res, ['read', 'write', 'maintain', 'dev', 'admin'], 'all')) return;
+ if (!req.auth(res, ['read', 'write', 'dev', 'admin'], 'all')) return;
const {error, value: filters} = SampleValidate.query(req.query);
if (error) return res400(error, res);
+ // spectral data not allowed for read/write users
+ if (filters.fields.find(e => /\.dpt$/.test(e)) && !req.auth(res, ['dev', 'admin'], 'all')) return;
+
// TODO: find a better place for these
const sampleKeys = ['_id', 'color', 'number', 'type', 'batch', 'added', 'condition', 'material_id', 'note_id',
'user_id'];
@@ -426,7 +429,7 @@ router.get('/samples', async (req, res, next) => {
});
router.get('/samples/:state(new|deleted)', (req, res, next) => {
- if (!req.auth(res, ['maintain', 'admin'], 'basic')) return;
+ if (!req.auth(res, ['dev', 'admin'], 'basic')) return;
SampleModel.find({status: globals.status[req.params.state]}).lean().exec((err, data) => {
if (err) return next(err);
@@ -436,7 +439,7 @@ router.get('/samples/:state(new|deleted)', (req, res, next) => {
});
router.get('/samples/count', (req, res, next) => {
- if (!req.auth(res, ['read', 'write', 'maintain', 'dev', 'admin'], 'all')) return;
+ if (!req.auth(res, ['read', 'write', 'dev', 'admin'], 'all')) return;
SampleModel.estimatedDocumentCount((err, data) => {
if (err) return next(err);
@@ -445,19 +448,20 @@ router.get('/samples/count', (req, res, next) => {
});
router.get('/sample/' + IdValidate.parameter(), (req, res, next) => {
- if (!req.auth(res, ['read', 'write', 'maintain', 'dev', 'admin'], 'all')) return;
+ if (!req.auth(res, ['read', 'write', 'dev', 'admin'], 'all')) return;
SampleModel.findById(req.params.id).populate('material_id').populate('user_id', 'name').populate('note_id')
.exec(async (err, sampleData: any) => {
- if (err) return next(err);
+ if (err) return next(err);
await sampleReturn(sampleData, req, res, next);
});
});
router.put('/sample/' + IdValidate.parameter(), (req, res, next) => {
- if (!req.auth(res, ['write', 'maintain', 'dev', 'admin'], 'basic')) return;
+ if (!req.auth(res, ['write', 'dev', 'admin'], 'basic')) return;
const {error, value: sample} = SampleValidate.input(req.body, 'change');
+ console.log(error);
if (error) return res400(error, res);
SampleModel.findById(req.params.id).lean().exec(async (err, sampleData: any) => { // check if id exists
@@ -469,8 +473,8 @@ router.put('/sample/' + IdValidate.parameter(), (req, res, next) => {
return res.status(403).json({status: 'Forbidden'});
}
- // 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;
+ // only dev and admin are allowed to edit other user's data
+ if (sampleData.user_id.toString() !== req.authDetails.id && !req.auth(res, ['dev', 'admin'], 'basic')) return;
if (sample.hasOwnProperty('material_id')) {
if (!await materialCheck(sample, res, next)) return;
}
@@ -528,7 +532,7 @@ router.put('/sample/' + IdValidate.parameter(), (req, res, next) => {
});
router.delete('/sample/' + IdValidate.parameter(), (req, res, next) => {
- if (!req.auth(res, ['write', 'maintain', 'dev', 'admin'], 'basic')) return;
+ if (!req.auth(res, ['write', 'dev', 'admin'], 'basic')) return;
SampleModel.findById(req.params.id).lean().exec(async (err, sampleData: any) => { // check if id exists
if (err) return next(err);
@@ -536,8 +540,8 @@ router.delete('/sample/' + IdValidate.parameter(), (req, res, next) => {
return res.status(404).json({status: 'Not found'});
}
- // 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;
+ // only dev and admin are allowed to edit other user's data
+ if (sampleData.user_id.toString() !== req.authDetails.id && !req.auth(res, ['dev', 'admin'], 'basic')) return;
// set sample status
await SampleModel.findByIdAndUpdate(req.params.id, {status:globals.status.deleted}).log(req).lean().exec(err => {
@@ -566,7 +570,7 @@ router.delete('/sample/' + IdValidate.parameter(), (req, res, next) => {
});
router.get('/sample/number/:number', (req, res, next) => {
- if (!req.auth(res, ['read', 'write', 'maintain', 'dev', 'admin'], 'all')) return;
+ if (!req.auth(res, ['read', 'write', 'dev', 'admin'], 'all')) return;
SampleModel.findOne({number: req.params.number}).populate('material_id').populate('user_id', 'name')
.populate('note_id').exec(async (err, sampleData: any) => {
@@ -576,7 +580,7 @@ router.get('/sample/number/:number', (req, res, next) => {
});
router.put('/sample/restore/' + IdValidate.parameter(), (req, res, next) => {
- if (!req.auth(res, ['maintain', 'admin'], 'basic')) return;
+ if (!req.auth(res, ['dev', 'admin'], 'basic')) return;
SampleModel.findByIdAndUpdate(req.params.id, {status: globals.status.new}).log(req).lean().exec((err, data) => {
if (err) return next(err);
@@ -589,35 +593,20 @@ router.put('/sample/restore/' + IdValidate.parameter(), (req, res, next) => {
});
router.put('/sample/validate/' + IdValidate.parameter(), (req, res, next) => {
- if (!req.auth(res, ['maintain', 'admin'], 'basic')) return;
+ if (!req.auth(res, ['dev', 'admin'], 'basic')) return;
- SampleModel.findById(req.params.id).lean().exec((err, data: any) => {
+ SampleModel.findByIdAndUpdate(req.params.id, {status: globals.status.validated}).log(req).lean().exec((err, data) => {
if (err) return next(err);
-
if (!data) {
return res.status(404).json({status: 'Not found'});
}
- if (Object.keys(data.condition).length === 0) {
- return res.status(400).json({status: 'Sample without condition cannot be valid'});
- }
- MeasurementModel.find({sample_id: mongoose.Types.ObjectId(req.params.id)}).lean().exec((err, data) => {
- if (err) return next(err);
-
- if (data.length === 0) {
- return res.status(400).json({status: 'Sample without measurements cannot be valid'});
- }
-
- SampleModel.findByIdAndUpdate(req.params.id, {status: globals.status.validated}).log(req).lean().exec(err => {
- if (err) return next(err);
- res.json({status: 'OK'});
- });
- });
+ res.json({status: 'OK'});
});
});
router.post('/sample/new', async (req, res, next) => {
- if (!req.auth(res, ['write', 'maintain', 'dev', 'admin'], 'basic')) return;
+ if (!req.auth(res, ['write', 'dev', 'admin'], 'basic')) return;
if (!req.body.hasOwnProperty('condition')) { // add empty condition if not specified
req.body.condition = {};
@@ -664,7 +653,7 @@ router.post('/sample/new', async (req, res, next) => {
});
router.get('/sample/notes/fields', (req, res, next) => {
- if (!req.auth(res, ['read', 'write', 'maintain', 'dev', 'admin'], 'all')) return;
+ if (!req.auth(res, ['read', 'write', 'dev', 'admin'], 'all')) return;
NoteFieldModel.find({}).lean().exec((err, data) => {
if (err) return next(err);
@@ -898,8 +887,8 @@ async function sampleReturn (sampleData, req, res, next) {
if (sampleData instanceof Error) return;
sampleData = sampleData.toObject();
- // deleted samples only available for maintain/admin
- if (sampleData.status === globals.status.deleted && !req.auth(res, ['maintain', 'admin'], 'all')) return;
+ // deleted samples only available for dev/admin
+ if (sampleData.status === globals.status.deleted && !req.auth(res, ['dev', 'admin'], 'all')) return;
sampleData.material = sampleData.material_id; // map data to right keys
sampleData.material.group = sampleData.material.group_id.name;
sampleData.material.supplier = sampleData.material.supplier_id.name;
@@ -908,6 +897,13 @@ async function sampleReturn (sampleData, req, res, next) {
MeasurementModel.find({sample_id: sampleData._id, status: {$ne: globals.status.deleted}})
.lean().exec((err, data) => {
sampleData.measurements = data;
+ if (['dev', 'admin'].indexOf(req.authDetails.level) < 0) { // strip dpt values if not dev or admin
+ sampleData.measurements.forEach(measurement => {
+ if (measurement.values.dpt) {
+ delete measurement.values.dpt;
+ }
+ });
+ }
res.json(SampleValidate.output(sampleData, 'details'));
});
}
diff --git a/src/routes/template.ts b/src/routes/template.ts
index 5641d1b..ad73a8c 100644
--- a/src/routes/template.ts
+++ b/src/routes/template.ts
@@ -15,17 +15,18 @@ import db from '../db';
const router = express.Router();
router.get('/template/:collection(measurements|conditions|materials)', (req, res, next) => {
- if (!req.auth(res, ['read', 'write', 'maintain', 'dev', 'admin'], 'basic')) return;
+ if (!req.auth(res, ['read', 'write', 'dev', 'admin'], 'basic')) return;
req.params.collection = req.params.collection.replace(/s$/g, ''); // remove trailing s
model(req).find({}).lean().exec((err, data) => {
if (err) next (err);
- res.json(_.compact(data.map(e => TemplateValidate.output(e)))); // validate all and filter null values from validation errors
+ // validate all and filter null values from validation errors
+ res.json(_.compact(data.map(e => TemplateValidate.output(e))));
});
});
router.get('/template/:collection(measurement|condition|material)/' + IdValidate.parameter(), (req, res, next) => {
- if (!req.auth(res, ['read', 'write', 'maintain', 'dev', 'admin'], 'basic')) return;
+ if (!req.auth(res, ['read', 'write', 'dev', 'admin'], 'basic')) return;
model(req).findById(req.params.id).lean().exec((err, data) => {
if (err) next (err);
@@ -38,8 +39,9 @@ router.get('/template/:collection(measurement|condition|material)/' + IdValidate
});
});
-router.put('/template/:collection(measurement|condition|material)/' + IdValidate.parameter(), async (req, res, next) => {
- if (!req.auth(res, ['maintain', 'admin'], 'basic')) return;
+router.put('/template/:collection(measurement|condition|material)/' + IdValidate.parameter(),
+ async (req, res, next) => {
+ if (!req.auth(res, ['dev', 'admin'], 'basic')) return;
const {error, value: template} = TemplateValidate.input(req.body, 'change');
if (error) return res400(error, res);
@@ -51,7 +53,8 @@ router.put('/template/:collection(measurement|condition|material)/' + IdValidate
return res.status(404).json({status: 'Not found'});
}
// find latest version
- const templateData = await model(req).findOne({first_id: templateRef.first_id}).sort({version: -1}).lean().exec().catch(err => {next(err);}) as any;
+ const templateData = await model(req).findOne({first_id: templateRef.first_id}).sort({version: -1})
+ .lean().exec().catch(err => {next(err);}) as any;
if (templateData instanceof Error) return;
if (!templateData) {
return res.status(404).json({status: 'Not found'});
@@ -59,7 +62,8 @@ router.put('/template/:collection(measurement|condition|material)/' + IdValidate
if (!_.isEqual(_.pick(templateData, _.keys(template)), template)) { // data was changed
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
+ // save new template, fill with old properties
+ await new (model(req))(_.assign({}, _.omit(templateData, ['_id', '__v']), template)).save((err, data) => {
if (err) next (err);
db.log(req, req.params.collection + '_templates', {_id: data._id}, data.toObject());
res.json(TemplateValidate.output(data.toObject()));
@@ -71,7 +75,7 @@ router.put('/template/:collection(measurement|condition|material)/' + IdValidate
});
router.post('/template/:collection(measurement|condition|material)/new', async (req, res, next) => {
- if (!req.auth(res, ['maintain', 'admin'], 'basic')) return;
+ if (!req.auth(res, ['dev', 'admin'], 'basic')) return;
const {error, value: template} = TemplateValidate.input(req.body, 'new');
if (error) return res400(error, res);
diff --git a/src/routes/user.spec.ts b/src/routes/user.spec.ts
index a39bc50..cbeda33 100644
--- a/src/routes/user.spec.ts
+++ b/src/routes/user.spec.ts
@@ -564,7 +564,7 @@ describe('/user', () => {
auth: {basic: 'admin'},
httpStatus: 400,
req: {email: 'john.doe@bosch.com', name: 'johndoe', pass: 'Abc123!#', level: 'xxx', location: 'Rng', device_name: 'Alpha II'},
- res: {status: 'Invalid body format', details: '"level" must be one of [read, write, maintain, dev, admin]'}
+ res: {status: 'Invalid body format', details: '"level" must be one of [read, write, dev, admin]'}
});
});
it('rejects an invalid email address', done => {
diff --git a/src/routes/user.ts b/src/routes/user.ts
index 2393150..7b43449 100644
--- a/src/routes/user.ts
+++ b/src/routes/user.ts
@@ -16,12 +16,15 @@ router.get('/users', (req, res) => {
if (!req.auth(res, ['admin'], 'basic')) return;
UserModel.find({}).lean().exec( (err, data:any) => {
- res.json(_.compact(data.map(e => UserValidate.output(e)))); // validate all and filter null values from validation errors
+ // validate all and filter null values from validation errors
+ res.json(_.compact(data.map(e => UserValidate.output(e))));
});
});
-router.get('/user:username([/](?!key|new).?*|/?)', (req, res, next) => { // this path matches /user, /user/ and /user/xxx, but not /user/key or user/new. See https://forbeslindesay.github.io/express-route-tester/ for the generated regex
- if (!req.auth(res, ['read', 'write', 'maintain', 'dev', 'admin'], 'basic')) return;
+// this path matches /user, /user/ and /user/xxx, but not /user/key or user/new.
+// See https://forbeslindesay.github.io/express-route-tester/ for the generated regex
+router.get('/user:username([/](?!key|new).?*|/?)', (req, res, next) => {
+ if (!req.auth(res, ['read', 'write', 'dev', 'admin'], 'basic')) return;
const username = getUsername(req, res);
if (!username) return;
@@ -36,13 +39,15 @@ router.get('/user:username([/](?!key|new).?*|/?)', (req, res, next) => { // thi
});
});
-router.put('/user:username([/](?!key|new).?*|/?)', async (req, res, next) => { // this path matches /user, /user/ and /user/xxx, but not /user/key or user/new
- if (!req.auth(res, ['read', 'write', 'maintain', 'dev', 'admin'], 'basic')) return;
+// this path matches /user, /user/ and /user/xxx, but not /user/key or user/new
+router.put('/user:username([/](?!key|new).?*|/?)', async (req, res, next) => {
+ if (!req.auth(res, ['read', 'write', 'dev', 'admin'], 'basic')) return;
const username = getUsername(req, res);
if (!username) return;
- 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 (user.hasOwnProperty('pass')) {
@@ -66,8 +71,10 @@ router.put('/user:username([/](?!key|new).?*|/?)', async (req, res, next) => {
});
// TODO: only possible if no data is linked to user, otherwise change status, etc.
-router.delete('/user:username([/](?!key|new).?*|/?)', (req, res, next) => { // this path matches /user, /user/ and /user/xxx, but not /user/key or user/new. See https://forbeslindesay.github.io/express-route-tester/ for the generated regex
- if (!req.auth(res, ['read', 'write', 'maintain', 'dev', 'admin'], 'basic')) return;
+// this path matches /user, /user/ and /user/xxx, but not /user/key or user/new.
+// See https://forbeslindesay.github.io/express-route-tester/ for the generated regex
+router.delete('/user:username([/](?!key|new).?*|/?)', (req, res, next) => {
+ if (!req.auth(res, ['read', 'write', 'dev', 'admin'], 'basic')) return;
const username = getUsername(req, res);
if (!username) return;
@@ -84,7 +91,7 @@ router.delete('/user:username([/](?!key|new).?*|/?)', (req, res, next) => { //
});
router.get('/user/key', (req, res, next) => {
- if (!req.auth(res, ['read', 'write', 'maintain', 'dev', 'admin'], 'basic')) return;
+ if (!req.auth(res, ['read', 'write', 'dev', 'admin'], 'basic')) return;
UserModel.findOne({name: req.authDetails.username}).lean().exec( (err, data:any) => {
if (err) return next(err);
@@ -126,7 +133,10 @@ router.post('/user/passreset', (req, res, next) => {
if (err) return next(err);
// send email
- mail(data[0].email, 'Your new password for the DFOP database', 'Hi,
You requested to reset your password.
Your new password is:
' + newPass + '
If you did not request a password reset, talk to the sysadmin quickly!
Have a nice day.
The DFOP team', err => {
+ mail(data[0].email, 'Your new password for the DeFinMa database',
+ 'Hi,
You requested to reset your password.
Your new password is:
' + newPass + '' +
+ '
If you did not request a password reset, talk to the sysadmin quickly!
Have a nice day.' +
+ '
The DeFinMa team', err => {
if (err) return next(err);
res.json({status: 'OK'});
});
diff --git a/src/routes/validate/measurement.ts b/src/routes/validate/measurement.ts
index 0af8fbd..f7d8c70 100644
--- a/src/routes/validate/measurement.ts
+++ b/src/routes/validate/measurement.ts
@@ -34,8 +34,12 @@ export default class MeasurementValidate {
}
}
- static output (data) { // validate output and strip unwanted properties, returns null if not valid
+ static output (data, req) { // validate output and strip unwanted properties, returns null if not valid
data = IdValidate.stringify(data);
+ // spectral data not allowed for read/write users
+ if (['dev', 'admin'].indexOf(req.authDetails.level) < 0 && data.values.dpt) {
+ delete data.values.dpt;
+ }
const {value, error} = Joi.object({
_id: IdValidate.get(),
sample_id: IdValidate.get(),
diff --git a/src/test/db.json b/src/test/db.json
index 1987846..f95ed05 100644
--- a/src/test/db.json
+++ b/src/test/db.json
@@ -99,7 +99,7 @@
{
"_id": {"$oid":"400000000000000000000007"},
"number": "34",
- "type": "other",
+ "type": "part",
"color": "black",
"batch": "",
"condition": {},