Merge pull request #2 in ~VLE2FE/dfop-api from user to develop
* commit '20f57acd2aa031a3fbce7b4f61f6a64749d98606': implemented first /sample methods finished /template methods finished /material methods styled swagger added /materials route added custom type definitions added /user DELETE route added /user/key and edited /user regex added test helper and rewrote tests added PUT /user route added GET /user route changed to findById and improved db.loadJson added passreset and mail helper added authorization cannot add username twice implemented first tests and basic functionality
This commit is contained in:
		
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@@ -112,3 +112,4 @@ dist
 | 
				
			|||||||
**/.idea/tasks.xml
 | 
					**/.idea/tasks.xml
 | 
				
			||||||
**/.idea/shelf
 | 
					**/.idea/shelf
 | 
				
			||||||
**/.idea/*.iml
 | 
					**/.idea/*.iml
 | 
				
			||||||
 | 
					/tmp/
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										5
									
								
								.idea/codeStyles/codeStyleConfig.xml
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								.idea/codeStyles/codeStyleConfig.xml
									
									
									
										generated
									
									
									
										Normal file
									
								
							@@ -0,0 +1,5 @@
 | 
				
			|||||||
 | 
					<component name="ProjectCodeStyleConfiguration">
 | 
				
			||||||
 | 
					  <state>
 | 
				
			||||||
 | 
					    <option name="PREFERRED_PROJECT_CODE_STYLE" value="Default" />
 | 
				
			||||||
 | 
					  </state>
 | 
				
			||||||
 | 
					</component>
 | 
				
			||||||
							
								
								
									
										9
									
								
								.idea/dictionaries/VLE2FE.xml
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								.idea/dictionaries/VLE2FE.xml
									
									
									
										generated
									
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
				
			|||||||
 | 
					<component name="ProjectDictionaryState">
 | 
				
			||||||
 | 
					  <dictionary name="VLE2FE">
 | 
				
			||||||
 | 
					    <words>
 | 
				
			||||||
 | 
					      <w>bcrypt</w>
 | 
				
			||||||
 | 
					      <w>cfenv</w>
 | 
				
			||||||
 | 
					      <w>dfopdb</w>
 | 
				
			||||||
 | 
					    </words>
 | 
				
			||||||
 | 
					  </dictionary>
 | 
				
			||||||
 | 
					</component>
 | 
				
			||||||
							
								
								
									
										1
									
								
								.idea/inspectionProfiles/Project_Default.xml
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										1
									
								
								.idea/inspectionProfiles/Project_Default.xml
									
									
									
										generated
									
									
									
								
							@@ -2,5 +2,6 @@
 | 
				
			|||||||
  <profile version="1.0">
 | 
					  <profile version="1.0">
 | 
				
			||||||
    <option name="myName" value="Project Default" />
 | 
					    <option name="myName" value="Project Default" />
 | 
				
			||||||
    <inspection_tool class="JSUnfilteredForInLoop" enabled="false" level="WARNING" enabled_by_default="false" />
 | 
					    <inspection_tool class="JSUnfilteredForInLoop" enabled="false" level="WARNING" enabled_by_default="false" />
 | 
				
			||||||
 | 
					    <inspection_tool class="ReservedWordUsedAsNameJS" enabled="false" level="WARNING" enabled_by_default="false" />
 | 
				
			||||||
  </profile>
 | 
					  </profile>
 | 
				
			||||||
</component>
 | 
					</component>
 | 
				
			||||||
@@ -6,7 +6,10 @@ info:
 | 
				
			|||||||
  version: 1.0.0
 | 
					  version: 1.0.0
 | 
				
			||||||
  description: |
 | 
					  description: |
 | 
				
			||||||
    This API gives access to the project database.<br>
 | 
					    This API gives access to the project database.<br>
 | 
				
			||||||
    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<br>
 | 
					    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<br>
 | 
				
			||||||
 | 
					    The description lists available authentication methods, also the locks of each method close correspondingly
 | 
				
			||||||
 | 
					    if the entered authentication is allowed.<br><br>
 | 
				
			||||||
    There are a number of different user levels: <br>
 | 
					    There are a number of different user levels: <br>
 | 
				
			||||||
    <ul>
 | 
					    <ul>
 | 
				
			||||||
      <li>read: read access to the samples database</li>
 | 
					      <li>read: read access to the samples database</li>
 | 
				
			||||||
@@ -15,6 +18,15 @@ info:
 | 
				
			|||||||
      <li>dev: handling machine learning models</li>
 | 
					      <li>dev: handling machine learning models</li>
 | 
				
			||||||
      <li>admin: user administration</li>
 | 
					      <li>admin: user administration</li>
 | 
				
			||||||
    </ul>
 | 
					    </ul>
 | 
				
			||||||
 | 
					    Password policy:
 | 
				
			||||||
 | 
					    <ul>
 | 
				
			||||||
 | 
					      <li>at least one digit</li>
 | 
				
			||||||
 | 
					      <li>at least one lower case letter</li>
 | 
				
			||||||
 | 
					      <li>at least one upper case letter</li>
 | 
				
			||||||
 | 
					      <li>at least one of the following special characters: !"#%&'()*+,-./:;<=>?@[\]^_`{|}~</li>
 | 
				
			||||||
 | 
					      <li>no whitespace</li>
 | 
				
			||||||
 | 
					      <li>at least 8 characters</li>
 | 
				
			||||||
 | 
					    </ul>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -36,7 +48,7 @@ tags:
 | 
				
			|||||||
  - name: /material
 | 
					  - name: /material
 | 
				
			||||||
  - name: /condition
 | 
					  - name: /condition
 | 
				
			||||||
  - name: /measurement
 | 
					  - name: /measurement
 | 
				
			||||||
  - name: /templates
 | 
					  - name: /template
 | 
				
			||||||
  - name: /model
 | 
					  - name: /model
 | 
				
			||||||
  - name: /user
 | 
					  - name: /user
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										73
									
								
								api/condition.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										73
									
								
								api/condition.yaml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,73 @@
 | 
				
			|||||||
 | 
					/condition/{id}:
 | 
				
			||||||
 | 
					  parameters:
 | 
				
			||||||
 | 
					    - $ref: 'api.yaml#/components/parameters/Id'
 | 
				
			||||||
 | 
					  get:
 | 
				
			||||||
 | 
					    summary: TODO condition by id
 | 
				
			||||||
 | 
					    description: 'Auth: all, levels: read, write, maintain, dev, admin'
 | 
				
			||||||
 | 
					    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: TODO add/change condition
 | 
				
			||||||
 | 
					    description: 'Auth: basic, levels: write, maintain, dev, admin'
 | 
				
			||||||
 | 
					    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'
 | 
				
			||||||
 | 
					      404:
 | 
				
			||||||
 | 
					        $ref: 'api.yaml#/components/responses/404'
 | 
				
			||||||
 | 
					      500:
 | 
				
			||||||
 | 
					        $ref: 'api.yaml#/components/responses/500'
 | 
				
			||||||
 | 
					  delete:
 | 
				
			||||||
 | 
					    summary: TODO delete condition
 | 
				
			||||||
 | 
					    description: 'Auth: basic, levels: write, maintain, dev, admin'
 | 
				
			||||||
 | 
					    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'
 | 
				
			||||||
							
								
								
									
										119
									
								
								api/material.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										119
									
								
								api/material.yaml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,119 @@
 | 
				
			|||||||
 | 
					/materials:
 | 
				
			||||||
 | 
					  get:
 | 
				
			||||||
 | 
					    summary: lists all materials
 | 
				
			||||||
 | 
					    description: 'Auth: all, levels: read, write, maintain, dev, admin'
 | 
				
			||||||
 | 
					    tags:
 | 
				
			||||||
 | 
					      - /material
 | 
				
			||||||
 | 
					    responses:
 | 
				
			||||||
 | 
					      200:
 | 
				
			||||||
 | 
					        description: all material details
 | 
				
			||||||
 | 
					        content:
 | 
				
			||||||
 | 
					          application/json:
 | 
				
			||||||
 | 
					            schema:
 | 
				
			||||||
 | 
					              type: array
 | 
				
			||||||
 | 
					              items:
 | 
				
			||||||
 | 
					                $ref: 'api.yaml#/components/schemas/Material'
 | 
				
			||||||
 | 
					      401:
 | 
				
			||||||
 | 
					        $ref: 'api.yaml#/components/responses/401'
 | 
				
			||||||
 | 
					      500:
 | 
				
			||||||
 | 
					        $ref: 'api.yaml#/components/responses/500'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/material/{id}:
 | 
				
			||||||
 | 
					  parameters:
 | 
				
			||||||
 | 
					    - $ref: 'api.yaml#/components/parameters/Id'
 | 
				
			||||||
 | 
					  get:
 | 
				
			||||||
 | 
					    summary: get material details
 | 
				
			||||||
 | 
					    description: 'Auth: all, levels: read, write, maintain, dev, admin'
 | 
				
			||||||
 | 
					    tags:
 | 
				
			||||||
 | 
					      - /material
 | 
				
			||||||
 | 
					    responses:
 | 
				
			||||||
 | 
					      200:
 | 
				
			||||||
 | 
					        description: material details
 | 
				
			||||||
 | 
					        content:
 | 
				
			||||||
 | 
					          application/json:
 | 
				
			||||||
 | 
					            schema:
 | 
				
			||||||
 | 
					              $ref: 'api.yaml#/components/schemas/Material'
 | 
				
			||||||
 | 
					      401:
 | 
				
			||||||
 | 
					        $ref: 'api.yaml#/components/responses/401'
 | 
				
			||||||
 | 
					      404:
 | 
				
			||||||
 | 
					        $ref: 'api.yaml#/components/responses/404'
 | 
				
			||||||
 | 
					      500:
 | 
				
			||||||
 | 
					        $ref: 'api.yaml#/components/responses/500'
 | 
				
			||||||
 | 
					  put:
 | 
				
			||||||
 | 
					    summary: change material
 | 
				
			||||||
 | 
					    description: 'Auth: basic, levels: write, maintain, dev, admin'
 | 
				
			||||||
 | 
					    tags:
 | 
				
			||||||
 | 
					      - /material
 | 
				
			||||||
 | 
					    security:
 | 
				
			||||||
 | 
					      - BasicAuth: []
 | 
				
			||||||
 | 
					    requestBody:
 | 
				
			||||||
 | 
					      required: true
 | 
				
			||||||
 | 
					      content:
 | 
				
			||||||
 | 
					        application/json:
 | 
				
			||||||
 | 
					          schema:
 | 
				
			||||||
 | 
					            $ref: 'api.yaml#/components/schemas/Material'
 | 
				
			||||||
 | 
					    responses:
 | 
				
			||||||
 | 
					      200:
 | 
				
			||||||
 | 
					        description: material details
 | 
				
			||||||
 | 
					        content:
 | 
				
			||||||
 | 
					          application/json:
 | 
				
			||||||
 | 
					            schema:
 | 
				
			||||||
 | 
					              $ref: 'api.yaml#/components/schemas/Material'
 | 
				
			||||||
 | 
					      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 material
 | 
				
			||||||
 | 
					    description: 'Auth: basic, levels: write, maintain, dev, admin'
 | 
				
			||||||
 | 
					    tags:
 | 
				
			||||||
 | 
					      - /material
 | 
				
			||||||
 | 
					    security:
 | 
				
			||||||
 | 
					      - BasicAuth: []
 | 
				
			||||||
 | 
					    responses:
 | 
				
			||||||
 | 
					      200:
 | 
				
			||||||
 | 
					        $ref: 'api.yaml#/components/responses/Ok'
 | 
				
			||||||
 | 
					      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'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/material/new:
 | 
				
			||||||
 | 
					  post:
 | 
				
			||||||
 | 
					    summary: add material
 | 
				
			||||||
 | 
					    description: 'Auth: basic, levels: write, maintain, dev, admin'
 | 
				
			||||||
 | 
					    tags:
 | 
				
			||||||
 | 
					      - /material
 | 
				
			||||||
 | 
					    security:
 | 
				
			||||||
 | 
					      - BasicAuth: []
 | 
				
			||||||
 | 
					    requestBody:
 | 
				
			||||||
 | 
					      required: true
 | 
				
			||||||
 | 
					      content:
 | 
				
			||||||
 | 
					        application/json:
 | 
				
			||||||
 | 
					          schema:
 | 
				
			||||||
 | 
					            $ref: 'api.yaml#/components/schemas/Material'
 | 
				
			||||||
 | 
					    responses:
 | 
				
			||||||
 | 
					      200:
 | 
				
			||||||
 | 
					        description: material details
 | 
				
			||||||
 | 
					        content:
 | 
				
			||||||
 | 
					          application/json:
 | 
				
			||||||
 | 
					            schema:
 | 
				
			||||||
 | 
					              $ref: 'api.yaml#/components/schemas/Material'
 | 
				
			||||||
 | 
					      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'
 | 
				
			||||||
							
								
								
									
										73
									
								
								api/measurement.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										73
									
								
								api/measurement.yaml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,73 @@
 | 
				
			|||||||
 | 
					/measurement/{id}:
 | 
				
			||||||
 | 
					  parameters:
 | 
				
			||||||
 | 
					    - $ref: 'api.yaml#/components/parameters/Id'
 | 
				
			||||||
 | 
					  get:
 | 
				
			||||||
 | 
					    summary: TODO measurement values by id
 | 
				
			||||||
 | 
					    description: 'Auth: all, levels: read, write, maintain, dev, admin'
 | 
				
			||||||
 | 
					    tags:
 | 
				
			||||||
 | 
					      - /measurement
 | 
				
			||||||
 | 
					    responses:
 | 
				
			||||||
 | 
					      200:
 | 
				
			||||||
 | 
					        description: measurement details
 | 
				
			||||||
 | 
					        content:
 | 
				
			||||||
 | 
					          application/json:
 | 
				
			||||||
 | 
					            schema:
 | 
				
			||||||
 | 
					              $ref: 'api.yaml#/components/schemas/Measurement'
 | 
				
			||||||
 | 
					      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: TODO add/change measurement
 | 
				
			||||||
 | 
					    description: 'Auth: basic, levels: write, maintain, dev, admin'
 | 
				
			||||||
 | 
					    tags:
 | 
				
			||||||
 | 
					      - /measurement
 | 
				
			||||||
 | 
					    security:
 | 
				
			||||||
 | 
					      - BasicAuth: []
 | 
				
			||||||
 | 
					    requestBody:
 | 
				
			||||||
 | 
					      required: true
 | 
				
			||||||
 | 
					      content:
 | 
				
			||||||
 | 
					        application/json:
 | 
				
			||||||
 | 
					          schema:
 | 
				
			||||||
 | 
					            $ref: 'api.yaml#/components/schemas/Measurement'
 | 
				
			||||||
 | 
					    responses:
 | 
				
			||||||
 | 
					      200:
 | 
				
			||||||
 | 
					        description: measurement details
 | 
				
			||||||
 | 
					        content:
 | 
				
			||||||
 | 
					          application/json:
 | 
				
			||||||
 | 
					            schema:
 | 
				
			||||||
 | 
					              $ref: 'api.yaml#/components/schemas/Measurement'
 | 
				
			||||||
 | 
					      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: TODO delete measurement
 | 
				
			||||||
 | 
					    description: 'Auth: basic, levels: write, maintain, dev, admin'
 | 
				
			||||||
 | 
					    tags:
 | 
				
			||||||
 | 
					      - /measurement
 | 
				
			||||||
 | 
					    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'
 | 
				
			||||||
							
								
								
									
										70
									
								
								api/model.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								api/model.yaml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,70 @@
 | 
				
			|||||||
 | 
					/model/{name}:
 | 
				
			||||||
 | 
					  parameters:
 | 
				
			||||||
 | 
					    - $ref: 'api.yaml#/components/parameters/Name'
 | 
				
			||||||
 | 
					  get:
 | 
				
			||||||
 | 
					    summary: TODO get model data by name
 | 
				
			||||||
 | 
					    description: 'Auth: all, levels: dev, admin'
 | 
				
			||||||
 | 
					    tags:
 | 
				
			||||||
 | 
					      - /model
 | 
				
			||||||
 | 
					    responses:
 | 
				
			||||||
 | 
					      200:
 | 
				
			||||||
 | 
					        description: binary model data
 | 
				
			||||||
 | 
					        content:
 | 
				
			||||||
 | 
					          application/octet-stream:
 | 
				
			||||||
 | 
					            schema:
 | 
				
			||||||
 | 
					              type: string
 | 
				
			||||||
 | 
					              format: binary
 | 
				
			||||||
 | 
					      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'
 | 
				
			||||||
 | 
					  put:
 | 
				
			||||||
 | 
					    summary: TODO add/replace model data by name
 | 
				
			||||||
 | 
					    description: 'Auth: all, levels: dev, admin'
 | 
				
			||||||
 | 
					    tags:
 | 
				
			||||||
 | 
					      - /model
 | 
				
			||||||
 | 
					    requestBody:
 | 
				
			||||||
 | 
					      required: true
 | 
				
			||||||
 | 
					      description: binary model data
 | 
				
			||||||
 | 
					      content:
 | 
				
			||||||
 | 
					        application/json:
 | 
				
			||||||
 | 
					          schema:
 | 
				
			||||||
 | 
					            type: string
 | 
				
			||||||
 | 
					            format: binary
 | 
				
			||||||
 | 
					    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'
 | 
				
			||||||
 | 
					  delete:
 | 
				
			||||||
 | 
					    summary: TODO delete model data
 | 
				
			||||||
 | 
					    description: 'Auth: basic, levels: dev, admin'
 | 
				
			||||||
 | 
					    tags:
 | 
				
			||||||
 | 
					      - /model
 | 
				
			||||||
 | 
					    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'
 | 
				
			||||||
							
								
								
									
										43
									
								
								api/others.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								api/others.yaml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,43 @@
 | 
				
			|||||||
 | 
					/:
 | 
				
			||||||
 | 
					  get:
 | 
				
			||||||
 | 
					    summary: Root method
 | 
				
			||||||
 | 
					    description: 'Auth: none'
 | 
				
			||||||
 | 
					    tags:
 | 
				
			||||||
 | 
					      - /
 | 
				
			||||||
 | 
					    security: []
 | 
				
			||||||
 | 
					    responses:
 | 
				
			||||||
 | 
					      200:
 | 
				
			||||||
 | 
					        description: Server is working
 | 
				
			||||||
 | 
					        content:
 | 
				
			||||||
 | 
					          application/json:
 | 
				
			||||||
 | 
					            schema:
 | 
				
			||||||
 | 
					              properties:
 | 
				
			||||||
 | 
					                status:
 | 
				
			||||||
 | 
					                  type: string
 | 
				
			||||||
 | 
					                  example: 'API server up and running!'
 | 
				
			||||||
 | 
					      500:
 | 
				
			||||||
 | 
					        $ref: 'api.yaml#/components/responses/500'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/authorized:
 | 
				
			||||||
 | 
					  get:
 | 
				
			||||||
 | 
					    summary: Checks authorization
 | 
				
			||||||
 | 
					    description: 'Auth: all, levels: read, write, maintain, dev, admin'
 | 
				
			||||||
 | 
					    tags:
 | 
				
			||||||
 | 
					      - /
 | 
				
			||||||
 | 
					    responses:
 | 
				
			||||||
 | 
					      200:
 | 
				
			||||||
 | 
					        description: Authorized
 | 
				
			||||||
 | 
					        content:
 | 
				
			||||||
 | 
					          application/json:
 | 
				
			||||||
 | 
					            schema:
 | 
				
			||||||
 | 
					              properties:
 | 
				
			||||||
 | 
					                status:
 | 
				
			||||||
 | 
					                  type: string
 | 
				
			||||||
 | 
					                  example: 'Authorization successful'
 | 
				
			||||||
 | 
					                method:
 | 
				
			||||||
 | 
					                  type: string
 | 
				
			||||||
 | 
					                  example: 'basic'
 | 
				
			||||||
 | 
					      401:
 | 
				
			||||||
 | 
					        $ref: 'api.yaml#/components/responses/401'
 | 
				
			||||||
 | 
					      500:
 | 
				
			||||||
 | 
					        $ref: 'api.yaml#/components/responses/500'
 | 
				
			||||||
@@ -4,8 +4,10 @@ Id:
 | 
				
			|||||||
  required: true
 | 
					  required: true
 | 
				
			||||||
  schema:
 | 
					  schema:
 | 
				
			||||||
    type: string
 | 
					    type: string
 | 
				
			||||||
 | 
					  example: 5ea0450ed851c30a90e70894
 | 
				
			||||||
Name:
 | 
					Name:
 | 
				
			||||||
  name: name
 | 
					  name: name
 | 
				
			||||||
 | 
					  description: has to be URL encoded
 | 
				
			||||||
  in: path
 | 
					  in: path
 | 
				
			||||||
  required: true
 | 
					  required: true
 | 
				
			||||||
  schema:
 | 
					  schema:
 | 
				
			||||||
							
								
								
									
										145
									
								
								api/sample.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										145
									
								
								api/sample.yaml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,145 @@
 | 
				
			|||||||
 | 
					/samples:
 | 
				
			||||||
 | 
					  get:
 | 
				
			||||||
 | 
					    summary: all samples in overview
 | 
				
			||||||
 | 
					    description: 'Auth: all, levels: read, write, maintain, dev, admin'
 | 
				
			||||||
 | 
					    tags:
 | 
				
			||||||
 | 
					      - /sample
 | 
				
			||||||
 | 
					    responses:
 | 
				
			||||||
 | 
					      200:
 | 
				
			||||||
 | 
					        description: samples overview
 | 
				
			||||||
 | 
					        content:
 | 
				
			||||||
 | 
					          application/json:
 | 
				
			||||||
 | 
					            schema:
 | 
				
			||||||
 | 
					              type: array
 | 
				
			||||||
 | 
					              items:
 | 
				
			||||||
 | 
					                $ref: 'api.yaml#/components/schemas/SampleRefs'
 | 
				
			||||||
 | 
					      401:
 | 
				
			||||||
 | 
					        $ref: 'api.yaml#/components/responses/401'
 | 
				
			||||||
 | 
					      500:
 | 
				
			||||||
 | 
					        $ref: 'api.yaml#/components/responses/500'
 | 
				
			||||||
 | 
					/sample/{id}:
 | 
				
			||||||
 | 
					  parameters:
 | 
				
			||||||
 | 
					    - $ref: 'api.yaml#/components/parameters/Id'
 | 
				
			||||||
 | 
					  get:
 | 
				
			||||||
 | 
					    summary: TODO sample details
 | 
				
			||||||
 | 
					    description: 'Auth: all, levels: read, write, maintain, dev, admin'
 | 
				
			||||||
 | 
					    tags:
 | 
				
			||||||
 | 
					      - /sample
 | 
				
			||||||
 | 
					    responses:
 | 
				
			||||||
 | 
					      200:
 | 
				
			||||||
 | 
					        description: samples details
 | 
				
			||||||
 | 
					        content:
 | 
				
			||||||
 | 
					          application/json:
 | 
				
			||||||
 | 
					            schema:
 | 
				
			||||||
 | 
					              $ref: 'api.yaml#/components/schemas/SampleDetail'
 | 
				
			||||||
 | 
					      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: TODO change sample
 | 
				
			||||||
 | 
					    description: 'Auth: basic, levels: write, maintain, dev, admin'
 | 
				
			||||||
 | 
					    tags:
 | 
				
			||||||
 | 
					      - /sample
 | 
				
			||||||
 | 
					    security:
 | 
				
			||||||
 | 
					        - BasicAuth: []
 | 
				
			||||||
 | 
					    requestBody:
 | 
				
			||||||
 | 
					      required: true
 | 
				
			||||||
 | 
					      content:
 | 
				
			||||||
 | 
					        application/json:
 | 
				
			||||||
 | 
					          schema:
 | 
				
			||||||
 | 
					            $ref: 'api.yaml#/components/schemas/Sample'
 | 
				
			||||||
 | 
					    responses:
 | 
				
			||||||
 | 
					      200:
 | 
				
			||||||
 | 
					        description: samples details
 | 
				
			||||||
 | 
					        content:
 | 
				
			||||||
 | 
					          application/json:
 | 
				
			||||||
 | 
					            schema:
 | 
				
			||||||
 | 
					              $ref: 'api.yaml#/components/schemas/SampleDetail'
 | 
				
			||||||
 | 
					      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: TODO delete sample
 | 
				
			||||||
 | 
					    description: 'Auth: basic, levels: write, maintain, dev, admin'
 | 
				
			||||||
 | 
					    tags:
 | 
				
			||||||
 | 
					      - /sample
 | 
				
			||||||
 | 
					    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'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/sample/new:
 | 
				
			||||||
 | 
					  post:
 | 
				
			||||||
 | 
					    summary: add sample
 | 
				
			||||||
 | 
					    description: 'Auth: basic, levels: write, maintain, dev, admin'
 | 
				
			||||||
 | 
					    tags:
 | 
				
			||||||
 | 
					      - /sample
 | 
				
			||||||
 | 
					    security:
 | 
				
			||||||
 | 
					      - BasicAuth: []
 | 
				
			||||||
 | 
					    requestBody:
 | 
				
			||||||
 | 
					      required: true
 | 
				
			||||||
 | 
					      content:
 | 
				
			||||||
 | 
					        application/json:
 | 
				
			||||||
 | 
					          schema:
 | 
				
			||||||
 | 
					            $ref: 'api.yaml#/components/schemas/Sample'
 | 
				
			||||||
 | 
					    responses:
 | 
				
			||||||
 | 
					      200:
 | 
				
			||||||
 | 
					        description: samples details
 | 
				
			||||||
 | 
					        content:
 | 
				
			||||||
 | 
					          application/json:
 | 
				
			||||||
 | 
					            schema:
 | 
				
			||||||
 | 
					              $ref: 'api.yaml#/components/schemas/SampleRefs'
 | 
				
			||||||
 | 
					      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'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/sample/notes/fields:
 | 
				
			||||||
 | 
					  get:
 | 
				
			||||||
 | 
					    summary: TODO list all existing field names for custom notes fields
 | 
				
			||||||
 | 
					    description: 'Auth: all, levels: read, write, maintain, dev, admin'
 | 
				
			||||||
 | 
					    tags:
 | 
				
			||||||
 | 
					      - /sample
 | 
				
			||||||
 | 
					    responses:
 | 
				
			||||||
 | 
					      200:
 | 
				
			||||||
 | 
					        description: field names and quantity of usage
 | 
				
			||||||
 | 
					        content:
 | 
				
			||||||
 | 
					          application/json:
 | 
				
			||||||
 | 
					            schema:
 | 
				
			||||||
 | 
					              properties:
 | 
				
			||||||
 | 
					                name:
 | 
				
			||||||
 | 
					                  type: string
 | 
				
			||||||
 | 
					                qty:
 | 
				
			||||||
 | 
					                  type: number
 | 
				
			||||||
 | 
					                  example: 20
 | 
				
			||||||
 | 
					      401:
 | 
				
			||||||
 | 
					        $ref: 'api.yaml#/components/responses/401'
 | 
				
			||||||
 | 
					      500:
 | 
				
			||||||
 | 
					        $ref: 'api.yaml#/components/responses/500'
 | 
				
			||||||
							
								
								
									
										183
									
								
								api/schemas.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										183
									
								
								api/schemas.yaml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,183 @@
 | 
				
			|||||||
 | 
					Id:
 | 
				
			||||||
 | 
					  type: string
 | 
				
			||||||
 | 
					  example: 5ea0450ed851c30a90e70894
 | 
				
			||||||
 | 
					_Id:
 | 
				
			||||||
 | 
					  properties:
 | 
				
			||||||
 | 
					    _id:
 | 
				
			||||||
 | 
					      allOf:
 | 
				
			||||||
 | 
					        - $ref: 'api.yaml#/components/schemas/Id'
 | 
				
			||||||
 | 
					      readOnly: true
 | 
				
			||||||
 | 
					Color:
 | 
				
			||||||
 | 
					  properties:
 | 
				
			||||||
 | 
					    color:
 | 
				
			||||||
 | 
					      type: string
 | 
				
			||||||
 | 
					      example: black
 | 
				
			||||||
 | 
					SampleProperties:
 | 
				
			||||||
 | 
					  properties:
 | 
				
			||||||
 | 
					    number:
 | 
				
			||||||
 | 
					      type: string
 | 
				
			||||||
 | 
					      example: Rng172
 | 
				
			||||||
 | 
					    type:
 | 
				
			||||||
 | 
					      type: string
 | 
				
			||||||
 | 
					      example: granulate
 | 
				
			||||||
 | 
					    batch:
 | 
				
			||||||
 | 
					      type: string
 | 
				
			||||||
 | 
					      example: 1560237365
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					SampleRefs:
 | 
				
			||||||
 | 
					  allOf:
 | 
				
			||||||
 | 
					    - $ref: 'api.yaml#/components/schemas/_Id'
 | 
				
			||||||
 | 
					    - $ref: 'api.yaml#/components/schemas/Color'
 | 
				
			||||||
 | 
					    - $ref: 'api.yaml#/components/schemas/SampleProperties'
 | 
				
			||||||
 | 
					  properties:
 | 
				
			||||||
 | 
					    material_id:
 | 
				
			||||||
 | 
					      $ref: 'api.yaml#/components/schemas/Id'
 | 
				
			||||||
 | 
					    note_id:
 | 
				
			||||||
 | 
					      $ref: 'api.yaml#/components/schemas/Id'
 | 
				
			||||||
 | 
					    user_id:
 | 
				
			||||||
 | 
					      $ref: 'api.yaml#/components/schemas/Id'
 | 
				
			||||||
 | 
					Sample:
 | 
				
			||||||
 | 
					  allOf:
 | 
				
			||||||
 | 
					    - $ref: 'api.yaml#/components/schemas/_Id'
 | 
				
			||||||
 | 
					    - $ref: 'api.yaml#/components/schemas/Color'
 | 
				
			||||||
 | 
					    - $ref: 'api.yaml#/components/schemas/SampleProperties'
 | 
				
			||||||
 | 
					  properties:
 | 
				
			||||||
 | 
					    material_id:
 | 
				
			||||||
 | 
					      allOf:
 | 
				
			||||||
 | 
					        - $ref: 'api.yaml#/components/schemas/Id'
 | 
				
			||||||
 | 
					    notes:
 | 
				
			||||||
 | 
					      type: object
 | 
				
			||||||
 | 
					      properties:
 | 
				
			||||||
 | 
					        comment:
 | 
				
			||||||
 | 
					          type: string
 | 
				
			||||||
 | 
					        sample_references:
 | 
				
			||||||
 | 
					          type: array
 | 
				
			||||||
 | 
					          items:
 | 
				
			||||||
 | 
					            properties:
 | 
				
			||||||
 | 
					              id:
 | 
				
			||||||
 | 
					                $ref: 'api.yaml#/components/schemas/Id'
 | 
				
			||||||
 | 
					              relation:
 | 
				
			||||||
 | 
					                type: string
 | 
				
			||||||
 | 
					                example: part to this sample
 | 
				
			||||||
 | 
					SampleDetail:
 | 
				
			||||||
 | 
					  allOf:
 | 
				
			||||||
 | 
					    - $ref: 'api.yaml#/components/schemas/_Id'
 | 
				
			||||||
 | 
					    - $ref: 'api.yaml#/components/schemas/Color'
 | 
				
			||||||
 | 
					    - $ref: 'api.yaml#/components/schemas/SampleProperties'
 | 
				
			||||||
 | 
					  properties:
 | 
				
			||||||
 | 
					    material:
 | 
				
			||||||
 | 
					      $ref: 'api.yaml#/components/schemas/Material'
 | 
				
			||||||
 | 
					    notes:
 | 
				
			||||||
 | 
					      type: object
 | 
				
			||||||
 | 
					      properties:
 | 
				
			||||||
 | 
					        comment:
 | 
				
			||||||
 | 
					          type: string
 | 
				
			||||||
 | 
					        sample_references:
 | 
				
			||||||
 | 
					          type: array
 | 
				
			||||||
 | 
					          items:
 | 
				
			||||||
 | 
					            $ref: 'api.yaml#/components/schemas/Id'
 | 
				
			||||||
 | 
					    conditions:
 | 
				
			||||||
 | 
					      type: array
 | 
				
			||||||
 | 
					      items:
 | 
				
			||||||
 | 
					        $ref: 'api.yaml#/components/schemas/Condition'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Material:
 | 
				
			||||||
 | 
					  allOf:
 | 
				
			||||||
 | 
					    - $ref: 'api.yaml#/components/schemas/_Id'
 | 
				
			||||||
 | 
					  properties:
 | 
				
			||||||
 | 
					    name:
 | 
				
			||||||
 | 
					      type: string
 | 
				
			||||||
 | 
					      example: Stanyl TW 200 F8
 | 
				
			||||||
 | 
					    supplier:
 | 
				
			||||||
 | 
					      type: string
 | 
				
			||||||
 | 
					      example: DSM
 | 
				
			||||||
 | 
					    group:
 | 
				
			||||||
 | 
					      type: string
 | 
				
			||||||
 | 
					      example: PA46
 | 
				
			||||||
 | 
					    mineral:
 | 
				
			||||||
 | 
					      type: number
 | 
				
			||||||
 | 
					      example: 0
 | 
				
			||||||
 | 
					    glass_fiber:
 | 
				
			||||||
 | 
					      type: number
 | 
				
			||||||
 | 
					      example: 40
 | 
				
			||||||
 | 
					    carbon_fiber:
 | 
				
			||||||
 | 
					      type: number
 | 
				
			||||||
 | 
					      example: 0
 | 
				
			||||||
 | 
					    numbers:
 | 
				
			||||||
 | 
					      type: array
 | 
				
			||||||
 | 
					      items:
 | 
				
			||||||
 | 
					        type: object
 | 
				
			||||||
 | 
					        allOf:
 | 
				
			||||||
 | 
					          - $ref: 'api.yaml#/components/schemas/Color'
 | 
				
			||||||
 | 
					        properties:
 | 
				
			||||||
 | 
					          number:
 | 
				
			||||||
 | 
					            type: number
 | 
				
			||||||
 | 
					            example: 5514263423
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Condition:
 | 
				
			||||||
 | 
					  allOf:
 | 
				
			||||||
 | 
					    - $ref: 'api.yaml#/components/schemas/_Id'
 | 
				
			||||||
 | 
					  properties:
 | 
				
			||||||
 | 
					    sample_id:
 | 
				
			||||||
 | 
					      $ref: 'api.yaml#/components/schemas/Id'
 | 
				
			||||||
 | 
					    parameters:
 | 
				
			||||||
 | 
					      type: object
 | 
				
			||||||
 | 
					    treatment_template:
 | 
				
			||||||
 | 
					      $ref: 'api.yaml#/components/schemas/Id'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Measurement:
 | 
				
			||||||
 | 
					  allOf:
 | 
				
			||||||
 | 
					    - $ref: 'api.yaml#/components/schemas/_Id'
 | 
				
			||||||
 | 
					  properties:
 | 
				
			||||||
 | 
					    condition_id:
 | 
				
			||||||
 | 
					      $ref: 'api.yaml#/components/schemas/Id'
 | 
				
			||||||
 | 
					    values:
 | 
				
			||||||
 | 
					      type: object
 | 
				
			||||||
 | 
					    measurement_template:
 | 
				
			||||||
 | 
					      $ref: 'api.yaml#/components/schemas/Id'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Template:
 | 
				
			||||||
 | 
					  allOf:
 | 
				
			||||||
 | 
					    - $ref: 'api.yaml#/components/schemas/_Id'
 | 
				
			||||||
 | 
					  properties:
 | 
				
			||||||
 | 
					    name:
 | 
				
			||||||
 | 
					      type: string
 | 
				
			||||||
 | 
					    parameters:
 | 
				
			||||||
 | 
					      type: array
 | 
				
			||||||
 | 
					      items:
 | 
				
			||||||
 | 
					        type: object
 | 
				
			||||||
 | 
					        properties:
 | 
				
			||||||
 | 
					          name:
 | 
				
			||||||
 | 
					            type: string
 | 
				
			||||||
 | 
					          range:
 | 
				
			||||||
 | 
					            type: object
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Email:
 | 
				
			||||||
 | 
					  properties:
 | 
				
			||||||
 | 
					    email:
 | 
				
			||||||
 | 
					      type: string
 | 
				
			||||||
 | 
					      example: john.doe@bosch.com
 | 
				
			||||||
 | 
					UserName:
 | 
				
			||||||
 | 
					  properties:
 | 
				
			||||||
 | 
					    name:
 | 
				
			||||||
 | 
					      type: string
 | 
				
			||||||
 | 
					      example: johndoe
 | 
				
			||||||
 | 
					User:
 | 
				
			||||||
 | 
					  allOf:
 | 
				
			||||||
 | 
					    - $ref: 'api.yaml#/components/schemas/_Id'
 | 
				
			||||||
 | 
					    - $ref: 'api.yaml#/components/schemas/UserName'
 | 
				
			||||||
 | 
					    - $ref: 'api.yaml#/components/schemas/Email'
 | 
				
			||||||
 | 
					  properties:
 | 
				
			||||||
 | 
					    pass:
 | 
				
			||||||
 | 
					      type: string
 | 
				
			||||||
 | 
					      writeOnly: true
 | 
				
			||||||
 | 
					      example: Abc123!#
 | 
				
			||||||
 | 
					    level:
 | 
				
			||||||
 | 
					      type: string
 | 
				
			||||||
 | 
					      example: read
 | 
				
			||||||
 | 
					    location:
 | 
				
			||||||
 | 
					      type: string
 | 
				
			||||||
 | 
					      example: Rng
 | 
				
			||||||
 | 
					    device_name:
 | 
				
			||||||
 | 
					      type: string
 | 
				
			||||||
 | 
					      example: Alpha II
 | 
				
			||||||
							
								
								
									
										263
									
								
								api/template.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										263
									
								
								api/template.yaml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,263 @@
 | 
				
			|||||||
 | 
					/template/treatments:
 | 
				
			||||||
 | 
					  get:
 | 
				
			||||||
 | 
					    summary: all available treatment methods
 | 
				
			||||||
 | 
					    description: 'Auth: basic, levels: read, write, maintain, dev, admin'
 | 
				
			||||||
 | 
					    tags:
 | 
				
			||||||
 | 
					      - /template
 | 
				
			||||||
 | 
					    security:
 | 
				
			||||||
 | 
					      - BasicAuth: []
 | 
				
			||||||
 | 
					    responses:
 | 
				
			||||||
 | 
					      200:
 | 
				
			||||||
 | 
					        description: list of treatments
 | 
				
			||||||
 | 
					        content:
 | 
				
			||||||
 | 
					          application/json:
 | 
				
			||||||
 | 
					            schema:
 | 
				
			||||||
 | 
					              type: array
 | 
				
			||||||
 | 
					              items:
 | 
				
			||||||
 | 
					                $ref: 'api.yaml#/components/schemas/Template'
 | 
				
			||||||
 | 
					              example:
 | 
				
			||||||
 | 
					                _id: 5ea0450ed851c30a90e70894
 | 
				
			||||||
 | 
					                name: heat aging
 | 
				
			||||||
 | 
					                parameters:
 | 
				
			||||||
 | 
					                  - name: method
 | 
				
			||||||
 | 
					                    range:
 | 
				
			||||||
 | 
					                      values:
 | 
				
			||||||
 | 
					                        - copper
 | 
				
			||||||
 | 
					                        - hot air
 | 
				
			||||||
 | 
					      401:
 | 
				
			||||||
 | 
					        $ref: 'api.yaml#/components/responses/401'
 | 
				
			||||||
 | 
					      500:
 | 
				
			||||||
 | 
					        $ref: 'api.yaml#/components/responses/500'
 | 
				
			||||||
 | 
					/template/treatment/{name}:
 | 
				
			||||||
 | 
					  parameters:
 | 
				
			||||||
 | 
					    - $ref: 'api.yaml#/components/parameters/Name'
 | 
				
			||||||
 | 
					  get:
 | 
				
			||||||
 | 
					    summary: treatment method details
 | 
				
			||||||
 | 
					    description: 'Auth: basic, levels: read, write, maintain, admin'
 | 
				
			||||||
 | 
					    tags:
 | 
				
			||||||
 | 
					      - /template
 | 
				
			||||||
 | 
					    security:
 | 
				
			||||||
 | 
					      - BasicAuth: []
 | 
				
			||||||
 | 
					    responses:
 | 
				
			||||||
 | 
					      200:
 | 
				
			||||||
 | 
					        description: treatment details
 | 
				
			||||||
 | 
					        content:
 | 
				
			||||||
 | 
					          application/json:
 | 
				
			||||||
 | 
					            schema:
 | 
				
			||||||
 | 
					              allOf:
 | 
				
			||||||
 | 
					                - $ref: 'api.yaml#/components/schemas/Template'
 | 
				
			||||||
 | 
					              example:
 | 
				
			||||||
 | 
					                _id: 5ea0450ed851c30a90e70894
 | 
				
			||||||
 | 
					                name: heat aging
 | 
				
			||||||
 | 
					                parameters:
 | 
				
			||||||
 | 
					                  - name: method
 | 
				
			||||||
 | 
					                    range:
 | 
				
			||||||
 | 
					                      values:
 | 
				
			||||||
 | 
					                        - copper
 | 
				
			||||||
 | 
					                        - hot air
 | 
				
			||||||
 | 
					      401:
 | 
				
			||||||
 | 
					        $ref: 'api.yaml#/components/responses/401'
 | 
				
			||||||
 | 
					      404:
 | 
				
			||||||
 | 
					        $ref: 'api.yaml#/components/responses/404'
 | 
				
			||||||
 | 
					      500:
 | 
				
			||||||
 | 
					        $ref: 'api.yaml#/components/responses/500'
 | 
				
			||||||
 | 
					  put:
 | 
				
			||||||
 | 
					    summary: add/change treatment method
 | 
				
			||||||
 | 
					    description: 'Auth: basic, levels: maintain, admin'
 | 
				
			||||||
 | 
					    tags:
 | 
				
			||||||
 | 
					      - /template
 | 
				
			||||||
 | 
					    security:
 | 
				
			||||||
 | 
					        - BasicAuth: []
 | 
				
			||||||
 | 
					    requestBody:
 | 
				
			||||||
 | 
					      required: true
 | 
				
			||||||
 | 
					      content:
 | 
				
			||||||
 | 
					        application/json:
 | 
				
			||||||
 | 
					          schema:
 | 
				
			||||||
 | 
					            allOf:
 | 
				
			||||||
 | 
					              - $ref: 'api.yaml#/components/schemas/Template'
 | 
				
			||||||
 | 
					            example:
 | 
				
			||||||
 | 
					              name: heat aging
 | 
				
			||||||
 | 
					              parameters:
 | 
				
			||||||
 | 
					                - name: method
 | 
				
			||||||
 | 
					                  range:
 | 
				
			||||||
 | 
					                    values:
 | 
				
			||||||
 | 
					                      - copper
 | 
				
			||||||
 | 
					                      - hot air
 | 
				
			||||||
 | 
					    responses:
 | 
				
			||||||
 | 
					      200:
 | 
				
			||||||
 | 
					        description: treatment details
 | 
				
			||||||
 | 
					        content:
 | 
				
			||||||
 | 
					          application/json:
 | 
				
			||||||
 | 
					            schema:
 | 
				
			||||||
 | 
					              allOf:
 | 
				
			||||||
 | 
					                - $ref: 'api.yaml#/components/schemas/Template'
 | 
				
			||||||
 | 
					              example:
 | 
				
			||||||
 | 
					                _id: 5ea0450ed851c30a90e70894
 | 
				
			||||||
 | 
					                name: heat aging
 | 
				
			||||||
 | 
					                parameters:
 | 
				
			||||||
 | 
					                  - name: method
 | 
				
			||||||
 | 
					                    range:
 | 
				
			||||||
 | 
					                      values:
 | 
				
			||||||
 | 
					                        - copper
 | 
				
			||||||
 | 
					                        - hot air
 | 
				
			||||||
 | 
					      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 treatment method
 | 
				
			||||||
 | 
					    description: 'Auth: basic, levels: maintain, admin'
 | 
				
			||||||
 | 
					    tags:
 | 
				
			||||||
 | 
					      - /template
 | 
				
			||||||
 | 
					    security:
 | 
				
			||||||
 | 
					      - BasicAuth: []
 | 
				
			||||||
 | 
					    responses:
 | 
				
			||||||
 | 
					      200:
 | 
				
			||||||
 | 
					        $ref: 'api.yaml#/components/responses/Ok'
 | 
				
			||||||
 | 
					      400:
 | 
				
			||||||
 | 
					        $ref: 'api.yaml#/components/responses/400'
 | 
				
			||||||
 | 
					      401:
 | 
				
			||||||
 | 
					        $ref: 'api.yaml#/components/responses/401'
 | 
				
			||||||
 | 
					      403:
 | 
				
			||||||
 | 
					        $ref: 'api.yaml#/components/responses/403'
 | 
				
			||||||
 | 
					      404:
 | 
				
			||||||
 | 
					        $ref: 'api.yaml#/components/responses/404'
 | 
				
			||||||
 | 
					      500:
 | 
				
			||||||
 | 
					        $ref: 'api.yaml#/components/responses/500'
 | 
				
			||||||
 | 
					/template/measurements:
 | 
				
			||||||
 | 
					  get:
 | 
				
			||||||
 | 
					    summary: all available measurement methods
 | 
				
			||||||
 | 
					    description: 'Auth: basic, levels: read, write, maintain, dev, admin'
 | 
				
			||||||
 | 
					    tags:
 | 
				
			||||||
 | 
					      - /template
 | 
				
			||||||
 | 
					    security:
 | 
				
			||||||
 | 
					      - BasicAuth: []
 | 
				
			||||||
 | 
					    responses:
 | 
				
			||||||
 | 
					      200:
 | 
				
			||||||
 | 
					        description: list of measurement methods
 | 
				
			||||||
 | 
					        content:
 | 
				
			||||||
 | 
					          application/json:
 | 
				
			||||||
 | 
					            schema:
 | 
				
			||||||
 | 
					              type: array
 | 
				
			||||||
 | 
					              items:
 | 
				
			||||||
 | 
					                $ref: 'api.yaml#/components/schemas/Template'
 | 
				
			||||||
 | 
					              example:
 | 
				
			||||||
 | 
					                _id: 5ea0450ed851c30a90e70894
 | 
				
			||||||
 | 
					                name: humidity
 | 
				
			||||||
 | 
					                parameters:
 | 
				
			||||||
 | 
					                  - name: kf
 | 
				
			||||||
 | 
					                    range:
 | 
				
			||||||
 | 
					                      min: 0
 | 
				
			||||||
 | 
					                      max: 2
 | 
				
			||||||
 | 
					      401:
 | 
				
			||||||
 | 
					        $ref: 'api.yaml#/components/responses/401'
 | 
				
			||||||
 | 
					      500:
 | 
				
			||||||
 | 
					        $ref: 'api.yaml#/components/responses/500'
 | 
				
			||||||
 | 
					/template/measurement/{name}:
 | 
				
			||||||
 | 
					  parameters:
 | 
				
			||||||
 | 
					    - $ref: 'api.yaml#/components/parameters/Name'
 | 
				
			||||||
 | 
					  get:
 | 
				
			||||||
 | 
					    summary: measurement method details
 | 
				
			||||||
 | 
					    description: 'Auth: basic, levels: read, write, maintain, admin'
 | 
				
			||||||
 | 
					    tags:
 | 
				
			||||||
 | 
					      - /template
 | 
				
			||||||
 | 
					    security:
 | 
				
			||||||
 | 
					      - BasicAuth: []
 | 
				
			||||||
 | 
					    responses:
 | 
				
			||||||
 | 
					      200:
 | 
				
			||||||
 | 
					        description: measurement details
 | 
				
			||||||
 | 
					        content:
 | 
				
			||||||
 | 
					          application/json:
 | 
				
			||||||
 | 
					            schema:
 | 
				
			||||||
 | 
					              allOf:
 | 
				
			||||||
 | 
					                - $ref: 'api.yaml#/components/schemas/Template'
 | 
				
			||||||
 | 
					              example:
 | 
				
			||||||
 | 
					                _id: 5ea0450ed851c30a90e70894
 | 
				
			||||||
 | 
					                name: humidity
 | 
				
			||||||
 | 
					                parameters:
 | 
				
			||||||
 | 
					                  - name: kf
 | 
				
			||||||
 | 
					                    range:
 | 
				
			||||||
 | 
					                      min: 0
 | 
				
			||||||
 | 
					                      max: 2
 | 
				
			||||||
 | 
					      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: add/change measurement method
 | 
				
			||||||
 | 
					    description: 'Auth: basic, levels: maintain, admin'
 | 
				
			||||||
 | 
					    tags:
 | 
				
			||||||
 | 
					      - /template
 | 
				
			||||||
 | 
					    security:
 | 
				
			||||||
 | 
					      - BasicAuth: []
 | 
				
			||||||
 | 
					    requestBody:
 | 
				
			||||||
 | 
					      required: true
 | 
				
			||||||
 | 
					      content:
 | 
				
			||||||
 | 
					        application/json:
 | 
				
			||||||
 | 
					          schema:
 | 
				
			||||||
 | 
					            allOf:
 | 
				
			||||||
 | 
					              - $ref: 'api.yaml#/components/schemas/Template'
 | 
				
			||||||
 | 
					            example:
 | 
				
			||||||
 | 
					              _id: 5ea0450ed851c30a90e70894
 | 
				
			||||||
 | 
					              name: humidity
 | 
				
			||||||
 | 
					              parameters:
 | 
				
			||||||
 | 
					                - name: kf
 | 
				
			||||||
 | 
					                  range:
 | 
				
			||||||
 | 
					                    min: 0
 | 
				
			||||||
 | 
					                    max: 2
 | 
				
			||||||
 | 
					    responses:
 | 
				
			||||||
 | 
					      200:
 | 
				
			||||||
 | 
					        description: measurement details
 | 
				
			||||||
 | 
					        content:
 | 
				
			||||||
 | 
					          application/json:
 | 
				
			||||||
 | 
					            schema:
 | 
				
			||||||
 | 
					              allOf:
 | 
				
			||||||
 | 
					                - $ref: 'api.yaml#/components/schemas/Template'
 | 
				
			||||||
 | 
					              example:
 | 
				
			||||||
 | 
					                _id: 5ea0450ed851c30a90e70894
 | 
				
			||||||
 | 
					                name: humidity
 | 
				
			||||||
 | 
					                parameters:
 | 
				
			||||||
 | 
					                  - name: kf
 | 
				
			||||||
 | 
					                    range:
 | 
				
			||||||
 | 
					                      min: 0
 | 
				
			||||||
 | 
					                      max: 2
 | 
				
			||||||
 | 
					      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 measurement method
 | 
				
			||||||
 | 
					    description: 'Auth: basic, levels: maintain, admin'
 | 
				
			||||||
 | 
					    tags:
 | 
				
			||||||
 | 
					      - /template
 | 
				
			||||||
 | 
					    security:
 | 
				
			||||||
 | 
					      - BasicAuth: []
 | 
				
			||||||
 | 
					    responses:
 | 
				
			||||||
 | 
					      200:
 | 
				
			||||||
 | 
					        $ref: 'api.yaml#/components/responses/Ok'
 | 
				
			||||||
 | 
					      400:
 | 
				
			||||||
 | 
					        $ref: 'api.yaml#/components/responses/400'
 | 
				
			||||||
 | 
					      401:
 | 
				
			||||||
 | 
					        $ref: 'api.yaml#/components/responses/401'
 | 
				
			||||||
 | 
					      403:
 | 
				
			||||||
 | 
					        $ref: 'api.yaml#/components/responses/403'
 | 
				
			||||||
 | 
					      404:
 | 
				
			||||||
 | 
					        $ref: 'api.yaml#/components/responses/404'
 | 
				
			||||||
 | 
					      500:
 | 
				
			||||||
 | 
					        $ref: 'api.yaml#/components/responses/500'
 | 
				
			||||||
							
								
								
									
										255
									
								
								api/user.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										255
									
								
								api/user.yaml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,255 @@
 | 
				
			|||||||
 | 
					/users:
 | 
				
			||||||
 | 
					  get:
 | 
				
			||||||
 | 
					    summary: lists all users
 | 
				
			||||||
 | 
					    description: 'Auth: basic, levels: admin'
 | 
				
			||||||
 | 
					    tags:
 | 
				
			||||||
 | 
					      - /user
 | 
				
			||||||
 | 
					    security:
 | 
				
			||||||
 | 
					      - BasicAuth: []
 | 
				
			||||||
 | 
					    responses:
 | 
				
			||||||
 | 
					      200:
 | 
				
			||||||
 | 
					        description: user API key
 | 
				
			||||||
 | 
					        content:
 | 
				
			||||||
 | 
					          application/json:
 | 
				
			||||||
 | 
					            schema:
 | 
				
			||||||
 | 
					              type: array
 | 
				
			||||||
 | 
					              items:
 | 
				
			||||||
 | 
					                $ref: 'api.yaml#/components/schemas/User'
 | 
				
			||||||
 | 
					      401:
 | 
				
			||||||
 | 
					        $ref: 'api.yaml#/components/responses/401'
 | 
				
			||||||
 | 
					      403:
 | 
				
			||||||
 | 
					        $ref: 'api.yaml#/components/responses/403'
 | 
				
			||||||
 | 
					      500:
 | 
				
			||||||
 | 
					        $ref: 'api.yaml#/components/responses/500'
 | 
				
			||||||
 | 
					/user:
 | 
				
			||||||
 | 
					  get:
 | 
				
			||||||
 | 
					    summary: list own user details
 | 
				
			||||||
 | 
					    description: 'Auth: basic, levels: read, write, maintain, admin'
 | 
				
			||||||
 | 
					    tags:
 | 
				
			||||||
 | 
					      - /user
 | 
				
			||||||
 | 
					    security:
 | 
				
			||||||
 | 
					      - BasicAuth: []
 | 
				
			||||||
 | 
					    responses:
 | 
				
			||||||
 | 
					      200:
 | 
				
			||||||
 | 
					        description: user details
 | 
				
			||||||
 | 
					        content:
 | 
				
			||||||
 | 
					          application/json:
 | 
				
			||||||
 | 
					            schema:
 | 
				
			||||||
 | 
					              $ref: 'api.yaml#/components/schemas/User'
 | 
				
			||||||
 | 
					      401:
 | 
				
			||||||
 | 
					        $ref: 'api.yaml#/components/responses/401'
 | 
				
			||||||
 | 
					      403:
 | 
				
			||||||
 | 
					        $ref: 'api.yaml#/components/responses/403'
 | 
				
			||||||
 | 
					      500:
 | 
				
			||||||
 | 
					        $ref: 'api.yaml#/components/responses/500'
 | 
				
			||||||
 | 
					  put:
 | 
				
			||||||
 | 
					    summary: change user details
 | 
				
			||||||
 | 
					    description: 'Auth: basic, levels: read, write, maintain, admin'
 | 
				
			||||||
 | 
					    tags:
 | 
				
			||||||
 | 
					      - /user
 | 
				
			||||||
 | 
					    security:
 | 
				
			||||||
 | 
					      - BasicAuth: []
 | 
				
			||||||
 | 
					    requestBody:
 | 
				
			||||||
 | 
					      required: true
 | 
				
			||||||
 | 
					      content:
 | 
				
			||||||
 | 
					        application/json:
 | 
				
			||||||
 | 
					          schema:
 | 
				
			||||||
 | 
					            allOf:
 | 
				
			||||||
 | 
					              - $ref: 'api.yaml#/components/schemas/_Id'
 | 
				
			||||||
 | 
					              - $ref: 'api.yaml#/components/schemas/UserName'
 | 
				
			||||||
 | 
					              - $ref: 'api.yaml#/components/schemas/Email'
 | 
				
			||||||
 | 
					            properties:
 | 
				
			||||||
 | 
					              pass:
 | 
				
			||||||
 | 
					                type: string
 | 
				
			||||||
 | 
					                writeOnly: true
 | 
				
			||||||
 | 
					                example: Abc123!#
 | 
				
			||||||
 | 
					              location:
 | 
				
			||||||
 | 
					                type: string
 | 
				
			||||||
 | 
					                example: Rng
 | 
				
			||||||
 | 
					              device_name:
 | 
				
			||||||
 | 
					                type: string
 | 
				
			||||||
 | 
					                example: Alpha II
 | 
				
			||||||
 | 
					    responses:
 | 
				
			||||||
 | 
					      200:
 | 
				
			||||||
 | 
					        description: user details
 | 
				
			||||||
 | 
					        content:
 | 
				
			||||||
 | 
					          application/json:
 | 
				
			||||||
 | 
					            schema:
 | 
				
			||||||
 | 
					              $ref: 'api.yaml#/components/schemas/User'
 | 
				
			||||||
 | 
					      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'
 | 
				
			||||||
 | 
					  delete:
 | 
				
			||||||
 | 
					    summary: delete user
 | 
				
			||||||
 | 
					    description: 'Auth: basic, levels: read, write, maintain, admin'
 | 
				
			||||||
 | 
					    tags:
 | 
				
			||||||
 | 
					      - /user
 | 
				
			||||||
 | 
					    security:
 | 
				
			||||||
 | 
					      - BasicAuth: []
 | 
				
			||||||
 | 
					    responses:
 | 
				
			||||||
 | 
					      200:
 | 
				
			||||||
 | 
					        $ref: 'api.yaml#/components/responses/Ok'
 | 
				
			||||||
 | 
					      401:
 | 
				
			||||||
 | 
					        $ref: 'api.yaml#/components/responses/401'
 | 
				
			||||||
 | 
					      500:
 | 
				
			||||||
 | 
					        $ref: 'api.yaml#/components/responses/500'
 | 
				
			||||||
 | 
					/user/{name}:
 | 
				
			||||||
 | 
					  parameters:
 | 
				
			||||||
 | 
					    - $ref: 'api.yaml#/components/parameters/Name'
 | 
				
			||||||
 | 
					  get:
 | 
				
			||||||
 | 
					    summary: list user details
 | 
				
			||||||
 | 
					    description: 'Auth: basic, levels: admin'
 | 
				
			||||||
 | 
					    tags:
 | 
				
			||||||
 | 
					      - /user
 | 
				
			||||||
 | 
					    security:
 | 
				
			||||||
 | 
					      - BasicAuth: []
 | 
				
			||||||
 | 
					    responses:
 | 
				
			||||||
 | 
					      200:
 | 
				
			||||||
 | 
					        description: user details
 | 
				
			||||||
 | 
					        content:
 | 
				
			||||||
 | 
					          application/json:
 | 
				
			||||||
 | 
					            schema:
 | 
				
			||||||
 | 
					              $ref: 'api.yaml#/components/schemas/User'
 | 
				
			||||||
 | 
					      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'
 | 
				
			||||||
 | 
					  put:
 | 
				
			||||||
 | 
					    summary: change user details
 | 
				
			||||||
 | 
					    description: 'Auth: basic, levels: admin'
 | 
				
			||||||
 | 
					    tags:
 | 
				
			||||||
 | 
					      - /user
 | 
				
			||||||
 | 
					    security:
 | 
				
			||||||
 | 
					      - BasicAuth: []
 | 
				
			||||||
 | 
					    requestBody:
 | 
				
			||||||
 | 
					      required: true
 | 
				
			||||||
 | 
					      content:
 | 
				
			||||||
 | 
					        application/json:
 | 
				
			||||||
 | 
					          schema:
 | 
				
			||||||
 | 
					            $ref: 'api.yaml#/components/schemas/User'
 | 
				
			||||||
 | 
					    responses:
 | 
				
			||||||
 | 
					      200:
 | 
				
			||||||
 | 
					        description: user details
 | 
				
			||||||
 | 
					        content:
 | 
				
			||||||
 | 
					          application/json:
 | 
				
			||||||
 | 
					            schema:
 | 
				
			||||||
 | 
					              $ref: 'api.yaml#/components/schemas/User'
 | 
				
			||||||
 | 
					      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 user
 | 
				
			||||||
 | 
					    description: 'Auth: basic, levels: admin'
 | 
				
			||||||
 | 
					    tags:
 | 
				
			||||||
 | 
					      - /user
 | 
				
			||||||
 | 
					    security:
 | 
				
			||||||
 | 
					      - BasicAuth: []
 | 
				
			||||||
 | 
					    responses:
 | 
				
			||||||
 | 
					      200:
 | 
				
			||||||
 | 
					        $ref: 'api.yaml#/components/responses/Ok'
 | 
				
			||||||
 | 
					      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'
 | 
				
			||||||
 | 
					/user/key:
 | 
				
			||||||
 | 
					  get:
 | 
				
			||||||
 | 
					    summary: get API key for the user
 | 
				
			||||||
 | 
					    description: 'Auth: basic, levels: read, write, maintain, dev, admin'
 | 
				
			||||||
 | 
					    tags:
 | 
				
			||||||
 | 
					      - /user
 | 
				
			||||||
 | 
					    security:
 | 
				
			||||||
 | 
					      - BasicAuth: []
 | 
				
			||||||
 | 
					    responses:
 | 
				
			||||||
 | 
					      200:
 | 
				
			||||||
 | 
					        description: user details
 | 
				
			||||||
 | 
					        content:
 | 
				
			||||||
 | 
					          application/json:
 | 
				
			||||||
 | 
					            schema:
 | 
				
			||||||
 | 
					              properties:
 | 
				
			||||||
 | 
					                key:
 | 
				
			||||||
 | 
					                  type: string
 | 
				
			||||||
 | 
					                  example: 5ea0450ed851c30a90e70899
 | 
				
			||||||
 | 
					      401:
 | 
				
			||||||
 | 
					        $ref: 'api.yaml#/components/responses/401'
 | 
				
			||||||
 | 
					      500:
 | 
				
			||||||
 | 
					        $ref: 'api.yaml#/components/responses/500'
 | 
				
			||||||
 | 
					/user/new:
 | 
				
			||||||
 | 
					  post:
 | 
				
			||||||
 | 
					    summary: add new user
 | 
				
			||||||
 | 
					    description: 'Auth: basic, levels: admin'
 | 
				
			||||||
 | 
					    tags:
 | 
				
			||||||
 | 
					      - /user
 | 
				
			||||||
 | 
					    security:
 | 
				
			||||||
 | 
					      - BasicAuth: []
 | 
				
			||||||
 | 
					    requestBody:
 | 
				
			||||||
 | 
					      required: true
 | 
				
			||||||
 | 
					      content:
 | 
				
			||||||
 | 
					        application/json:
 | 
				
			||||||
 | 
					          schema:
 | 
				
			||||||
 | 
					            required:
 | 
				
			||||||
 | 
					              - email
 | 
				
			||||||
 | 
					              - name
 | 
				
			||||||
 | 
					              - pass
 | 
				
			||||||
 | 
					              - level
 | 
				
			||||||
 | 
					              - location
 | 
				
			||||||
 | 
					              - device_name
 | 
				
			||||||
 | 
					            allOf:
 | 
				
			||||||
 | 
					              - $ref: 'api.yaml#/components/schemas/User'
 | 
				
			||||||
 | 
					    responses:
 | 
				
			||||||
 | 
					      200:
 | 
				
			||||||
 | 
					        description: user details
 | 
				
			||||||
 | 
					        content:
 | 
				
			||||||
 | 
					          application/json:
 | 
				
			||||||
 | 
					            schema:
 | 
				
			||||||
 | 
					              $ref: 'api.yaml#/components/schemas/User'
 | 
				
			||||||
 | 
					      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'
 | 
				
			||||||
 | 
					/user/passreset:
 | 
				
			||||||
 | 
					  post:
 | 
				
			||||||
 | 
					    summary: reset password and send mail to restore
 | 
				
			||||||
 | 
					    description: 'Auth: none'
 | 
				
			||||||
 | 
					    tags:
 | 
				
			||||||
 | 
					      - /user
 | 
				
			||||||
 | 
					    security: []
 | 
				
			||||||
 | 
					    requestBody:
 | 
				
			||||||
 | 
					      required: true
 | 
				
			||||||
 | 
					      description: mail saved in user profile to provide authentication
 | 
				
			||||||
 | 
					      content:
 | 
				
			||||||
 | 
					        application/json:
 | 
				
			||||||
 | 
					          schema:
 | 
				
			||||||
 | 
					            allOf:
 | 
				
			||||||
 | 
					              - $ref: 'api.yaml#/components/schemas/UserName'
 | 
				
			||||||
 | 
					              - $ref: 'api.yaml#/components/schemas/Email'
 | 
				
			||||||
 | 
					    responses:
 | 
				
			||||||
 | 
					      200:
 | 
				
			||||||
 | 
					        $ref: 'api.yaml#/components/responses/Ok'
 | 
				
			||||||
 | 
					      404:
 | 
				
			||||||
 | 
					        $ref: 'api.yaml#/components/responses/404'
 | 
				
			||||||
 | 
					      500:
 | 
				
			||||||
 | 
					        $ref: 'api.yaml#/components/responses/500'
 | 
				
			||||||
@@ -1,69 +0,0 @@
 | 
				
			|||||||
/condition/{id}:
 | 
					 | 
				
			||||||
  parameters:
 | 
					 | 
				
			||||||
    - $ref: 'oas.yaml#/components/parameters/Id'
 | 
					 | 
				
			||||||
  get:
 | 
					 | 
				
			||||||
    summary: TODO condition by id
 | 
					 | 
				
			||||||
    description: 'levels: read, write, maintain, dev, admin'
 | 
					 | 
				
			||||||
    tags:
 | 
					 | 
				
			||||||
      - /condition
 | 
					 | 
				
			||||||
    responses:
 | 
					 | 
				
			||||||
      200:
 | 
					 | 
				
			||||||
        description: condition details
 | 
					 | 
				
			||||||
        content:
 | 
					 | 
				
			||||||
          application/json:
 | 
					 | 
				
			||||||
            schema:
 | 
					 | 
				
			||||||
              $ref: 'oas.yaml#/components/schemas/Condition'
 | 
					 | 
				
			||||||
      400:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/400'
 | 
					 | 
				
			||||||
      401:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/401'
 | 
					 | 
				
			||||||
      404:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/404'
 | 
					 | 
				
			||||||
      500:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/500'
 | 
					 | 
				
			||||||
  put:
 | 
					 | 
				
			||||||
    summary: TODO add/change condition
 | 
					 | 
				
			||||||
    description: 'levels: write, maintain, dev, admin'
 | 
					 | 
				
			||||||
    tags:
 | 
					 | 
				
			||||||
      - /condition
 | 
					 | 
				
			||||||
    requestBody:
 | 
					 | 
				
			||||||
      required: true
 | 
					 | 
				
			||||||
      content:
 | 
					 | 
				
			||||||
        application/json:
 | 
					 | 
				
			||||||
          schema:
 | 
					 | 
				
			||||||
            $ref: 'oas.yaml#/components/schemas/Condition'
 | 
					 | 
				
			||||||
    responses:
 | 
					 | 
				
			||||||
      200:
 | 
					 | 
				
			||||||
        description: condition details
 | 
					 | 
				
			||||||
        content:
 | 
					 | 
				
			||||||
          application/json:
 | 
					 | 
				
			||||||
            schema:
 | 
					 | 
				
			||||||
              $ref: 'oas.yaml#/components/schemas/Condition'
 | 
					 | 
				
			||||||
      400:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/400'
 | 
					 | 
				
			||||||
      401:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/401'
 | 
					 | 
				
			||||||
      403:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/403'
 | 
					 | 
				
			||||||
      404:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/404'
 | 
					 | 
				
			||||||
      500:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/500'
 | 
					 | 
				
			||||||
  delete:
 | 
					 | 
				
			||||||
    summary: TODO delete condition
 | 
					 | 
				
			||||||
    description: 'levels: write, maintain, dev, admin'
 | 
					 | 
				
			||||||
    tags:
 | 
					 | 
				
			||||||
      - /condition
 | 
					 | 
				
			||||||
    responses:
 | 
					 | 
				
			||||||
      200:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/Ok'
 | 
					 | 
				
			||||||
      400:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/400'
 | 
					 | 
				
			||||||
      401:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/401'
 | 
					 | 
				
			||||||
      403:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/403'
 | 
					 | 
				
			||||||
      404:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/404'
 | 
					 | 
				
			||||||
      500:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/500'
 | 
					 | 
				
			||||||
@@ -1,63 +0,0 @@
 | 
				
			|||||||
/material/{id}:
 | 
					 | 
				
			||||||
  parameters:
 | 
					 | 
				
			||||||
    - $ref: 'oas.yaml#/components/parameters/Id'
 | 
					 | 
				
			||||||
  get:
 | 
					 | 
				
			||||||
    summary: TODO get material details
 | 
					 | 
				
			||||||
    description: 'levels: read, write, maintain, dev, admin'
 | 
					 | 
				
			||||||
    tags:
 | 
					 | 
				
			||||||
      - /material
 | 
					 | 
				
			||||||
    responses:
 | 
					 | 
				
			||||||
      200:
 | 
					 | 
				
			||||||
        description: created material
 | 
					 | 
				
			||||||
        content:
 | 
					 | 
				
			||||||
          application/json:
 | 
					 | 
				
			||||||
            schema:
 | 
					 | 
				
			||||||
              $ref: 'oas.yaml#/components/schemas/Material'
 | 
					 | 
				
			||||||
      400:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/400'
 | 
					 | 
				
			||||||
      401:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/401'
 | 
					 | 
				
			||||||
      500:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/500'
 | 
					 | 
				
			||||||
  put:
 | 
					 | 
				
			||||||
    summary: TODO add/change material
 | 
					 | 
				
			||||||
    description: 'levels: write, maintain, dev, admin'
 | 
					 | 
				
			||||||
    tags:
 | 
					 | 
				
			||||||
      - /material
 | 
					 | 
				
			||||||
    requestBody:
 | 
					 | 
				
			||||||
      required: true
 | 
					 | 
				
			||||||
      content:
 | 
					 | 
				
			||||||
        application/json:
 | 
					 | 
				
			||||||
          schema:
 | 
					 | 
				
			||||||
            $ref: 'oas.yaml#/components/schemas/Material'
 | 
					 | 
				
			||||||
    responses:
 | 
					 | 
				
			||||||
      200:
 | 
					 | 
				
			||||||
        description: material details
 | 
					 | 
				
			||||||
        content:
 | 
					 | 
				
			||||||
          application/json:
 | 
					 | 
				
			||||||
            schema:
 | 
					 | 
				
			||||||
              $ref: 'oas.yaml#/components/schemas/Material'
 | 
					 | 
				
			||||||
      400:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/400'
 | 
					 | 
				
			||||||
      401:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/401'
 | 
					 | 
				
			||||||
      403:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/403'
 | 
					 | 
				
			||||||
      500:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/500'
 | 
					 | 
				
			||||||
  delete:
 | 
					 | 
				
			||||||
    summary: TODO delete material
 | 
					 | 
				
			||||||
    description: 'levels: write, maintain, dev, admin'
 | 
					 | 
				
			||||||
    tags:
 | 
					 | 
				
			||||||
      - /material
 | 
					 | 
				
			||||||
    responses:
 | 
					 | 
				
			||||||
      200:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/Ok'
 | 
					 | 
				
			||||||
      400:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/400'
 | 
					 | 
				
			||||||
      401:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/401'
 | 
					 | 
				
			||||||
      403:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/403'
 | 
					 | 
				
			||||||
      500:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/500'
 | 
					 | 
				
			||||||
@@ -1,69 +0,0 @@
 | 
				
			|||||||
/measurement/{id}:
 | 
					 | 
				
			||||||
  parameters:
 | 
					 | 
				
			||||||
    - $ref: 'oas.yaml#/components/parameters/Id'
 | 
					 | 
				
			||||||
  get:
 | 
					 | 
				
			||||||
    summary: TODO measurement values by id
 | 
					 | 
				
			||||||
    description: 'levels: read, write, maintain, dev, admin'
 | 
					 | 
				
			||||||
    tags:
 | 
					 | 
				
			||||||
      - /measurement
 | 
					 | 
				
			||||||
    responses:
 | 
					 | 
				
			||||||
      200:
 | 
					 | 
				
			||||||
        description: measurement details
 | 
					 | 
				
			||||||
        content:
 | 
					 | 
				
			||||||
          application/json:
 | 
					 | 
				
			||||||
            schema:
 | 
					 | 
				
			||||||
              $ref: 'oas.yaml#/components/schemas/Measurement'
 | 
					 | 
				
			||||||
      400:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/400'
 | 
					 | 
				
			||||||
      401:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/401'
 | 
					 | 
				
			||||||
      404:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/404'
 | 
					 | 
				
			||||||
      500:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/500'
 | 
					 | 
				
			||||||
  put:
 | 
					 | 
				
			||||||
    summary: TODO add/change measurement
 | 
					 | 
				
			||||||
    description: 'levels: write, maintain, dev, admin'
 | 
					 | 
				
			||||||
    tags:
 | 
					 | 
				
			||||||
      - /measurement
 | 
					 | 
				
			||||||
    requestBody:
 | 
					 | 
				
			||||||
      required: true
 | 
					 | 
				
			||||||
      content:
 | 
					 | 
				
			||||||
        application/json:
 | 
					 | 
				
			||||||
          schema:
 | 
					 | 
				
			||||||
            $ref: 'oas.yaml#/components/schemas/Measurement'
 | 
					 | 
				
			||||||
    responses:
 | 
					 | 
				
			||||||
      200:
 | 
					 | 
				
			||||||
        description: measurement details
 | 
					 | 
				
			||||||
        content:
 | 
					 | 
				
			||||||
          application/json:
 | 
					 | 
				
			||||||
            schema:
 | 
					 | 
				
			||||||
              $ref: 'oas.yaml#/components/schemas/Measurement'
 | 
					 | 
				
			||||||
      400:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/400'
 | 
					 | 
				
			||||||
      401:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/401'
 | 
					 | 
				
			||||||
      403:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/403'
 | 
					 | 
				
			||||||
      404:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/404'
 | 
					 | 
				
			||||||
      500:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/500'
 | 
					 | 
				
			||||||
  delete:
 | 
					 | 
				
			||||||
    summary: TODO delete measurement
 | 
					 | 
				
			||||||
    description: 'levels: write, maintain, dev, admin'
 | 
					 | 
				
			||||||
    tags:
 | 
					 | 
				
			||||||
      - /measurement
 | 
					 | 
				
			||||||
    responses:
 | 
					 | 
				
			||||||
      200:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/Ok'
 | 
					 | 
				
			||||||
      400:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/400'
 | 
					 | 
				
			||||||
      401:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/401'
 | 
					 | 
				
			||||||
      403:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/403'
 | 
					 | 
				
			||||||
      404:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/404'
 | 
					 | 
				
			||||||
      500:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/500'
 | 
					 | 
				
			||||||
@@ -1,68 +0,0 @@
 | 
				
			|||||||
/model/{name}:
 | 
					 | 
				
			||||||
  parameters:
 | 
					 | 
				
			||||||
    - $ref: 'oas.yaml#/components/parameters/Name'
 | 
					 | 
				
			||||||
  get:
 | 
					 | 
				
			||||||
    summary: TODO get model data by name
 | 
					 | 
				
			||||||
    description: 'levels: dev, admin'
 | 
					 | 
				
			||||||
    tags:
 | 
					 | 
				
			||||||
      - /model
 | 
					 | 
				
			||||||
    responses:
 | 
					 | 
				
			||||||
      200:
 | 
					 | 
				
			||||||
        description: binary model data
 | 
					 | 
				
			||||||
        content:
 | 
					 | 
				
			||||||
          application/octet-stream:
 | 
					 | 
				
			||||||
            schema:
 | 
					 | 
				
			||||||
              type: string
 | 
					 | 
				
			||||||
              format: binary
 | 
					 | 
				
			||||||
      401:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/401'
 | 
					 | 
				
			||||||
      403:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/403'
 | 
					 | 
				
			||||||
      404:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/404'
 | 
					 | 
				
			||||||
      500:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/500'
 | 
					 | 
				
			||||||
  put:
 | 
					 | 
				
			||||||
    summary: TODO add/replace model data by name
 | 
					 | 
				
			||||||
    description: 'levels: dev, admin'
 | 
					 | 
				
			||||||
    tags:
 | 
					 | 
				
			||||||
      - /model
 | 
					 | 
				
			||||||
    requestBody:
 | 
					 | 
				
			||||||
      required: true
 | 
					 | 
				
			||||||
      description: binary model data
 | 
					 | 
				
			||||||
      content:
 | 
					 | 
				
			||||||
        application/json:
 | 
					 | 
				
			||||||
          schema:
 | 
					 | 
				
			||||||
            type: string
 | 
					 | 
				
			||||||
            format: binary
 | 
					 | 
				
			||||||
    responses:
 | 
					 | 
				
			||||||
      200:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/Ok'
 | 
					 | 
				
			||||||
      400:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/400'
 | 
					 | 
				
			||||||
      401:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/401'
 | 
					 | 
				
			||||||
      403:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/403'
 | 
					 | 
				
			||||||
      404:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/404'
 | 
					 | 
				
			||||||
      500:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/500'
 | 
					 | 
				
			||||||
  delete:
 | 
					 | 
				
			||||||
    summary: TODO delete model data
 | 
					 | 
				
			||||||
    description: 'levels: dev, admin'
 | 
					 | 
				
			||||||
    tags:
 | 
					 | 
				
			||||||
      - /model
 | 
					 | 
				
			||||||
    responses:
 | 
					 | 
				
			||||||
      200:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/Ok'
 | 
					 | 
				
			||||||
      400:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/400'
 | 
					 | 
				
			||||||
      401:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/401'
 | 
					 | 
				
			||||||
      403:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/403'
 | 
					 | 
				
			||||||
      404:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/404'
 | 
					 | 
				
			||||||
      500:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/500'
 | 
					 | 
				
			||||||
@@ -1,18 +0,0 @@
 | 
				
			|||||||
/:
 | 
					 | 
				
			||||||
  get:
 | 
					 | 
				
			||||||
    summary: Root method
 | 
					 | 
				
			||||||
    tags:
 | 
					 | 
				
			||||||
      - /
 | 
					 | 
				
			||||||
    security: []
 | 
					 | 
				
			||||||
    responses:
 | 
					 | 
				
			||||||
      200:
 | 
					 | 
				
			||||||
        description: Server is working
 | 
					 | 
				
			||||||
        content:
 | 
					 | 
				
			||||||
          application/json:
 | 
					 | 
				
			||||||
            schema:
 | 
					 | 
				
			||||||
              properties:
 | 
					 | 
				
			||||||
                message:
 | 
					 | 
				
			||||||
                  type: string
 | 
					 | 
				
			||||||
                  example: 'API server up and running!'
 | 
					 | 
				
			||||||
      500:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/500'
 | 
					 | 
				
			||||||
							
								
								
									
										108
									
								
								oas/sample.yaml
									
									
									
									
									
								
							
							
						
						
									
										108
									
								
								oas/sample.yaml
									
									
									
									
									
								
							@@ -1,108 +0,0 @@
 | 
				
			|||||||
/samples:
 | 
					 | 
				
			||||||
  get:
 | 
					 | 
				
			||||||
    summary: TODO all samples in overview
 | 
					 | 
				
			||||||
    description: 'levels: read, write, maintain, dev, admin'
 | 
					 | 
				
			||||||
    tags:
 | 
					 | 
				
			||||||
      - /sample
 | 
					 | 
				
			||||||
    responses:
 | 
					 | 
				
			||||||
      200:
 | 
					 | 
				
			||||||
        description: samples overview
 | 
					 | 
				
			||||||
        content:
 | 
					 | 
				
			||||||
          application/json:
 | 
					 | 
				
			||||||
            schema:
 | 
					 | 
				
			||||||
              $ref: 'oas.yaml#/components/schemas/Samples'
 | 
					 | 
				
			||||||
      401:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/401'
 | 
					 | 
				
			||||||
      500:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/500'
 | 
					 | 
				
			||||||
/sample/{id}:
 | 
					 | 
				
			||||||
  parameters:
 | 
					 | 
				
			||||||
    - $ref: 'oas.yaml#/components/parameters/Id'
 | 
					 | 
				
			||||||
  get:
 | 
					 | 
				
			||||||
    summary: TODO sample details
 | 
					 | 
				
			||||||
    description: 'levels: read, write, maintain, dev, admin'
 | 
					 | 
				
			||||||
    tags:
 | 
					 | 
				
			||||||
      - /sample
 | 
					 | 
				
			||||||
    responses:
 | 
					 | 
				
			||||||
      200:
 | 
					 | 
				
			||||||
        description: samples details
 | 
					 | 
				
			||||||
        content:
 | 
					 | 
				
			||||||
          application/json:
 | 
					 | 
				
			||||||
            schema:
 | 
					 | 
				
			||||||
              $ref: 'oas.yaml#/components/schemas/SampleDetail'
 | 
					 | 
				
			||||||
      400:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/400'
 | 
					 | 
				
			||||||
      401:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/401'
 | 
					 | 
				
			||||||
      404:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/404'
 | 
					 | 
				
			||||||
      500:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/500'
 | 
					 | 
				
			||||||
  put:
 | 
					 | 
				
			||||||
    summary: TODO add/change sample
 | 
					 | 
				
			||||||
    description: 'levels: write, maintain, dev, admin'
 | 
					 | 
				
			||||||
    tags:
 | 
					 | 
				
			||||||
      - /sample
 | 
					 | 
				
			||||||
    requestBody:
 | 
					 | 
				
			||||||
      required: true
 | 
					 | 
				
			||||||
      content:
 | 
					 | 
				
			||||||
        application/json:
 | 
					 | 
				
			||||||
          schema:
 | 
					 | 
				
			||||||
            $ref: 'oas.yaml#/components/schemas/Sample'
 | 
					 | 
				
			||||||
    responses:
 | 
					 | 
				
			||||||
      200:
 | 
					 | 
				
			||||||
        description: samples details
 | 
					 | 
				
			||||||
        content:
 | 
					 | 
				
			||||||
          application/json:
 | 
					 | 
				
			||||||
            schema:
 | 
					 | 
				
			||||||
              $ref: 'oas.yaml#/components/schemas/SampleDetail'
 | 
					 | 
				
			||||||
      400:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/400'
 | 
					 | 
				
			||||||
      401:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/401'
 | 
					 | 
				
			||||||
      403:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/403'
 | 
					 | 
				
			||||||
      404:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/404'
 | 
					 | 
				
			||||||
      500:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/500'
 | 
					 | 
				
			||||||
  delete:
 | 
					 | 
				
			||||||
    summary: TODO delete sample
 | 
					 | 
				
			||||||
    description: 'levels: write, maintain, dev, admin'
 | 
					 | 
				
			||||||
    tags:
 | 
					 | 
				
			||||||
      - /sample
 | 
					 | 
				
			||||||
    responses:
 | 
					 | 
				
			||||||
      200:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/Ok'
 | 
					 | 
				
			||||||
      400:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/400'
 | 
					 | 
				
			||||||
      401:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/401'
 | 
					 | 
				
			||||||
      403:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/403'
 | 
					 | 
				
			||||||
      404:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/404'
 | 
					 | 
				
			||||||
      500:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/500'
 | 
					 | 
				
			||||||
/sample/notes/fields:
 | 
					 | 
				
			||||||
  get:
 | 
					 | 
				
			||||||
    summary: TODO list all existing field names for custom notes fields
 | 
					 | 
				
			||||||
    description: 'levels: write, maintain, dev, admin'
 | 
					 | 
				
			||||||
    tags:
 | 
					 | 
				
			||||||
      - /sample
 | 
					 | 
				
			||||||
    responses:
 | 
					 | 
				
			||||||
      200:
 | 
					 | 
				
			||||||
        description: field names and quantity of usage
 | 
					 | 
				
			||||||
        content:
 | 
					 | 
				
			||||||
          application/json:
 | 
					 | 
				
			||||||
            schema:
 | 
					 | 
				
			||||||
              properties:
 | 
					 | 
				
			||||||
                name:
 | 
					 | 
				
			||||||
                  type: string
 | 
					 | 
				
			||||||
                qty:
 | 
					 | 
				
			||||||
                  type: number
 | 
					 | 
				
			||||||
                  example: 20
 | 
					 | 
				
			||||||
      401:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/401'
 | 
					 | 
				
			||||||
      500:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/500'
 | 
					 | 
				
			||||||
							
								
								
									
										164
									
								
								oas/schemas.yaml
									
									
									
									
									
								
							
							
						
						
									
										164
									
								
								oas/schemas.yaml
									
									
									
									
									
								
							@@ -1,164 +0,0 @@
 | 
				
			|||||||
Id:
 | 
					 | 
				
			||||||
  type: string
 | 
					 | 
				
			||||||
_Id:
 | 
					 | 
				
			||||||
  properties:
 | 
					 | 
				
			||||||
    _id:
 | 
					 | 
				
			||||||
      allOf:
 | 
					 | 
				
			||||||
        - $ref: 'oas.yaml#/components/schemas/Id'
 | 
					 | 
				
			||||||
      readOnly: true
 | 
					 | 
				
			||||||
Color:
 | 
					 | 
				
			||||||
  properties:
 | 
					 | 
				
			||||||
    color:
 | 
					 | 
				
			||||||
      type: string
 | 
					 | 
				
			||||||
SampleProperties:
 | 
					 | 
				
			||||||
  properties:
 | 
					 | 
				
			||||||
    sample_number:
 | 
					 | 
				
			||||||
      type: string
 | 
					 | 
				
			||||||
    type:
 | 
					 | 
				
			||||||
      type: string
 | 
					 | 
				
			||||||
    batch:
 | 
					 | 
				
			||||||
      type: string
 | 
					 | 
				
			||||||
    validated:
 | 
					 | 
				
			||||||
      type: boolean
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Samples:
 | 
					 | 
				
			||||||
  allOf:
 | 
					 | 
				
			||||||
    - $ref: 'oas.yaml#/components/schemas/_Id'
 | 
					 | 
				
			||||||
    - $ref: 'oas.yaml#/components/schemas/Color'
 | 
					 | 
				
			||||||
    - $ref: 'oas.yaml#/components/schemas/SampleProperties'
 | 
					 | 
				
			||||||
  properties:
 | 
					 | 
				
			||||||
    material_id:
 | 
					 | 
				
			||||||
      $ref: 'oas.yaml#/components/schemas/Id'
 | 
					 | 
				
			||||||
    note_id:
 | 
					 | 
				
			||||||
      $ref: 'oas.yaml#/components/schemas/Id'
 | 
					 | 
				
			||||||
    user_id:
 | 
					 | 
				
			||||||
      $ref: 'oas.yaml#/components/schemas/Id'
 | 
					 | 
				
			||||||
Sample:
 | 
					 | 
				
			||||||
  allOf:
 | 
					 | 
				
			||||||
    - $ref: 'oas.yaml#/components/schemas/_Id'
 | 
					 | 
				
			||||||
    - $ref: 'oas.yaml#/components/schemas/Color'
 | 
					 | 
				
			||||||
    - $ref: 'oas.yaml#/components/schemas/SampleProperties'
 | 
					 | 
				
			||||||
  properties:
 | 
					 | 
				
			||||||
    material:
 | 
					 | 
				
			||||||
      $ref: 'oas.yaml#/components/schemas/Material'
 | 
					 | 
				
			||||||
    notes:
 | 
					 | 
				
			||||||
      type: object
 | 
					 | 
				
			||||||
      properties:
 | 
					 | 
				
			||||||
        comments:
 | 
					 | 
				
			||||||
          type: string
 | 
					 | 
				
			||||||
        sample_references:
 | 
					 | 
				
			||||||
          type: array
 | 
					 | 
				
			||||||
          items:
 | 
					 | 
				
			||||||
            $ref: 'oas.yaml#/components/schemas/Id'
 | 
					 | 
				
			||||||
SampleDetail:
 | 
					 | 
				
			||||||
  allOf:
 | 
					 | 
				
			||||||
    - $ref: 'oas.yaml#/components/schemas/_Id'
 | 
					 | 
				
			||||||
    - $ref: 'oas.yaml#/components/schemas/Color'
 | 
					 | 
				
			||||||
    - $ref: 'oas.yaml#/components/schemas/SampleProperties'
 | 
					 | 
				
			||||||
  properties:
 | 
					 | 
				
			||||||
    material:
 | 
					 | 
				
			||||||
      $ref: 'oas.yaml#/components/schemas/Material'
 | 
					 | 
				
			||||||
    notes:
 | 
					 | 
				
			||||||
      type: object
 | 
					 | 
				
			||||||
      properties:
 | 
					 | 
				
			||||||
        comments:
 | 
					 | 
				
			||||||
          type: string
 | 
					 | 
				
			||||||
        sample_references:
 | 
					 | 
				
			||||||
          type: array
 | 
					 | 
				
			||||||
          items:
 | 
					 | 
				
			||||||
            $ref: 'oas.yaml#/components/schemas/Id'
 | 
					 | 
				
			||||||
    conditions:
 | 
					 | 
				
			||||||
      type: array
 | 
					 | 
				
			||||||
      items:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/schemas/Condition'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Material:
 | 
					 | 
				
			||||||
  allOf:
 | 
					 | 
				
			||||||
    - $ref: 'oas.yaml#/components/schemas/_Id'
 | 
					 | 
				
			||||||
  properties:
 | 
					 | 
				
			||||||
    material_numbers:
 | 
					 | 
				
			||||||
      type: array
 | 
					 | 
				
			||||||
      items:
 | 
					 | 
				
			||||||
        type: object
 | 
					 | 
				
			||||||
        allOf:
 | 
					 | 
				
			||||||
          - $ref: 'oas.yaml#/components/schemas/Color'
 | 
					 | 
				
			||||||
        properties:
 | 
					 | 
				
			||||||
          number:
 | 
					 | 
				
			||||||
            type: number
 | 
					 | 
				
			||||||
    material_group:
 | 
					 | 
				
			||||||
      type: string
 | 
					 | 
				
			||||||
    supplier:
 | 
					 | 
				
			||||||
      type: string
 | 
					 | 
				
			||||||
    material_name:
 | 
					 | 
				
			||||||
      type: string
 | 
					 | 
				
			||||||
    mineral:
 | 
					 | 
				
			||||||
      type: number
 | 
					 | 
				
			||||||
    glass_fiber:
 | 
					 | 
				
			||||||
      type: number
 | 
					 | 
				
			||||||
    carbon_fiber:
 | 
					 | 
				
			||||||
      type: number
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Condition:
 | 
					 | 
				
			||||||
  allOf:
 | 
					 | 
				
			||||||
    - $ref: 'oas.yaml#/components/schemas/_Id'
 | 
					 | 
				
			||||||
  properties:
 | 
					 | 
				
			||||||
    sample_id:
 | 
					 | 
				
			||||||
      $ref: 'oas.yaml#/components/schemas/Id'
 | 
					 | 
				
			||||||
    parameters:
 | 
					 | 
				
			||||||
      type: object
 | 
					 | 
				
			||||||
    treatment_template:
 | 
					 | 
				
			||||||
      $ref: 'oas.yaml#/components/schemas/Id'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Measurement:
 | 
					 | 
				
			||||||
  allOf:
 | 
					 | 
				
			||||||
    - $ref: 'oas.yaml#/components/schemas/_Id'
 | 
					 | 
				
			||||||
  properties:
 | 
					 | 
				
			||||||
    condition_id:
 | 
					 | 
				
			||||||
      $ref: 'oas.yaml#/components/schemas/Id'
 | 
					 | 
				
			||||||
    values:
 | 
					 | 
				
			||||||
      type: object
 | 
					 | 
				
			||||||
    measurement_template:
 | 
					 | 
				
			||||||
      $ref: 'oas.yaml#/components/schemas/Id'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Template:
 | 
					 | 
				
			||||||
  allOf:
 | 
					 | 
				
			||||||
    - $ref: 'oas.yaml#/components/schemas/_Id'
 | 
					 | 
				
			||||||
  properties:
 | 
					 | 
				
			||||||
    name:
 | 
					 | 
				
			||||||
      type: string
 | 
					 | 
				
			||||||
    parameters:
 | 
					 | 
				
			||||||
      type: array
 | 
					 | 
				
			||||||
      items:
 | 
					 | 
				
			||||||
        type: object
 | 
					 | 
				
			||||||
        properties:
 | 
					 | 
				
			||||||
          name:
 | 
					 | 
				
			||||||
            type: string
 | 
					 | 
				
			||||||
          range:
 | 
					 | 
				
			||||||
            type: object
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Email:
 | 
					 | 
				
			||||||
  required:
 | 
					 | 
				
			||||||
    - email
 | 
					 | 
				
			||||||
  properties:
 | 
					 | 
				
			||||||
    email:
 | 
					 | 
				
			||||||
      type: string
 | 
					 | 
				
			||||||
      example: john.doe@bosch.com
 | 
					 | 
				
			||||||
User:
 | 
					 | 
				
			||||||
  allOf:
 | 
					 | 
				
			||||||
    - $ref: 'oas.yaml#/components/schemas/_Id'
 | 
					 | 
				
			||||||
    - $ref: 'oas.yaml#/components/schemas/Email'
 | 
					 | 
				
			||||||
  properties:
 | 
					 | 
				
			||||||
    name:
 | 
					 | 
				
			||||||
      type: string
 | 
					 | 
				
			||||||
      example: johndoe
 | 
					 | 
				
			||||||
    levels:
 | 
					 | 
				
			||||||
      type: array
 | 
					 | 
				
			||||||
      items:
 | 
					 | 
				
			||||||
        type: string
 | 
					 | 
				
			||||||
        example: read
 | 
					 | 
				
			||||||
    location:
 | 
					 | 
				
			||||||
      type: string
 | 
					 | 
				
			||||||
      example: Rng
 | 
					 | 
				
			||||||
    device_name:
 | 
					 | 
				
			||||||
      type: string
 | 
					 | 
				
			||||||
      example: Alpha II
 | 
					 | 
				
			||||||
@@ -1,242 +0,0 @@
 | 
				
			|||||||
/template/treatments:
 | 
					 | 
				
			||||||
  get:
 | 
					 | 
				
			||||||
    summary: TODO all available treatment methods
 | 
					 | 
				
			||||||
    description: 'levels: read, write, maintain, dev, admin'
 | 
					 | 
				
			||||||
    tags:
 | 
					 | 
				
			||||||
      - /templates
 | 
					 | 
				
			||||||
    security:
 | 
					 | 
				
			||||||
      - BasicAuth: []
 | 
					 | 
				
			||||||
    responses:
 | 
					 | 
				
			||||||
      200:
 | 
					 | 
				
			||||||
        description: list of treatments
 | 
					 | 
				
			||||||
        content:
 | 
					 | 
				
			||||||
          application/json:
 | 
					 | 
				
			||||||
            schema:
 | 
					 | 
				
			||||||
              type: array
 | 
					 | 
				
			||||||
              items:
 | 
					 | 
				
			||||||
                $ref: 'oas.yaml#/components/schemas/Template'
 | 
					 | 
				
			||||||
              example:
 | 
					 | 
				
			||||||
                name: heat aging
 | 
					 | 
				
			||||||
                parameters:
 | 
					 | 
				
			||||||
                  - name: method
 | 
					 | 
				
			||||||
                    range:
 | 
					 | 
				
			||||||
                      - copper
 | 
					 | 
				
			||||||
      401:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/401'
 | 
					 | 
				
			||||||
      500:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/500'
 | 
					 | 
				
			||||||
/templates/treatment/{name}:
 | 
					 | 
				
			||||||
  parameters:
 | 
					 | 
				
			||||||
    - $ref: 'oas.yaml#/components/parameters/Name'
 | 
					 | 
				
			||||||
  get:
 | 
					 | 
				
			||||||
    summary: TODO treatment method details
 | 
					 | 
				
			||||||
    description: 'levels: read, write, maintain, admin'
 | 
					 | 
				
			||||||
    tags:
 | 
					 | 
				
			||||||
      - /templates
 | 
					 | 
				
			||||||
    security:
 | 
					 | 
				
			||||||
      - BasicAuth: []
 | 
					 | 
				
			||||||
    responses:
 | 
					 | 
				
			||||||
      200:
 | 
					 | 
				
			||||||
        description: treatment details
 | 
					 | 
				
			||||||
        content:
 | 
					 | 
				
			||||||
          application/json:
 | 
					 | 
				
			||||||
            schema:
 | 
					 | 
				
			||||||
              allOf:
 | 
					 | 
				
			||||||
                - $ref: 'oas.yaml#/components/schemas/Template'
 | 
					 | 
				
			||||||
              example:
 | 
					 | 
				
			||||||
                name: heat aging
 | 
					 | 
				
			||||||
                parameters:
 | 
					 | 
				
			||||||
                  - name: method
 | 
					 | 
				
			||||||
                    range:
 | 
					 | 
				
			||||||
                      - copper
 | 
					 | 
				
			||||||
      400:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/400'
 | 
					 | 
				
			||||||
      401:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/401'
 | 
					 | 
				
			||||||
      404:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/404'
 | 
					 | 
				
			||||||
      500:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/500'
 | 
					 | 
				
			||||||
  put:
 | 
					 | 
				
			||||||
    summary: TODO add/change treatment method
 | 
					 | 
				
			||||||
    description: 'levels: maintain, admin'
 | 
					 | 
				
			||||||
    tags:
 | 
					 | 
				
			||||||
      - /templates
 | 
					 | 
				
			||||||
    requestBody:
 | 
					 | 
				
			||||||
      required: true
 | 
					 | 
				
			||||||
      content:
 | 
					 | 
				
			||||||
        application/json:
 | 
					 | 
				
			||||||
          schema:
 | 
					 | 
				
			||||||
            allOf:
 | 
					 | 
				
			||||||
              - $ref: 'oas.yaml#/components/schemas/Template'
 | 
					 | 
				
			||||||
            example:
 | 
					 | 
				
			||||||
              name: heat aging
 | 
					 | 
				
			||||||
              parameters:
 | 
					 | 
				
			||||||
                - name: method
 | 
					 | 
				
			||||||
                  range:
 | 
					 | 
				
			||||||
                    - copper
 | 
					 | 
				
			||||||
    responses:
 | 
					 | 
				
			||||||
      200:
 | 
					 | 
				
			||||||
        description: treatment details
 | 
					 | 
				
			||||||
        content:
 | 
					 | 
				
			||||||
          application/json:
 | 
					 | 
				
			||||||
            schema:
 | 
					 | 
				
			||||||
              allOf:
 | 
					 | 
				
			||||||
                - $ref: 'oas.yaml#/components/schemas/Template'
 | 
					 | 
				
			||||||
              example:
 | 
					 | 
				
			||||||
                name: heat aging
 | 
					 | 
				
			||||||
                parameters:
 | 
					 | 
				
			||||||
                  - name: method
 | 
					 | 
				
			||||||
                    range:
 | 
					 | 
				
			||||||
                      - copper
 | 
					 | 
				
			||||||
      400:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/400'
 | 
					 | 
				
			||||||
      401:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/401'
 | 
					 | 
				
			||||||
      403:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/403'
 | 
					 | 
				
			||||||
      404:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/404'
 | 
					 | 
				
			||||||
      500:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/500'
 | 
					 | 
				
			||||||
  delete:
 | 
					 | 
				
			||||||
    summary: TODO delete treatment method
 | 
					 | 
				
			||||||
    description: 'levels: maintain, admin'
 | 
					 | 
				
			||||||
    tags:
 | 
					 | 
				
			||||||
      - /templates
 | 
					 | 
				
			||||||
    responses:
 | 
					 | 
				
			||||||
      200:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/Ok'
 | 
					 | 
				
			||||||
      400:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/400'
 | 
					 | 
				
			||||||
      401:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/401'
 | 
					 | 
				
			||||||
      403:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/403'
 | 
					 | 
				
			||||||
      404:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/404'
 | 
					 | 
				
			||||||
      500:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/500'
 | 
					 | 
				
			||||||
/template/measurements:
 | 
					 | 
				
			||||||
  get:
 | 
					 | 
				
			||||||
    summary: TODO all available measurement methods
 | 
					 | 
				
			||||||
    description: 'levels: read, write, maintain, dev, admin'
 | 
					 | 
				
			||||||
    tags:
 | 
					 | 
				
			||||||
      - /templates
 | 
					 | 
				
			||||||
    security:
 | 
					 | 
				
			||||||
      - BasicAuth: []
 | 
					 | 
				
			||||||
    responses:
 | 
					 | 
				
			||||||
      200:
 | 
					 | 
				
			||||||
        description: list of measurement methods
 | 
					 | 
				
			||||||
        content:
 | 
					 | 
				
			||||||
          application/json:
 | 
					 | 
				
			||||||
            schema:
 | 
					 | 
				
			||||||
              type: array
 | 
					 | 
				
			||||||
              items:
 | 
					 | 
				
			||||||
                $ref: 'oas.yaml#/components/schemas/Template'
 | 
					 | 
				
			||||||
              example:
 | 
					 | 
				
			||||||
                name: humidity
 | 
					 | 
				
			||||||
                parameters:
 | 
					 | 
				
			||||||
                  - name: kf
 | 
					 | 
				
			||||||
                    range:
 | 
					 | 
				
			||||||
                      min: 0
 | 
					 | 
				
			||||||
                      max: 2
 | 
					 | 
				
			||||||
      401:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/401'
 | 
					 | 
				
			||||||
      500:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/500'
 | 
					 | 
				
			||||||
/templates/measurement/{name}:
 | 
					 | 
				
			||||||
  parameters:
 | 
					 | 
				
			||||||
    - $ref: 'oas.yaml#/components/parameters/Name'
 | 
					 | 
				
			||||||
  get:
 | 
					 | 
				
			||||||
    summary: TODO measurement method details
 | 
					 | 
				
			||||||
    description: 'levels: read, write, maintain, admin'
 | 
					 | 
				
			||||||
    tags:
 | 
					 | 
				
			||||||
      - /templates
 | 
					 | 
				
			||||||
    security:
 | 
					 | 
				
			||||||
      - BasicAuth: []
 | 
					 | 
				
			||||||
    responses:
 | 
					 | 
				
			||||||
      200:
 | 
					 | 
				
			||||||
        description: measurement details
 | 
					 | 
				
			||||||
        content:
 | 
					 | 
				
			||||||
          application/json:
 | 
					 | 
				
			||||||
            schema:
 | 
					 | 
				
			||||||
              allOf:
 | 
					 | 
				
			||||||
                - $ref: 'oas.yaml#/components/schemas/Template'
 | 
					 | 
				
			||||||
              example:
 | 
					 | 
				
			||||||
                name: humidity
 | 
					 | 
				
			||||||
                parameters:
 | 
					 | 
				
			||||||
                  - name: kf
 | 
					 | 
				
			||||||
                    range:
 | 
					 | 
				
			||||||
                      min: 0
 | 
					 | 
				
			||||||
                      max: 2
 | 
					 | 
				
			||||||
      400:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/400'
 | 
					 | 
				
			||||||
      401:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/401'
 | 
					 | 
				
			||||||
      404:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/404'
 | 
					 | 
				
			||||||
      500:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/500'
 | 
					 | 
				
			||||||
  put:
 | 
					 | 
				
			||||||
    summary: TODO add/change measurement method
 | 
					 | 
				
			||||||
    description: 'levels: maintain, admin'
 | 
					 | 
				
			||||||
    tags:
 | 
					 | 
				
			||||||
      - /templates
 | 
					 | 
				
			||||||
    requestBody:
 | 
					 | 
				
			||||||
      required: true
 | 
					 | 
				
			||||||
      content:
 | 
					 | 
				
			||||||
        application/json:
 | 
					 | 
				
			||||||
          schema:
 | 
					 | 
				
			||||||
            allOf:
 | 
					 | 
				
			||||||
              - $ref: 'oas.yaml#/components/schemas/Template'
 | 
					 | 
				
			||||||
            example:
 | 
					 | 
				
			||||||
              name: humidity
 | 
					 | 
				
			||||||
              parameters:
 | 
					 | 
				
			||||||
                - name: kf
 | 
					 | 
				
			||||||
                  range:
 | 
					 | 
				
			||||||
                    min: 0
 | 
					 | 
				
			||||||
                    max: 2
 | 
					 | 
				
			||||||
    responses:
 | 
					 | 
				
			||||||
      200:
 | 
					 | 
				
			||||||
        description: measurement details
 | 
					 | 
				
			||||||
        content:
 | 
					 | 
				
			||||||
          application/json:
 | 
					 | 
				
			||||||
            schema:
 | 
					 | 
				
			||||||
              allOf:
 | 
					 | 
				
			||||||
                - $ref: 'oas.yaml#/components/schemas/Template'
 | 
					 | 
				
			||||||
              example:
 | 
					 | 
				
			||||||
                name: humidity
 | 
					 | 
				
			||||||
                parameters:
 | 
					 | 
				
			||||||
                  - name: kf
 | 
					 | 
				
			||||||
                    range:
 | 
					 | 
				
			||||||
                      min: 0
 | 
					 | 
				
			||||||
                      max: 2
 | 
					 | 
				
			||||||
      400:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/400'
 | 
					 | 
				
			||||||
      401:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/401'
 | 
					 | 
				
			||||||
      403:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/403'
 | 
					 | 
				
			||||||
      404:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/404'
 | 
					 | 
				
			||||||
      500:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/500'
 | 
					 | 
				
			||||||
  delete:
 | 
					 | 
				
			||||||
    summary: TODO delete measurement method
 | 
					 | 
				
			||||||
    description: 'levels: maintain, admin'
 | 
					 | 
				
			||||||
    tags:
 | 
					 | 
				
			||||||
      - /templates
 | 
					 | 
				
			||||||
    responses:
 | 
					 | 
				
			||||||
      200:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/Ok'
 | 
					 | 
				
			||||||
      400:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/400'
 | 
					 | 
				
			||||||
      401:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/401'
 | 
					 | 
				
			||||||
      403:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/403'
 | 
					 | 
				
			||||||
      404:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/404'
 | 
					 | 
				
			||||||
      500:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/500'
 | 
					 | 
				
			||||||
							
								
								
									
										170
									
								
								oas/user.yaml
									
									
									
									
									
								
							
							
						
						
									
										170
									
								
								oas/user.yaml
									
									
									
									
									
								
							@@ -1,170 +0,0 @@
 | 
				
			|||||||
/users:
 | 
					 | 
				
			||||||
  get:
 | 
					 | 
				
			||||||
    summary: TODO lists all users
 | 
					 | 
				
			||||||
    description: 'levels: admin'
 | 
					 | 
				
			||||||
    tags:
 | 
					 | 
				
			||||||
      - /user
 | 
					 | 
				
			||||||
    security:
 | 
					 | 
				
			||||||
      - BasicAuth: []
 | 
					 | 
				
			||||||
    responses:
 | 
					 | 
				
			||||||
      200:
 | 
					 | 
				
			||||||
        description: user API key
 | 
					 | 
				
			||||||
        content:
 | 
					 | 
				
			||||||
          application/json:
 | 
					 | 
				
			||||||
            schema:
 | 
					 | 
				
			||||||
              type: array
 | 
					 | 
				
			||||||
              items:
 | 
					 | 
				
			||||||
                $ref: 'oas.yaml#/components/schemas/User'
 | 
					 | 
				
			||||||
      401:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/401'
 | 
					 | 
				
			||||||
      403:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/403'
 | 
					 | 
				
			||||||
      500:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/500'
 | 
					 | 
				
			||||||
/user/{name}:
 | 
					 | 
				
			||||||
  parameters:
 | 
					 | 
				
			||||||
    - $ref: 'oas.yaml#/components/parameters/Name'
 | 
					 | 
				
			||||||
  get:
 | 
					 | 
				
			||||||
    summary: TODO list user details
 | 
					 | 
				
			||||||
    description: 'levels: read, write, maintain, dev get their own information without a name property specified, level: admin can get any user using the name parameter'
 | 
					 | 
				
			||||||
    tags:
 | 
					 | 
				
			||||||
      - /user
 | 
					 | 
				
			||||||
    security:
 | 
					 | 
				
			||||||
      - BasicAuth: []
 | 
					 | 
				
			||||||
    responses:
 | 
					 | 
				
			||||||
      200:
 | 
					 | 
				
			||||||
        description: user details
 | 
					 | 
				
			||||||
        content:
 | 
					 | 
				
			||||||
          application/json:
 | 
					 | 
				
			||||||
            schema:
 | 
					 | 
				
			||||||
              type: array
 | 
					 | 
				
			||||||
              items:
 | 
					 | 
				
			||||||
                $ref: 'oas.yaml#/components/schemas/User'
 | 
					 | 
				
			||||||
      400:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/400'
 | 
					 | 
				
			||||||
      401:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/401'
 | 
					 | 
				
			||||||
      403:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/403'
 | 
					 | 
				
			||||||
      404:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/404'
 | 
					 | 
				
			||||||
      500:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/500'
 | 
					 | 
				
			||||||
  put:
 | 
					 | 
				
			||||||
    summary: TODO change user details
 | 
					 | 
				
			||||||
    description: 'levels: read, write, maintain, dev can change their own information (except level) without a name property specified, level: admin can change any user using the name parameter'
 | 
					 | 
				
			||||||
    tags:
 | 
					 | 
				
			||||||
      - /user
 | 
					 | 
				
			||||||
    requestBody:
 | 
					 | 
				
			||||||
      required: true
 | 
					 | 
				
			||||||
      content:
 | 
					 | 
				
			||||||
        application/json:
 | 
					 | 
				
			||||||
          schema:
 | 
					 | 
				
			||||||
            $ref: 'oas.yaml#/components/schemas/User'
 | 
					 | 
				
			||||||
    responses:
 | 
					 | 
				
			||||||
      200:
 | 
					 | 
				
			||||||
        description: user details
 | 
					 | 
				
			||||||
        content:
 | 
					 | 
				
			||||||
          application/json:
 | 
					 | 
				
			||||||
            schema:
 | 
					 | 
				
			||||||
              type: array
 | 
					 | 
				
			||||||
              items:
 | 
					 | 
				
			||||||
                $ref: 'oas.yaml#/components/schemas/User'
 | 
					 | 
				
			||||||
      400:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/400'
 | 
					 | 
				
			||||||
      401:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/401'
 | 
					 | 
				
			||||||
      403:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/403'
 | 
					 | 
				
			||||||
      404:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/404'
 | 
					 | 
				
			||||||
      500:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/500'
 | 
					 | 
				
			||||||
  delete:
 | 
					 | 
				
			||||||
    summary: TODO delete user
 | 
					 | 
				
			||||||
    description: 'levels: read, write, maintain, dev can delete their own account, level: admin can delete any user using the name parameter'
 | 
					 | 
				
			||||||
    tags:
 | 
					 | 
				
			||||||
      - /user
 | 
					 | 
				
			||||||
    responses:
 | 
					 | 
				
			||||||
      200:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/Ok'
 | 
					 | 
				
			||||||
      400:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/400'
 | 
					 | 
				
			||||||
      401:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/401'
 | 
					 | 
				
			||||||
      403:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/403'
 | 
					 | 
				
			||||||
      404:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/404'
 | 
					 | 
				
			||||||
      500:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/500'
 | 
					 | 
				
			||||||
/user/key:
 | 
					 | 
				
			||||||
  get:
 | 
					 | 
				
			||||||
    summary: TODO get API key for the user
 | 
					 | 
				
			||||||
    description: 'levels: read, write, maintain, dev, admin'
 | 
					 | 
				
			||||||
    tags:
 | 
					 | 
				
			||||||
      - /user
 | 
					 | 
				
			||||||
    security:
 | 
					 | 
				
			||||||
      - BasicAuth: []
 | 
					 | 
				
			||||||
    responses:
 | 
					 | 
				
			||||||
      200:
 | 
					 | 
				
			||||||
        description: user details
 | 
					 | 
				
			||||||
        content:
 | 
					 | 
				
			||||||
          application/json:
 | 
					 | 
				
			||||||
            schema:
 | 
					 | 
				
			||||||
              $ref: 'oas.yaml#/components/schemas/User'
 | 
					 | 
				
			||||||
      401:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/401'
 | 
					 | 
				
			||||||
      500:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/500'
 | 
					 | 
				
			||||||
/user/new:
 | 
					 | 
				
			||||||
  post:
 | 
					 | 
				
			||||||
    summary: TODO add new user
 | 
					 | 
				
			||||||
    description: 'levels: admin'
 | 
					 | 
				
			||||||
    tags:
 | 
					 | 
				
			||||||
      - /user
 | 
					 | 
				
			||||||
    security:
 | 
					 | 
				
			||||||
      - BasicAuth: []
 | 
					 | 
				
			||||||
    requestBody:
 | 
					 | 
				
			||||||
      required: true
 | 
					 | 
				
			||||||
      content:
 | 
					 | 
				
			||||||
        application/json:
 | 
					 | 
				
			||||||
          schema:
 | 
					 | 
				
			||||||
            $ref: 'oas.yaml#/components/schemas/User'
 | 
					 | 
				
			||||||
    responses:
 | 
					 | 
				
			||||||
      200:
 | 
					 | 
				
			||||||
        description: user details
 | 
					 | 
				
			||||||
        content:
 | 
					 | 
				
			||||||
          application/json:
 | 
					 | 
				
			||||||
            schema:
 | 
					 | 
				
			||||||
              type: array
 | 
					 | 
				
			||||||
              items:
 | 
					 | 
				
			||||||
                $ref: 'oas.yaml#/components/schemas/User'
 | 
					 | 
				
			||||||
      400:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/400'
 | 
					 | 
				
			||||||
      401:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/401'
 | 
					 | 
				
			||||||
      403:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/403'
 | 
					 | 
				
			||||||
      500:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/500'
 | 
					 | 
				
			||||||
/user/passreset:
 | 
					 | 
				
			||||||
  post:
 | 
					 | 
				
			||||||
    summary: TODO reset password and send mail to restore
 | 
					 | 
				
			||||||
    tags:
 | 
					 | 
				
			||||||
      - /user
 | 
					 | 
				
			||||||
    security: []
 | 
					 | 
				
			||||||
    requestBody:
 | 
					 | 
				
			||||||
      required: true
 | 
					 | 
				
			||||||
      description: mail saved in user profile to provide authentication
 | 
					 | 
				
			||||||
      content:
 | 
					 | 
				
			||||||
        application/json:
 | 
					 | 
				
			||||||
          schema:
 | 
					 | 
				
			||||||
            $ref: 'oas.yaml#/components/schemas/Email'
 | 
					 | 
				
			||||||
    responses:
 | 
					 | 
				
			||||||
      200:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/Ok'
 | 
					 | 
				
			||||||
      401:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/401'
 | 
					 | 
				
			||||||
      500:
 | 
					 | 
				
			||||||
        $ref: 'oas.yaml#/components/responses/500'
 | 
					 | 
				
			||||||
							
								
								
									
										284
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										284
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							@@ -32,6 +32,49 @@
 | 
				
			|||||||
        "js-tokens": "^4.0.0"
 | 
					        "js-tokens": "^4.0.0"
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    "@hapi/address": {
 | 
				
			||||||
 | 
					      "version": "4.0.1",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/@hapi/address/-/address-4.0.1.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-0oEP5UiyV4f3d6cBL8F3Z5S7iWSX39Knnl0lY8i+6gfmmIBj44JCBNtcMgwyS+5v7j3VYavNay0NFHDS+UGQcw==",
 | 
				
			||||||
 | 
					      "requires": {
 | 
				
			||||||
 | 
					        "@hapi/hoek": "^9.0.0"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "@hapi/formula": {
 | 
				
			||||||
 | 
					      "version": "2.0.0",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/@hapi/formula/-/formula-2.0.0.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-V87P8fv7PI0LH7LiVi8Lkf3x+KCO7pQozXRssAHNXXL9L1K+uyu4XypLXwxqVDKgyQai6qj3/KteNlrqDx4W5A=="
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "@hapi/hoek": {
 | 
				
			||||||
 | 
					      "version": "9.0.4",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.0.4.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-EwaJS7RjoXUZ2cXXKZZxZqieGtc7RbvQhUy8FwDoMQtxWVi14tFjeFCYPZAM1mBCpOpiBpyaZbb9NeHc7eGKgw=="
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "@hapi/joi": {
 | 
				
			||||||
 | 
					      "version": "17.1.1",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/@hapi/joi/-/joi-17.1.1.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-p4DKeZAoeZW4g3u7ZeRo+vCDuSDgSvtsB/NpfjXEHTUjSeINAi/RrVOWiVQ1isaoLzMvFEhe8n5065mQq1AdQg==",
 | 
				
			||||||
 | 
					      "requires": {
 | 
				
			||||||
 | 
					        "@hapi/address": "^4.0.1",
 | 
				
			||||||
 | 
					        "@hapi/formula": "^2.0.0",
 | 
				
			||||||
 | 
					        "@hapi/hoek": "^9.0.0",
 | 
				
			||||||
 | 
					        "@hapi/pinpoint": "^2.0.0",
 | 
				
			||||||
 | 
					        "@hapi/topo": "^5.0.0"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "@hapi/pinpoint": {
 | 
				
			||||||
 | 
					      "version": "2.0.0",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/@hapi/pinpoint/-/pinpoint-2.0.0.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-vzXR5MY7n4XeIvLpfl3HtE3coZYO4raKXW766R6DZw/6aLqR26iuZ109K7a0NtF2Db0jxqh7xz2AxkUwpUFybw=="
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "@hapi/topo": {
 | 
				
			||||||
 | 
					      "version": "5.0.0",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-5.0.0.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-tFJlT47db0kMqVm3H4nQYgn6Pwg10GTZHb1pwmSiv1K4ks6drQOtfEF5ZnPjkvC+y4/bUPHK+bc87QvLcL+WMw==",
 | 
				
			||||||
 | 
					      "requires": {
 | 
				
			||||||
 | 
					        "@hapi/hoek": "^9.0.0"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    "@jsdevtools/ono": {
 | 
					    "@jsdevtools/ono": {
 | 
				
			||||||
      "version": "7.1.2",
 | 
					      "version": "7.1.2",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/@jsdevtools/ono/-/ono-7.1.2.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/@jsdevtools/ono/-/ono-7.1.2.tgz",
 | 
				
			||||||
@@ -50,21 +93,102 @@
 | 
				
			|||||||
        "defer-to-connect": "^1.0.1"
 | 
					        "defer-to-connect": "^1.0.1"
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    "@types/bcrypt": {
 | 
				
			||||||
 | 
					      "version": "3.0.0",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/@types/bcrypt/-/bcrypt-3.0.0.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-nohgNyv+1ViVcubKBh0+XiNJ3dO8nYu///9aJ4cgSqv70gBL+94SNy/iC2NLzKPT2Zt/QavrOkBVbZRLZmw6NQ=="
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "@types/body-parser": {
 | 
				
			||||||
 | 
					      "version": "1.19.0",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.0.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-W98JrE0j2K78swW4ukqMleo8R7h/pFETjM2DQ90MF6XK2i4LO4W3gQ71Lt4w3bfm2EvVSyWHplECvB5sK22yFQ==",
 | 
				
			||||||
 | 
					      "requires": {
 | 
				
			||||||
 | 
					        "@types/connect": "*",
 | 
				
			||||||
 | 
					        "@types/node": "*"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "@types/bson": {
 | 
				
			||||||
 | 
					      "version": "4.0.2",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/@types/bson/-/bson-4.0.2.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-+uWmsejEHfmSjyyM/LkrP0orfE2m5Mx9Xel4tXNeqi1ldK5XMQcDsFkBmLDtuyKUbxj2jGDo0H240fbCRJZo7Q==",
 | 
				
			||||||
 | 
					      "requires": {
 | 
				
			||||||
 | 
					        "@types/node": "*"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    "@types/color-name": {
 | 
					    "@types/color-name": {
 | 
				
			||||||
      "version": "1.1.1",
 | 
					      "version": "1.1.1",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz",
 | 
				
			||||||
      "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ=="
 | 
					      "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ=="
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    "@types/connect": {
 | 
				
			||||||
 | 
					      "version": "3.4.33",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.33.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-2+FrkXY4zllzTNfJth7jOqEHC+enpLeGslEhpnTAkg21GkRrWV4SsAtqchtT4YS9/nODBU2/ZfsBY2X4J/dX7A==",
 | 
				
			||||||
 | 
					      "requires": {
 | 
				
			||||||
 | 
					        "@types/node": "*"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "@types/express-serve-static-core": {
 | 
				
			||||||
 | 
					      "version": "4.17.5",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.5.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-578YH5Lt88AKoADy0b2jQGwJtrBxezXtVe/MBqWXKZpqx91SnC0pVkVCcxcytz3lWW+cHBYDi3Ysh0WXc+rAYw==",
 | 
				
			||||||
 | 
					      "requires": {
 | 
				
			||||||
 | 
					        "@types/node": "*",
 | 
				
			||||||
 | 
					        "@types/range-parser": "*"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "@types/mime": {
 | 
				
			||||||
 | 
					      "version": "2.0.1",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/@types/mime/-/mime-2.0.1.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-FwI9gX75FgVBJ7ywgnq/P7tw+/o1GUbtP0KzbtusLigAOgIgNISRK0ZPl4qertvXSIE8YbsVJueQ90cDt9YYyw=="
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    "@types/mocha": {
 | 
					    "@types/mocha": {
 | 
				
			||||||
      "version": "5.2.7",
 | 
					      "version": "5.2.7",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-5.2.7.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-5.2.7.tgz",
 | 
				
			||||||
      "integrity": "sha512-NYrtPht0wGzhwe9+/idPaBB+TqkY9AhTvOLMkThm0IoEfLaiVQZwBwyJ5puCkO3AUCWrmcoePjp2mbFocKy4SQ=="
 | 
					      "integrity": "sha512-NYrtPht0wGzhwe9+/idPaBB+TqkY9AhTvOLMkThm0IoEfLaiVQZwBwyJ5puCkO3AUCWrmcoePjp2mbFocKy4SQ=="
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    "@types/mongodb": {
 | 
				
			||||||
 | 
					      "version": "3.5.10",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/@types/mongodb/-/mongodb-3.5.10.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-6NkJNfFdFa/njBvN/9eAfq78bWUnapkdR3JbWGGpd7U71PjgKweA4Tlag8psi2mqm973vBYVTD1oc1u0lzRcig==",
 | 
				
			||||||
 | 
					      "requires": {
 | 
				
			||||||
 | 
					        "@types/bson": "*",
 | 
				
			||||||
 | 
					        "@types/node": "*"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "@types/mongoose": {
 | 
				
			||||||
 | 
					      "version": "5.7.12",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/@types/mongoose/-/mongoose-5.7.12.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-yzLJk3cdSwuMXaIacUCWUb8m960YcgnID7S4ZPOOgzT39aSC46670TuunN+ajDio7OUcGG4mGg8eOGs2Z6VmrA==",
 | 
				
			||||||
 | 
					      "requires": {
 | 
				
			||||||
 | 
					        "@types/mongodb": "*",
 | 
				
			||||||
 | 
					        "@types/node": "*"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    "@types/node": {
 | 
					    "@types/node": {
 | 
				
			||||||
      "version": "13.1.6",
 | 
					      "version": "13.1.6",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/@types/node/-/node-13.1.6.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/@types/node/-/node-13.1.6.tgz",
 | 
				
			||||||
      "integrity": "sha512-Jg1F+bmxcpENHP23sVKkNuU3uaxPnsBMW0cLjleiikFKomJQbsn0Cqk2yDvQArqzZN6ABfBkZ0To7pQ8sLdWDg=="
 | 
					      "integrity": "sha512-Jg1F+bmxcpENHP23sVKkNuU3uaxPnsBMW0cLjleiikFKomJQbsn0Cqk2yDvQArqzZN6ABfBkZ0To7pQ8sLdWDg=="
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    "@types/qs": {
 | 
				
			||||||
 | 
					      "version": "6.9.1",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.1.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-lhbQXx9HKZAPgBkISrBcmAcMpZsmpe/Cd/hY7LGZS5OfkySUBItnPZHgQPssWYUET8elF+yCFBbP1Q0RZPTdaw=="
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "@types/range-parser": {
 | 
				
			||||||
 | 
					      "version": "1.2.3",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.3.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA=="
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "@types/serve-static": {
 | 
				
			||||||
 | 
					      "version": "1.13.3",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.3.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-oprSwp094zOglVrXdlo/4bAHtKTAxX6VT8FOZlBKrmyLbNvE1zxZyJ6yikMVtHIvwP45+ZQGJn+FdXGKTozq0g==",
 | 
				
			||||||
 | 
					      "requires": {
 | 
				
			||||||
 | 
					        "@types/express-serve-static-core": "*",
 | 
				
			||||||
 | 
					        "@types/mime": "*"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    "abbrev": {
 | 
					    "abbrev": {
 | 
				
			||||||
      "version": "1.1.1",
 | 
					      "version": "1.1.1",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
 | 
				
			||||||
@@ -160,11 +284,32 @@
 | 
				
			|||||||
      "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=",
 | 
					      "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=",
 | 
				
			||||||
      "dev": true
 | 
					      "dev": true
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    "axios": {
 | 
				
			||||||
 | 
					      "version": "0.19.2",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/axios/-/axios-0.19.2.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-fjgm5MvRHLhx+osE2xoekY70AhARk3a6hkN+3Io1jc00jtquGvxYlKlsFUhmUET0V5te6CcZI7lcv2Ym61mjHA==",
 | 
				
			||||||
 | 
					      "requires": {
 | 
				
			||||||
 | 
					        "follow-redirects": "1.5.10"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    "balanced-match": {
 | 
					    "balanced-match": {
 | 
				
			||||||
      "version": "1.0.0",
 | 
					      "version": "1.0.0",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
 | 
				
			||||||
      "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
 | 
					      "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    "basic-auth": {
 | 
				
			||||||
 | 
					      "version": "2.0.1",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==",
 | 
				
			||||||
 | 
					      "requires": {
 | 
				
			||||||
 | 
					        "safe-buffer": "5.1.2"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "bcryptjs": {
 | 
				
			||||||
 | 
					      "version": "2.4.3",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-2.4.3.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha1-mrVie5PmBiH/fNrF2pczAn3x0Ms="
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    "binary-extensions": {
 | 
					    "binary-extensions": {
 | 
				
			||||||
      "version": "2.0.0",
 | 
					      "version": "2.0.0",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.0.0.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.0.0.tgz",
 | 
				
			||||||
@@ -514,6 +659,11 @@
 | 
				
			|||||||
        "safe-buffer": "5.1.2"
 | 
					        "safe-buffer": "5.1.2"
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    "content-filter": {
 | 
				
			||||||
 | 
					      "version": "1.1.2",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/content-filter/-/content-filter-1.1.2.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-VaZ4Y7h776r0v2WxWqu3iatjYI6/N0msXK8O1ymtkFWbSvaFoCePksS8U60BS6dUMZeAlqhN09SuM7ghdzRP1Q=="
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    "content-type": {
 | 
					    "content-type": {
 | 
				
			||||||
      "version": "1.0.4",
 | 
					      "version": "1.0.4",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz",
 | 
				
			||||||
@@ -645,9 +795,9 @@
 | 
				
			|||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "es-abstract": {
 | 
					    "es-abstract": {
 | 
				
			||||||
      "version": "1.17.0",
 | 
					      "version": "1.17.5",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.0.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.5.tgz",
 | 
				
			||||||
      "integrity": "sha512-yYkE07YF+6SIBmg1MsJ9dlub5L48Ek7X0qz+c/CPCHS9EBXfESorzng4cJQjJW5/pB6vDF41u7F8vUhLVDqIug==",
 | 
					      "integrity": "sha512-BR9auzDbySxOcfog0tLECW8l28eRGpDpU3Dm3Hp4q/N+VtLTmyj4EUN088XZWQDW/hzj6sYRDXeOFsaAODKvpg==",
 | 
				
			||||||
      "dev": true,
 | 
					      "dev": true,
 | 
				
			||||||
      "requires": {
 | 
					      "requires": {
 | 
				
			||||||
        "es-to-primitive": "^1.2.1",
 | 
					        "es-to-primitive": "^1.2.1",
 | 
				
			||||||
@@ -787,6 +937,24 @@
 | 
				
			|||||||
        "is-buffer": "~2.0.3"
 | 
					        "is-buffer": "~2.0.3"
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    "follow-redirects": {
 | 
				
			||||||
 | 
					      "version": "1.5.10",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.10.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==",
 | 
				
			||||||
 | 
					      "requires": {
 | 
				
			||||||
 | 
					        "debug": "=3.1.0"
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      "dependencies": {
 | 
				
			||||||
 | 
					        "debug": {
 | 
				
			||||||
 | 
					          "version": "3.1.0",
 | 
				
			||||||
 | 
					          "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
 | 
				
			||||||
 | 
					          "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
 | 
				
			||||||
 | 
					          "requires": {
 | 
				
			||||||
 | 
					            "ms": "2.0.0"
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    "form-data": {
 | 
					    "form-data": {
 | 
				
			||||||
      "version": "2.5.1",
 | 
					      "version": "2.5.1",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.1.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.1.tgz",
 | 
				
			||||||
@@ -1181,12 +1349,12 @@
 | 
				
			|||||||
      "dev": true
 | 
					      "dev": true
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "log-symbols": {
 | 
					    "log-symbols": {
 | 
				
			||||||
      "version": "2.2.0",
 | 
					      "version": "3.0.0",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-3.0.0.tgz",
 | 
				
			||||||
      "integrity": "sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==",
 | 
					      "integrity": "sha512-dSkNGuI7iG3mfvDzUuYZyvk5dD9ocYCYzNU6CYDE6+Xqd+gwme6Z00NS3dUh8mq/73HaEtT7m6W+yUPtU6BZnQ==",
 | 
				
			||||||
      "dev": true,
 | 
					      "dev": true,
 | 
				
			||||||
      "requires": {
 | 
					      "requires": {
 | 
				
			||||||
        "chalk": "^2.0.1"
 | 
					        "chalk": "^2.4.2"
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "lowercase-keys": {
 | 
					    "lowercase-keys": {
 | 
				
			||||||
@@ -1275,9 +1443,9 @@
 | 
				
			|||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "mocha": {
 | 
					    "mocha": {
 | 
				
			||||||
      "version": "7.0.0",
 | 
					      "version": "7.1.2",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/mocha/-/mocha-7.0.0.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/mocha/-/mocha-7.1.2.tgz",
 | 
				
			||||||
      "integrity": "sha512-CirsOPbO3jU86YKjjMzFLcXIb5YiGLUrjrXFHoJ3e2z9vWiaZVCZQ2+gtRGMPWF+nFhN6AWwLM/juzAQ6KRkbA==",
 | 
					      "integrity": "sha512-o96kdRKMKI3E8U0bjnfqW4QMk12MwZ4mhdBTf+B5a1q9+aq2HRnj+3ZdJu0B/ZhJeK78MgYuv6L8d/rA5AeBJA==",
 | 
				
			||||||
      "dev": true,
 | 
					      "dev": true,
 | 
				
			||||||
      "requires": {
 | 
					      "requires": {
 | 
				
			||||||
        "ansi-colors": "3.2.3",
 | 
					        "ansi-colors": "3.2.3",
 | 
				
			||||||
@@ -1291,9 +1459,9 @@
 | 
				
			|||||||
        "growl": "1.10.5",
 | 
					        "growl": "1.10.5",
 | 
				
			||||||
        "he": "1.2.0",
 | 
					        "he": "1.2.0",
 | 
				
			||||||
        "js-yaml": "3.13.1",
 | 
					        "js-yaml": "3.13.1",
 | 
				
			||||||
        "log-symbols": "2.2.0",
 | 
					        "log-symbols": "3.0.0",
 | 
				
			||||||
        "minimatch": "3.0.4",
 | 
					        "minimatch": "3.0.4",
 | 
				
			||||||
        "mkdirp": "0.5.1",
 | 
					        "mkdirp": "0.5.5",
 | 
				
			||||||
        "ms": "2.1.1",
 | 
					        "ms": "2.1.1",
 | 
				
			||||||
        "node-environment-flags": "1.0.6",
 | 
					        "node-environment-flags": "1.0.6",
 | 
				
			||||||
        "object.assign": "4.1.0",
 | 
					        "object.assign": "4.1.0",
 | 
				
			||||||
@@ -1301,8 +1469,8 @@
 | 
				
			|||||||
        "supports-color": "6.0.0",
 | 
					        "supports-color": "6.0.0",
 | 
				
			||||||
        "which": "1.3.1",
 | 
					        "which": "1.3.1",
 | 
				
			||||||
        "wide-align": "1.1.3",
 | 
					        "wide-align": "1.1.3",
 | 
				
			||||||
        "yargs": "13.3.0",
 | 
					        "yargs": "13.3.2",
 | 
				
			||||||
        "yargs-parser": "13.1.1",
 | 
					        "yargs-parser": "13.1.2",
 | 
				
			||||||
        "yargs-unparser": "1.6.0"
 | 
					        "yargs-unparser": "1.6.0"
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
      "dependencies": {
 | 
					      "dependencies": {
 | 
				
			||||||
@@ -1351,21 +1519,6 @@
 | 
				
			|||||||
            "path-is-absolute": "^1.0.0"
 | 
					            "path-is-absolute": "^1.0.0"
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        "minimist": {
 | 
					 | 
				
			||||||
          "version": "0.0.8",
 | 
					 | 
				
			||||||
          "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
 | 
					 | 
				
			||||||
          "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=",
 | 
					 | 
				
			||||||
          "dev": true
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
        "mkdirp": {
 | 
					 | 
				
			||||||
          "version": "0.5.1",
 | 
					 | 
				
			||||||
          "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
 | 
					 | 
				
			||||||
          "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
 | 
					 | 
				
			||||||
          "dev": true,
 | 
					 | 
				
			||||||
          "requires": {
 | 
					 | 
				
			||||||
            "minimist": "0.0.8"
 | 
					 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
        "ms": {
 | 
					        "ms": {
 | 
				
			||||||
          "version": "2.1.1",
 | 
					          "version": "2.1.1",
 | 
				
			||||||
          "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
 | 
					          "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
 | 
				
			||||||
@@ -1392,6 +1545,11 @@
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    "mongo-sanitize": {
 | 
				
			||||||
 | 
					      "version": "1.1.0",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/mongo-sanitize/-/mongo-sanitize-1.1.0.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-6gB9AiJD+om2eZLxaPKIP5Q8P3Fr+s+17rVWso7hU0+MAzmIvIMlgTYuyvalDLTtE/p0gczcvJ8A3pbN1XmQ/A=="
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    "mongodb": {
 | 
					    "mongodb": {
 | 
				
			||||||
      "version": "3.4.1",
 | 
					      "version": "3.4.1",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.4.1.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.4.1.tgz",
 | 
				
			||||||
@@ -1586,9 +1744,9 @@
 | 
				
			|||||||
      "integrity": "sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw=="
 | 
					      "integrity": "sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw=="
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "p-limit": {
 | 
					    "p-limit": {
 | 
				
			||||||
      "version": "2.2.2",
 | 
					      "version": "2.3.0",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.2.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
 | 
				
			||||||
      "integrity": "sha512-WGR+xHecKTr7EbUEhyLSh5Dube9JtdiG78ufaeLxTgpudf/20KqyMioIUZJAezlTIi6evxuoUs9YXc11cU+yzQ==",
 | 
					      "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
 | 
				
			||||||
      "dev": true,
 | 
					      "dev": true,
 | 
				
			||||||
      "requires": {
 | 
					      "requires": {
 | 
				
			||||||
        "p-try": "^2.0.0"
 | 
					        "p-try": "^2.0.0"
 | 
				
			||||||
@@ -2009,24 +2167,46 @@
 | 
				
			|||||||
        "strip-ansi": "^4.0.0"
 | 
					        "strip-ansi": "^4.0.0"
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "string.prototype.trimleft": {
 | 
					    "string.prototype.trimend": {
 | 
				
			||||||
      "version": "2.1.1",
 | 
					      "version": "1.0.1",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.1.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz",
 | 
				
			||||||
      "integrity": "sha512-iu2AGd3PuP5Rp7x2kEZCrB2Nf41ehzh+goo8TV7z8/XDBbsvc6HQIlUl9RjkZ4oyrW1XM5UwlGl1oVEaDjg6Ag==",
 | 
					      "integrity": "sha512-LRPxFUaTtpqYsTeNKaFOw3R4bxIzWOnbQ837QfBylo8jIxtcbK/A/sMV7Q+OAV/vWo+7s25pOE10KYSjaSO06g==",
 | 
				
			||||||
      "dev": true,
 | 
					      "dev": true,
 | 
				
			||||||
      "requires": {
 | 
					      "requires": {
 | 
				
			||||||
        "define-properties": "^1.1.3",
 | 
					        "define-properties": "^1.1.3",
 | 
				
			||||||
        "function-bind": "^1.1.1"
 | 
					        "es-abstract": "^1.17.5"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "string.prototype.trimleft": {
 | 
				
			||||||
 | 
					      "version": "2.1.2",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.2.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-gCA0tza1JBvqr3bfAIFJGqfdRTyPae82+KTnm3coDXkZN9wnuW3HjGgN386D7hfv5CHQYCI022/rJPVlqXyHSw==",
 | 
				
			||||||
 | 
					      "dev": true,
 | 
				
			||||||
 | 
					      "requires": {
 | 
				
			||||||
 | 
					        "define-properties": "^1.1.3",
 | 
				
			||||||
 | 
					        "es-abstract": "^1.17.5",
 | 
				
			||||||
 | 
					        "string.prototype.trimstart": "^1.0.0"
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "string.prototype.trimright": {
 | 
					    "string.prototype.trimright": {
 | 
				
			||||||
      "version": "2.1.1",
 | 
					      "version": "2.1.2",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.1.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.2.tgz",
 | 
				
			||||||
      "integrity": "sha512-qFvWL3/+QIgZXVmJBfpHmxLB7xsUXz6HsUmP8+5dRaC3Q7oKUv9Vo6aMCRZC1smrtyECFsIT30PqBJ1gTjAs+g==",
 | 
					      "integrity": "sha512-ZNRQ7sY3KroTaYjRS6EbNiiHrOkjihL9aQE/8gfQ4DtAC/aEBRHFJa44OmoWxGGqXuJlfKkZW4WcXErGr+9ZFg==",
 | 
				
			||||||
      "dev": true,
 | 
					      "dev": true,
 | 
				
			||||||
      "requires": {
 | 
					      "requires": {
 | 
				
			||||||
        "define-properties": "^1.1.3",
 | 
					        "define-properties": "^1.1.3",
 | 
				
			||||||
        "function-bind": "^1.1.1"
 | 
					        "es-abstract": "^1.17.5",
 | 
				
			||||||
 | 
					        "string.prototype.trimend": "^1.0.0"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "string.prototype.trimstart": {
 | 
				
			||||||
 | 
					      "version": "1.0.1",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.1.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-XxZn+QpvrBI1FOcg6dIpxUPgWCPuNXvMD72aaRaUQv1eD4e/Qy8i/hFTe0BUmD60p/QA6bh1avmuPTfNjqVWRw==",
 | 
				
			||||||
 | 
					      "dev": true,
 | 
				
			||||||
 | 
					      "requires": {
 | 
				
			||||||
 | 
					        "define-properties": "^1.1.3",
 | 
				
			||||||
 | 
					        "es-abstract": "^1.17.5"
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "string_decoder": {
 | 
					    "string_decoder": {
 | 
				
			||||||
@@ -2459,9 +2639,9 @@
 | 
				
			|||||||
      "dev": true
 | 
					      "dev": true
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "yargs": {
 | 
					    "yargs": {
 | 
				
			||||||
      "version": "13.3.0",
 | 
					      "version": "13.3.2",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.0.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz",
 | 
				
			||||||
      "integrity": "sha512-2eehun/8ALW8TLoIl7MVaRUrg+yCnenu8B4kBlRxj3GJGDKU1Og7sMXPNm1BYyM1DOJmTZ4YeN/Nwxv+8XJsUA==",
 | 
					      "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==",
 | 
				
			||||||
      "dev": true,
 | 
					      "dev": true,
 | 
				
			||||||
      "requires": {
 | 
					      "requires": {
 | 
				
			||||||
        "cliui": "^5.0.0",
 | 
					        "cliui": "^5.0.0",
 | 
				
			||||||
@@ -2473,7 +2653,7 @@
 | 
				
			|||||||
        "string-width": "^3.0.0",
 | 
					        "string-width": "^3.0.0",
 | 
				
			||||||
        "which-module": "^2.0.0",
 | 
					        "which-module": "^2.0.0",
 | 
				
			||||||
        "y18n": "^4.0.0",
 | 
					        "y18n": "^4.0.0",
 | 
				
			||||||
        "yargs-parser": "^13.1.1"
 | 
					        "yargs-parser": "^13.1.2"
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
      "dependencies": {
 | 
					      "dependencies": {
 | 
				
			||||||
        "ansi-regex": {
 | 
					        "ansi-regex": {
 | 
				
			||||||
@@ -2505,21 +2685,13 @@
 | 
				
			|||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "yargs-parser": {
 | 
					    "yargs-parser": {
 | 
				
			||||||
      "version": "13.1.1",
 | 
					      "version": "13.1.2",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.1.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz",
 | 
				
			||||||
      "integrity": "sha512-oVAVsHz6uFrg3XQheFII8ESO2ssAf9luWuAd6Wexsu4F3OtIW0o8IribPXYrD4WC24LWtPrJlGy87y5udK+dxQ==",
 | 
					      "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==",
 | 
				
			||||||
      "dev": true,
 | 
					      "dev": true,
 | 
				
			||||||
      "requires": {
 | 
					      "requires": {
 | 
				
			||||||
        "camelcase": "^5.0.0",
 | 
					        "camelcase": "^5.0.0",
 | 
				
			||||||
        "decamelize": "^1.2.0"
 | 
					        "decamelize": "^1.2.0"
 | 
				
			||||||
      },
 | 
					 | 
				
			||||||
      "dependencies": {
 | 
					 | 
				
			||||||
        "camelcase": {
 | 
					 | 
				
			||||||
          "version": "5.3.1",
 | 
					 | 
				
			||||||
          "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
 | 
					 | 
				
			||||||
          "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
 | 
					 | 
				
			||||||
          "dev": true
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "yargs-unparser": {
 | 
					    "yargs-unparser": {
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										18
									
								
								package.json
									
									
									
									
									
								
							
							
						
						
									
										18
									
								
								package.json
									
									
									
									
									
								
							@@ -4,8 +4,9 @@
 | 
				
			|||||||
  "description": "API for the digital fingerprint of plastics mongodb",
 | 
					  "description": "API for the digital fingerprint of plastics mongodb",
 | 
				
			||||||
  "main": "index.js",
 | 
					  "main": "index.js",
 | 
				
			||||||
  "scripts": {
 | 
					  "scripts": {
 | 
				
			||||||
 | 
					    "tsc": "tsc",
 | 
				
			||||||
    "test": "mocha dist/**/**.spec.js",
 | 
					    "test": "mocha dist/**/**.spec.js",
 | 
				
			||||||
    "start": "tsc && node dist/index.js",
 | 
					    "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\""
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  "keywords": [],
 | 
					  "keywords": [],
 | 
				
			||||||
@@ -13,11 +14,24 @@
 | 
				
			|||||||
  "license": "ISC",
 | 
					  "license": "ISC",
 | 
				
			||||||
  "dependencies": {
 | 
					  "dependencies": {
 | 
				
			||||||
    "@apidevtools/json-schema-ref-parser": "^8.0.0",
 | 
					    "@apidevtools/json-schema-ref-parser": "^8.0.0",
 | 
				
			||||||
 | 
					    "@hapi/joi": "^17.1.1",
 | 
				
			||||||
 | 
					    "@types/bcrypt": "^3.0.0",
 | 
				
			||||||
 | 
					    "@types/body-parser": "^1.19.0",
 | 
				
			||||||
 | 
					    "@types/express-serve-static-core": "^4.17.5",
 | 
				
			||||||
    "@types/mocha": "^5.2.7",
 | 
					    "@types/mocha": "^5.2.7",
 | 
				
			||||||
 | 
					    "@types/mongoose": "^5.7.12",
 | 
				
			||||||
    "@types/node": "^13.1.6",
 | 
					    "@types/node": "^13.1.6",
 | 
				
			||||||
 | 
					    "@types/qs": "^6.9.1",
 | 
				
			||||||
 | 
					    "@types/serve-static": "^1.13.3",
 | 
				
			||||||
 | 
					    "axios": "^0.19.2",
 | 
				
			||||||
 | 
					    "basic-auth": "^2.0.1",
 | 
				
			||||||
 | 
					    "bcryptjs": "^2.4.3",
 | 
				
			||||||
 | 
					    "body-parser": "^1.19.0",
 | 
				
			||||||
    "cfenv": "^1.2.2",
 | 
					    "cfenv": "^1.2.2",
 | 
				
			||||||
 | 
					    "content-filter": "^1.1.2",
 | 
				
			||||||
    "express": "^4.17.1",
 | 
					    "express": "^4.17.1",
 | 
				
			||||||
    "json-schema": "^0.2.5",
 | 
					    "json-schema": "^0.2.5",
 | 
				
			||||||
 | 
					    "mongo-sanitize": "^1.1.0",
 | 
				
			||||||
    "mongoose": "^5.8.7",
 | 
					    "mongoose": "^5.8.7",
 | 
				
			||||||
    "nodemon": "^2.0.3",
 | 
					    "nodemon": "^2.0.3",
 | 
				
			||||||
    "swagger-ui-express": "^4.1.2",
 | 
					    "swagger-ui-express": "^4.1.2",
 | 
				
			||||||
@@ -25,7 +39,7 @@
 | 
				
			|||||||
    "typescript": "^3.7.4"
 | 
					    "typescript": "^3.7.4"
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  "devDependencies": {
 | 
					  "devDependencies": {
 | 
				
			||||||
    "mocha": "^7.0.0",
 | 
					    "mocha": "^7.1.2",
 | 
				
			||||||
    "should": "^13.2.3",
 | 
					    "should": "^13.2.3",
 | 
				
			||||||
    "supertest": "^4.0.2"
 | 
					    "supertest": "^4.0.2"
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										116
									
								
								src/customTypes/express.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										116
									
								
								src/customTypes/express.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,116 @@
 | 
				
			|||||||
 | 
					// Type definitions for Express 4.17
 | 
				
			||||||
 | 
					// Project: http://expressjs.com
 | 
				
			||||||
 | 
					// Definitions by: Boris Yankov <https://github.com/borisyankov>
 | 
				
			||||||
 | 
					//                 China Medical University Hospital <https://github.com/CMUH>
 | 
				
			||||||
 | 
					//                 Puneet Arora <https://github.com/puneetar>
 | 
				
			||||||
 | 
					//                 Dylan Frankland <https://github.com/dfrankland>
 | 
				
			||||||
 | 
					// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
 | 
				
			||||||
 | 
					// TypeScript Version: 2.3
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* =================== USAGE ===================
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    import * as express from "express";
 | 
				
			||||||
 | 
					    var app = express();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 =============================================== */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// <reference types="express-serve-static-core" />
 | 
				
			||||||
 | 
					/// <reference types="serve-static" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import * as bodyParser from "body-parser";
 | 
				
			||||||
 | 
					import serveStatic = require("serve-static");
 | 
				
			||||||
 | 
					import * as core from "express-serve-static-core";
 | 
				
			||||||
 | 
					import * as qs from "qs";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Creates an Express application. The express() function is a top-level function exported by the express module.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					declare function e(): core.Express;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					declare namespace e {
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * This is a built-in middleware function in Express. It parses incoming requests with JSON payloads and is based on body-parser.
 | 
				
			||||||
 | 
					     * @since 4.16.0
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    var json: typeof bodyParser.json;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * This is a built-in middleware function in Express. It parses incoming requests with Buffer payloads and is based on body-parser.
 | 
				
			||||||
 | 
					     * @since 4.17.0
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    var raw: typeof bodyParser.raw;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * This is a built-in middleware function in Express. It parses incoming requests with text payloads and is based on body-parser.
 | 
				
			||||||
 | 
					     * @since 4.17.0
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    var text: typeof bodyParser.text;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * These are the exposed prototypes.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    var application: Application;
 | 
				
			||||||
 | 
					    var request: Request;
 | 
				
			||||||
 | 
					    var response: Response;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * This is a built-in middleware function in Express. It serves static files and is based on serve-static.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    var static: typeof serveStatic;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * This is a built-in middleware function in Express. It parses incoming requests with urlencoded payloads and is based on body-parser.
 | 
				
			||||||
 | 
					     * @since 4.16.0
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    var urlencoded: typeof bodyParser.urlencoded;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * This is a built-in middleware function in Express. It parses incoming request query parameters.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    export function query(options: qs.IParseOptions | typeof qs.parse): Handler;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    export function Router(options?: RouterOptions): core.Router;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    interface RouterOptions {
 | 
				
			||||||
 | 
					        /**
 | 
				
			||||||
 | 
					         * Enable case sensitivity.
 | 
				
			||||||
 | 
					         */
 | 
				
			||||||
 | 
					        caseSensitive?: boolean;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /**
 | 
				
			||||||
 | 
					         * Preserve the req.params values from the parent router.
 | 
				
			||||||
 | 
					         * If the parent and the child have conflicting param names, the child’s value take precedence.
 | 
				
			||||||
 | 
					         *
 | 
				
			||||||
 | 
					         * @default false
 | 
				
			||||||
 | 
					         * @since 4.5.0
 | 
				
			||||||
 | 
					         */
 | 
				
			||||||
 | 
					        mergeParams?: boolean;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /**
 | 
				
			||||||
 | 
					         * Enable strict routing.
 | 
				
			||||||
 | 
					         */
 | 
				
			||||||
 | 
					        strict?: boolean;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    interface Application extends core.Application { }
 | 
				
			||||||
 | 
					    interface CookieOptions extends core.CookieOptions { }
 | 
				
			||||||
 | 
					    interface Errback extends core.Errback { }
 | 
				
			||||||
 | 
					    interface ErrorRequestHandler<P extends core.Params = core.ParamsDictionary, ResBody = any, ReqBody = any, ReqQuery = core.Query>
 | 
				
			||||||
 | 
					        extends core.ErrorRequestHandler<P, ResBody, ReqBody, ReqQuery> { }
 | 
				
			||||||
 | 
					    interface Express extends core.Express { }
 | 
				
			||||||
 | 
					    interface Handler extends core.Handler { }
 | 
				
			||||||
 | 
					    interface IRoute extends core.IRoute { }
 | 
				
			||||||
 | 
					    interface IRouter extends core.IRouter { }
 | 
				
			||||||
 | 
					    interface IRouterHandler<T> extends core.IRouterHandler<T> { }
 | 
				
			||||||
 | 
					    interface IRouterMatcher<T> extends core.IRouterMatcher<T> { }
 | 
				
			||||||
 | 
					    interface MediaType extends core.MediaType { }
 | 
				
			||||||
 | 
					    interface NextFunction extends core.NextFunction { }
 | 
				
			||||||
 | 
					    interface Request<P extends core.Params = core.ParamsDictionary, ResBody = any, ReqBody = any, ReqQuery = core.Query> extends core.Request<P, ResBody, ReqBody, ReqQuery> { }
 | 
				
			||||||
 | 
					    interface RequestHandler<P extends core.Params = core.ParamsDictionary, ResBody = any, ReqBody = any, ReqQuery = core.Query> extends core.RequestHandler<P, ResBody, ReqBody, ReqQuery> { }
 | 
				
			||||||
 | 
					    interface RequestParamHandler extends core.RequestParamHandler { }
 | 
				
			||||||
 | 
					    export interface Response<ResBody = any> extends core.Response<ResBody> { }
 | 
				
			||||||
 | 
					    interface Router extends core.Router { }
 | 
				
			||||||
 | 
					    interface Send extends core.Send { }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export = e;
 | 
				
			||||||
							
								
								
									
										109
									
								
								src/db.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										109
									
								
								src/db.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,109 @@
 | 
				
			|||||||
 | 
					import mongoose from 'mongoose';
 | 
				
			||||||
 | 
					import cfenv from 'cfenv';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// mongoose.set('debug', true);  // enable mongoose debug
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// database urls, prod db url is retrieved automatically
 | 
				
			||||||
 | 
					const TESTING_URL = 'mongodb://localhost/dfopdb_test';
 | 
				
			||||||
 | 
					const DEV_URL = 'mongodb://localhost/dfopdb';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default class db {
 | 
				
			||||||
 | 
					  private static state = {  // db object and current mode (test, dev, prod)
 | 
				
			||||||
 | 
					    db: null,
 | 
				
			||||||
 | 
					    mode: null,
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  static connect (mode = '', done: Function = () => {}) {  // set mode to test for unit/integration tests, otherwise skip parameter. done is also only needed for testing
 | 
				
			||||||
 | 
					    if (this.state.db) return done();  // db is already connected
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // find right connection url
 | 
				
			||||||
 | 
					    let connectionString: string = "";
 | 
				
			||||||
 | 
					    if (mode === 'test') {  // testing
 | 
				
			||||||
 | 
					      connectionString = TESTING_URL;
 | 
				
			||||||
 | 
					      this.state.mode = 'test';
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else if(process.env.NODE_ENV === 'production') {
 | 
				
			||||||
 | 
					      let services = cfenv.getAppEnv().getServices();
 | 
				
			||||||
 | 
					      for (let service in services) {
 | 
				
			||||||
 | 
					        if(services[service].tags.indexOf("mongodb") >= 0) {
 | 
				
			||||||
 | 
					          connectionString = services[service]["credentials"].uri;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      this.state.mode = 'prod';
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else {
 | 
				
			||||||
 | 
					      connectionString = DEV_URL;
 | 
				
			||||||
 | 
					      this.state.mode = 'dev';
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // connect to db
 | 
				
			||||||
 | 
					    mongoose.connect(connectionString, {useNewUrlParser: true, useUnifiedTopology: true, useCreateIndex: true, connectTimeoutMS: 10000}, err => {
 | 
				
			||||||
 | 
					      if (err) done(err);
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    mongoose.connection.on('error', console.error.bind(console, 'connection error:'));
 | 
				
			||||||
 | 
					    mongoose.connection.on('disconnected', () => {  // reset state on disconnect
 | 
				
			||||||
 | 
					      console.log('Database disconnected');
 | 
				
			||||||
 | 
					      this.state.db = 0;
 | 
				
			||||||
 | 
					      done();
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    process.on('SIGINT', () => {  // close connection when app is terminated
 | 
				
			||||||
 | 
					      mongoose.connection.close(() => {
 | 
				
			||||||
 | 
					        console.log('Mongoose default connection disconnected through app termination');
 | 
				
			||||||
 | 
					        process.exit(0);
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    mongoose.connection.once('open', () => {
 | 
				
			||||||
 | 
					      mongoose.set('useFindAndModify', false);
 | 
				
			||||||
 | 
					      console.log(process.env.NODE_ENV === 'test' ? '' : `Connected to ${connectionString}`);
 | 
				
			||||||
 | 
					      this.state.db = mongoose.connection;
 | 
				
			||||||
 | 
					      done();
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  static getState () {
 | 
				
			||||||
 | 
					    return this.state;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  static drop (done: Function = () => {}) {  // drop all collections of connected db (only dev and test for safety reasons ;)
 | 
				
			||||||
 | 
					    if (!this.state.db || this.state.mode === 'prod') return done();  // no db connection or prod db
 | 
				
			||||||
 | 
					    this.state.db.db.listCollections().toArray((err, collections) => {  // get list of all collections
 | 
				
			||||||
 | 
					      if (collections.length === 0) {  // there are no collections to drop
 | 
				
			||||||
 | 
					        return done();
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      else {
 | 
				
			||||||
 | 
					        let dropCounter = 0;  // count number of dropped collections to know when to return done()
 | 
				
			||||||
 | 
					        collections.forEach(collection => {  // drop each collection
 | 
				
			||||||
 | 
					          this.state.db.dropCollection(collection.name, () => {
 | 
				
			||||||
 | 
					            if (++ dropCounter >= collections.length) {  // all collections dropped
 | 
				
			||||||
 | 
					              done();
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					          });
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  static loadJson (json, done: Function = () => {}) {  // insert given JSON data into db, uses core mongodb methods
 | 
				
			||||||
 | 
					    if (!this.state.db || !json.hasOwnProperty('collections') || json.collections.length === 0) {
 | 
				
			||||||
 | 
					      return done();
 | 
				
			||||||
 | 
					    }  // no db connection or nothing to load
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let loadCounter = 0;  // count number of loaded collections to know when to return done()
 | 
				
			||||||
 | 
					    Object.keys(json.collections).forEach(collectionName => {  // create each collection
 | 
				
			||||||
 | 
					      for(let i in json.collections[collectionName]) {  // convert $oid fields to actual ObjectIds
 | 
				
			||||||
 | 
					        Object.keys(json.collections[collectionName][i]).forEach(key => {
 | 
				
			||||||
 | 
					          if (json.collections[collectionName][i][key] !== null && json.collections[collectionName][i][key].hasOwnProperty('$oid')) {
 | 
				
			||||||
 | 
					            json.collections[collectionName][i][key] = mongoose.Types.ObjectId(json.collections[collectionName][i][key].$oid);
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      this.state.db.createCollection(collectionName, (err, collection) => {
 | 
				
			||||||
 | 
					        collection.insertMany(json.collections[collectionName], () => {  // insert JSON data
 | 
				
			||||||
 | 
					          if (++ loadCounter >= Object.keys(json.collections).length) {  // all collections loaded
 | 
				
			||||||
 | 
					            done();
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
							
								
								
									
										11
									
								
								src/globals.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								src/globals.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,11 @@
 | 
				
			|||||||
 | 
					const globals = {
 | 
				
			||||||
 | 
					  levels: [  // access levels
 | 
				
			||||||
 | 
					    'read',
 | 
				
			||||||
 | 
					    'write',
 | 
				
			||||||
 | 
					    'maintain',
 | 
				
			||||||
 | 
					    'dev',
 | 
				
			||||||
 | 
					    'admin'
 | 
				
			||||||
 | 
					  ]
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default globals;
 | 
				
			||||||
							
								
								
									
										101
									
								
								src/helpers/authorize.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										101
									
								
								src/helpers/authorize.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,101 @@
 | 
				
			|||||||
 | 
					import basicAuth from 'basic-auth';
 | 
				
			||||||
 | 
					import bcrypt from 'bcryptjs';
 | 
				
			||||||
 | 
					import UserModel from '../models/user';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// appends req.auth(res, ['levels'], method = 'all')
 | 
				
			||||||
 | 
					// which returns sends error message and returns false if unauthorized, otherwise true
 | 
				
			||||||
 | 
					// req.authDetails returns eg. {methods: ['basic'], username: 'johndoe', level: 'write'}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module.exports = async (req, res, next) => {
 | 
				
			||||||
 | 
					  let givenMethod = '';  // authorization method given by client, basic taken preferred
 | 
				
			||||||
 | 
					  let user = {name: '', level: '', id: ''};               // user object
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // test authentications
 | 
				
			||||||
 | 
					  const userBasic = await basic(req, next);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (userBasic) {  // basic available
 | 
				
			||||||
 | 
					    givenMethod = 'basic';
 | 
				
			||||||
 | 
					    user = userBasic;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  else {  // if basic not available, test key
 | 
				
			||||||
 | 
					    const userKey = await key(req, next);
 | 
				
			||||||
 | 
					    if (userKey) {
 | 
				
			||||||
 | 
					      givenMethod = 'key';
 | 
				
			||||||
 | 
					      user = userKey;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  req.auth = (res, levels, method = 'all') => {
 | 
				
			||||||
 | 
					    if (givenMethod === method || (method === 'all' && givenMethod !== '')) {  // method is available
 | 
				
			||||||
 | 
					      if (levels.indexOf(user.level) > -1) {  // level is available
 | 
				
			||||||
 | 
					        return true;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      else {
 | 
				
			||||||
 | 
					        res.status(403).json({status: 'Forbidden'});
 | 
				
			||||||
 | 
					        return false;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else {
 | 
				
			||||||
 | 
					      res.status(401).json({status: 'Unauthorized'});
 | 
				
			||||||
 | 
					      return false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  req.authDetails = {
 | 
				
			||||||
 | 
					    method: givenMethod,
 | 
				
			||||||
 | 
					    username: user.name,
 | 
				
			||||||
 | 
					    level: user.level,
 | 
				
			||||||
 | 
					    id: user.id
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  next();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function basic (req, next): any {  // checks basic auth and returns changed user object
 | 
				
			||||||
 | 
					  return new Promise(resolve => {
 | 
				
			||||||
 | 
					    const auth = basicAuth(req);
 | 
				
			||||||
 | 
					    if (auth !== undefined) {  // basic auth available
 | 
				
			||||||
 | 
					      UserModel.find({name: auth.name}).lean().exec( (err, data: any) => {  // find user
 | 
				
			||||||
 | 
					        if (err) return next(err);
 | 
				
			||||||
 | 
					        if (data.length === 1) {  // one user found
 | 
				
			||||||
 | 
					          bcrypt.compare(auth.pass, data[0].pass, (err, res) => {  // check password
 | 
				
			||||||
 | 
					            if (err) return next(err);
 | 
				
			||||||
 | 
					            if (res === true) {
 | 
				
			||||||
 | 
					              resolve({level: data[0].level, name: data[0].name, id: data[0]._id.toString()});
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            else {
 | 
				
			||||||
 | 
					              resolve(null);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					          });
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else {
 | 
				
			||||||
 | 
					          resolve(null);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else {
 | 
				
			||||||
 | 
					      resolve(null);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function key (req, next): any {  // checks API key and returns changed user object
 | 
				
			||||||
 | 
					  return new Promise(resolve => {
 | 
				
			||||||
 | 
					    if (req.query.key !== undefined) {
 | 
				
			||||||
 | 
					      UserModel.find({key: req.query.key}).lean().exec( (err, data: any) => {  // find user
 | 
				
			||||||
 | 
					        if (err) return next(err);
 | 
				
			||||||
 | 
					        if (data.length === 1) {  // one user found
 | 
				
			||||||
 | 
					          resolve({level: data[0].level, name: data[0].name, id: data[0]._id.toString()});
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else {
 | 
				
			||||||
 | 
					          resolve(null);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else {
 | 
				
			||||||
 | 
					      resolve(null);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										64
									
								
								src/helpers/mail.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								src/helpers/mail.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,64 @@
 | 
				
			|||||||
 | 
					import axios from 'axios';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// sends an email
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default (mailAddress, subject, content, f) => {  // callback, executed empty or with error
 | 
				
			||||||
 | 
					  if (process.env.NODE_ENV === 'production') {
 | 
				
			||||||
 | 
					    const mailService = JSON.parse(process.env.VCAP_SERVICES).Mail[0];
 | 
				
			||||||
 | 
					    axios({
 | 
				
			||||||
 | 
					      method: 'post',
 | 
				
			||||||
 | 
					      url: mailService.credentials.uri + '/email',
 | 
				
			||||||
 | 
					      auth: {username: mailService.credentials.username, password: mailService.credentials.password},
 | 
				
			||||||
 | 
					      data: {
 | 
				
			||||||
 | 
					        recipients: [{to: mailAddress}],
 | 
				
			||||||
 | 
					        subject: {content: subject},
 | 
				
			||||||
 | 
					        body: {
 | 
				
			||||||
 | 
					          content: content,
 | 
				
			||||||
 | 
					          contentType: "text/html"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        from: {
 | 
				
			||||||
 | 
					          eMail: "dfop@bosch-iot.com",
 | 
				
			||||||
 | 
					          password: "PlasticsOfFingerprintDigital"
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					      .then(() => {
 | 
				
			||||||
 | 
					        f();
 | 
				
			||||||
 | 
					      })
 | 
				
			||||||
 | 
					      .catch((err) => {
 | 
				
			||||||
 | 
					        f(err);
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  else if (process.env.NODE_ENV === 'test') {
 | 
				
			||||||
 | 
					    console.log('Sending mail to ' + mailAddress + ':  -- ' + subject + ' -- ' + content);
 | 
				
			||||||
 | 
					    f();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  else {  // dev
 | 
				
			||||||
 | 
					    axios({
 | 
				
			||||||
 | 
					      method: 'get',
 | 
				
			||||||
 | 
					      url: 'https://digital-fingerprint-of-plastics-mail-test.apps.de1.bosch-iot-cloud.com/api',
 | 
				
			||||||
 | 
					      data: {
 | 
				
			||||||
 | 
					        method: 'post',
 | 
				
			||||||
 | 
					        url: '/email',
 | 
				
			||||||
 | 
					        data: {
 | 
				
			||||||
 | 
					          recipients: [{to: mailAddress}],
 | 
				
			||||||
 | 
					          subject: {content: subject},
 | 
				
			||||||
 | 
					          body: {
 | 
				
			||||||
 | 
					            content: content,
 | 
				
			||||||
 | 
					            contentType: "text/html"
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          from: {
 | 
				
			||||||
 | 
					            eMail: "dfop-test@bosch-iot.com",
 | 
				
			||||||
 | 
					            password: "PlasticsOfFingerprintDigital"
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					      .then(() => {
 | 
				
			||||||
 | 
					        f();
 | 
				
			||||||
 | 
					      })
 | 
				
			||||||
 | 
					      .catch((err) => {
 | 
				
			||||||
 | 
					        f(err);
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										90
									
								
								src/helpers/test.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										90
									
								
								src/helpers/test.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,90 @@
 | 
				
			|||||||
 | 
					import supertest from 'supertest';
 | 
				
			||||||
 | 
					import should from 'should/as-function';
 | 
				
			||||||
 | 
					import db from "../db";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default class TestHelper {
 | 
				
			||||||
 | 
					  public static auth = {
 | 
				
			||||||
 | 
					    admin: {pass: 'Abc123!#', key: '000000000000000000001003'},
 | 
				
			||||||
 | 
					    janedoe: {pass: 'Xyz890*)', key: '000000000000000000001002'},
 | 
				
			||||||
 | 
					    user: {pass: 'Xyz890*)', key: '000000000000000000001001'}
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  public static res = {
 | 
				
			||||||
 | 
					    400: {status: 'Bad request'},
 | 
				
			||||||
 | 
					    401: {status: 'Unauthorized'},
 | 
				
			||||||
 | 
					    403: {status: 'Forbidden'},
 | 
				
			||||||
 | 
					    404: {status: 'Not found'},
 | 
				
			||||||
 | 
					    500: {status: 'Internal server error'}
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  static before (done) {
 | 
				
			||||||
 | 
					    process.env.port = '2999';
 | 
				
			||||||
 | 
					    process.env.NODE_ENV = 'test';
 | 
				
			||||||
 | 
					    db.connect('test', done);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  static beforeEach (server, done) {
 | 
				
			||||||
 | 
					    delete require.cache[require.resolve('../index')];  // prevent loading from cache
 | 
				
			||||||
 | 
					    server = require('../index');
 | 
				
			||||||
 | 
					    db.drop(err => {  // reset database
 | 
				
			||||||
 | 
					      if (err) return done(err);
 | 
				
			||||||
 | 
					      db.loadJson(require('../test/db.json'), done);
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    return server
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  static afterEach (server, 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}
 | 
				
			||||||
 | 
					    let st = supertest(server);
 | 
				
			||||||
 | 
					    if (options.hasOwnProperty('auth') && options.auth.hasOwnProperty('key')) {
 | 
				
			||||||
 | 
					      options.url += '?key=' + (this.auth.hasOwnProperty(options.auth.key)? this.auth[options.auth.key].key : options.auth.key);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    switch (options.method) {
 | 
				
			||||||
 | 
					      case 'get':
 | 
				
			||||||
 | 
					        st = st.get(options.url)
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					      case 'post':
 | 
				
			||||||
 | 
					        st = st.post(options.url)
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					      case 'put':
 | 
				
			||||||
 | 
					        st = st.put(options.url)
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					      case 'delete':
 | 
				
			||||||
 | 
					        st = st.delete(options.url)
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (options.hasOwnProperty('req')) {
 | 
				
			||||||
 | 
					      st = st.send(options.req);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (options.hasOwnProperty('auth') && options.auth.hasOwnProperty('basic')) {
 | 
				
			||||||
 | 
					      if (this.auth.hasOwnProperty(options.auth.basic)) {
 | 
				
			||||||
 | 
					        st = st.auth(options.auth.basic, this.auth[options.auth.basic].pass)
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      else {
 | 
				
			||||||
 | 
					        st = st.auth(options.auth.basic.name, options.auth.basic.pass)
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    st = st.expect('Content-type', /json/)
 | 
				
			||||||
 | 
					      .expect(options.httpStatus);
 | 
				
			||||||
 | 
					    if (options.hasOwnProperty('res')) {
 | 
				
			||||||
 | 
					      return st.end((err, res) => {
 | 
				
			||||||
 | 
					        if (err) return done (err);
 | 
				
			||||||
 | 
					        should(res.body).be.eql(options.res);
 | 
				
			||||||
 | 
					        done();
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else if (this.res.hasOwnProperty(options.httpStatus) && options.default !== false) {
 | 
				
			||||||
 | 
					      return st.end((err, res) => {
 | 
				
			||||||
 | 
					        if (err) return done (err);
 | 
				
			||||||
 | 
					        should(res.body).be.eql(this.res[options.httpStatus]);
 | 
				
			||||||
 | 
					        done();
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else {
 | 
				
			||||||
 | 
					      return st;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										90
									
								
								src/index.ts
									
									
									
									
									
								
							
							
						
						
									
										90
									
								
								src/index.ts
									
									
									
									
									
								
							@@ -1,37 +1,18 @@
 | 
				
			|||||||
import cfenv from 'cfenv';
 | 
					 | 
				
			||||||
import express from 'express';
 | 
					import express from 'express';
 | 
				
			||||||
import mongoose from 'mongoose';
 | 
					import bodyParser from 'body-parser';
 | 
				
			||||||
import swagger from 'swagger-ui-express';
 | 
					import swagger from 'swagger-ui-express';
 | 
				
			||||||
import jsonRefParser, {JSONSchema} from '@apidevtools/json-schema-ref-parser';
 | 
					import jsonRefParser, {JSONSchema} from '@apidevtools/json-schema-ref-parser';
 | 
				
			||||||
 | 
					import contentFilter from 'content-filter';
 | 
				
			||||||
 | 
					import mongoSanitize from 'mongo-sanitize';
 | 
				
			||||||
 | 
					import db from './db';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// tell if server is running in debug or production environment
 | 
					// tell if server is running in debug or production environment
 | 
				
			||||||
console.log(process.env.NODE_ENV === 'production' ? '===== PRODUCTION =====' : '===== DEVELOPMENT =====');
 | 
					console.log(process.env.NODE_ENV === 'production' ? '===== PRODUCTION =====' : process.env.NODE_ENV === 'test' ? '' :'===== DEVELOPMENT =====');
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// get mongodb address from server, otherwise set to localhost
 | 
					 | 
				
			||||||
let connectionString: string = "";
 | 
					 | 
				
			||||||
if(process.env.NODE_ENV === 'production') {
 | 
					 | 
				
			||||||
  let services = cfenv.getAppEnv().getServices();
 | 
					 | 
				
			||||||
  for (let service in services) {
 | 
					 | 
				
			||||||
    if(services[service].tags.indexOf("mongodb") >= 0) {
 | 
					 | 
				
			||||||
      connectionString = services[service]["credentials"].uri;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
else {
 | 
					 | 
				
			||||||
  connectionString = 'mongodb://localhost/dfopdb';
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
mongoose.connect(connectionString, {useNewUrlParser: true, useUnifiedTopology: true});
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// connect to mongodb
 | 
					 | 
				
			||||||
let db = mongoose.connection;
 | 
					 | 
				
			||||||
db.on('error', console.error.bind(console, 'connection error:'));
 | 
					 | 
				
			||||||
db.once('open', () => {
 | 
					 | 
				
			||||||
  console.log(`Connected to ${connectionString}`);
 | 
					 | 
				
			||||||
});
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// mongodb connection
 | 
				
			||||||
 | 
					db.connect();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// create Express app
 | 
					// create Express app
 | 
				
			||||||
const app = express();
 | 
					const app = express();
 | 
				
			||||||
@@ -40,20 +21,61 @@ app.disable('x-powered-by');
 | 
				
			|||||||
// get port from environment, defaults to 3000
 | 
					// get port from environment, defaults to 3000
 | 
				
			||||||
const port = process.env.PORT || 3000;
 | 
					const port = process.env.PORT || 3000;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//middleware
 | 
				
			||||||
 | 
					app.use(express.json({ limit: '5mb'}));
 | 
				
			||||||
 | 
					app.use(express.urlencoded({ extended: false, limit: '5mb' }));
 | 
				
			||||||
 | 
					app.use(bodyParser.json());
 | 
				
			||||||
 | 
					app.use(contentFilter());  // filter URL query attacks
 | 
				
			||||||
 | 
					app.use((req, res, next) => {  // filter body query attacks
 | 
				
			||||||
 | 
					  req.body = mongoSanitize(req.body);
 | 
				
			||||||
 | 
					  next();
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					app.use((err, req, res, ignore) => {  // bodyParser error handling
 | 
				
			||||||
 | 
					  res.status(400).send({status: 'Invalid JSON body'});
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					app.use((req, res, next) => {  // no database connection error
 | 
				
			||||||
 | 
					  if (db.getState().db) {
 | 
				
			||||||
 | 
					    next();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  else {
 | 
				
			||||||
 | 
					    res.status(500).send({status: 'Internal server error'});
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					app.use(require('./helpers/authorize'));  // handle authentication
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// require routes
 | 
					// require routes
 | 
				
			||||||
app.use('/', require('./routes/root'));
 | 
					app.use('/', require('./routes/root'));
 | 
				
			||||||
 | 
					app.use('/', require('./routes/sample'));
 | 
				
			||||||
 | 
					app.use('/', require('./routes/material'));
 | 
				
			||||||
 | 
					app.use('/', require('./routes/template'));
 | 
				
			||||||
 | 
					app.use('/', require('./routes/user'));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// static files
 | 
				
			||||||
 | 
					app.use('/static', express.static('static'));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Swagger UI
 | 
					// Swagger UI
 | 
				
			||||||
let oasDoc: JSONSchema = {};
 | 
					let apiDoc: JSONSchema = {};
 | 
				
			||||||
jsonRefParser.bundle('oas/oas.yaml', (err, doc) => {
 | 
					jsonRefParser.bundle('api/api.yaml', (err, doc) => {
 | 
				
			||||||
  if(err) throw err;
 | 
					  if(err) throw err;
 | 
				
			||||||
  oasDoc = doc;
 | 
					  apiDoc = doc;
 | 
				
			||||||
  oasDoc.paths = oasDoc.paths.allOf.reduce((s, e) => Object.assign(s, e));
 | 
					  apiDoc.paths = apiDoc.paths.allOf.reduce((s, e) => Object.assign(s, e));
 | 
				
			||||||
  swagger.setup(oasDoc, {defaultModelsExpandDepth: -1, customCss: '.swagger-ui .topbar { display: none }'});
 | 
					  swagger.setup(apiDoc, {defaultModelsExpandDepth: -1, customCss: '.swagger-ui .topbar { display: none }'});
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
app.use('/api', swagger.serve, swagger.setup(oasDoc, {defaultModelsExpandDepth: -1, customCss: '.swagger-ui .topbar { display: none }'}));
 | 
					app.use('/api', swagger.serve, swagger.setup(apiDoc, {customCssUrl: '/static/styles/swagger.css'}));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					app.use((req, res) => {  // 404 error handling
 | 
				
			||||||
 | 
					  res.status(404).json({status: 'Not found'});
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					app.use((err, req, res, ignore) => {  // internal server error handling
 | 
				
			||||||
 | 
					  console.error(err);
 | 
				
			||||||
 | 
					  res.status(500).json({status: 'Internal server error'});
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// hook up server to port
 | 
					// hook up server to port
 | 
				
			||||||
app.listen(port, () => {
 | 
					const server = app.listen(port, () => {
 | 
				
			||||||
  console.log(`Listening on http;//localhost:${port}`);
 | 
					  console.log(process.env.NODE_ENV === 'test' ? '' : `Listening on http://localhost:${port}`);
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module.exports = server;
 | 
				
			||||||
							
								
								
									
										16
									
								
								src/models/material.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								src/models/material.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,16 @@
 | 
				
			|||||||
 | 
					import mongoose from 'mongoose';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const MaterialSchema = new mongoose.Schema({
 | 
				
			||||||
 | 
					  name: {type: String, index: {unique: true}},
 | 
				
			||||||
 | 
					  supplier: String,
 | 
				
			||||||
 | 
					  group: String,
 | 
				
			||||||
 | 
					  mineral: String,
 | 
				
			||||||
 | 
					  glass_fiber: String,
 | 
				
			||||||
 | 
					  carbon_fiber: String,
 | 
				
			||||||
 | 
					  numbers: [{
 | 
				
			||||||
 | 
					    color: String,
 | 
				
			||||||
 | 
					    number: Number
 | 
				
			||||||
 | 
					  }]
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default mongoose.model('material', MaterialSchema);
 | 
				
			||||||
							
								
								
									
										11
									
								
								src/models/measurement_template.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								src/models/measurement_template.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,11 @@
 | 
				
			|||||||
 | 
					import mongoose from 'mongoose';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const MeasurementTemplateSchema = new mongoose.Schema({
 | 
				
			||||||
 | 
					  name: {type: String, index: {unique: true}},
 | 
				
			||||||
 | 
					  parameters: [{
 | 
				
			||||||
 | 
					    name: String,
 | 
				
			||||||
 | 
					    range: mongoose.Schema.Types.Mixed
 | 
				
			||||||
 | 
					  }]
 | 
				
			||||||
 | 
					}, {minimize: false});  // to allow empty objects
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default mongoose.model('measurement_template', MeasurementTemplateSchema);
 | 
				
			||||||
							
								
								
									
										12
									
								
								src/models/note.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								src/models/note.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,12 @@
 | 
				
			|||||||
 | 
					import mongoose from 'mongoose';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const NoteSchema = new mongoose.Schema({
 | 
				
			||||||
 | 
					  comment: String,
 | 
				
			||||||
 | 
					  sample_references: [{
 | 
				
			||||||
 | 
					    id: mongoose.Schema.Types.ObjectId,
 | 
				
			||||||
 | 
					    relation: String
 | 
				
			||||||
 | 
					  }],
 | 
				
			||||||
 | 
					  custom_fields: mongoose.Schema.Types.Mixed
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default mongoose.model('note', NoteSchema);
 | 
				
			||||||
							
								
								
									
										8
									
								
								src/models/note_field.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								src/models/note_field.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,8 @@
 | 
				
			|||||||
 | 
					import mongoose from 'mongoose';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const NoteFieldSchema = new mongoose.Schema({
 | 
				
			||||||
 | 
					  name: {type: String, index: {unique: true}},
 | 
				
			||||||
 | 
					  qty: Number
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default mongoose.model('note_field', NoteFieldSchema);
 | 
				
			||||||
							
								
								
									
										18
									
								
								src/models/sample.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								src/models/sample.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,18 @@
 | 
				
			|||||||
 | 
					import mongoose from 'mongoose';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import MaterialModel from './material';
 | 
				
			||||||
 | 
					import NoteModel from './note';
 | 
				
			||||||
 | 
					import UserModel from './user';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const SampleSchema = new mongoose.Schema({
 | 
				
			||||||
 | 
					  number: {type: String, index: {unique: true}},
 | 
				
			||||||
 | 
					  type: String,
 | 
				
			||||||
 | 
					  color: String,
 | 
				
			||||||
 | 
					  batch: String,
 | 
				
			||||||
 | 
					  validated: Boolean,
 | 
				
			||||||
 | 
					  material_id: {type: mongoose.Schema.Types.ObjectId, ref: MaterialModel},
 | 
				
			||||||
 | 
					  note_id: {type: mongoose.Schema.Types.ObjectId, ref: NoteModel},
 | 
				
			||||||
 | 
					  user_id: {type: mongoose.Schema.Types.ObjectId, ref: UserModel}
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default mongoose.model('sample', SampleSchema);
 | 
				
			||||||
							
								
								
									
										11
									
								
								src/models/treatment_template.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								src/models/treatment_template.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,11 @@
 | 
				
			|||||||
 | 
					import mongoose from 'mongoose';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const TreatmentTemplateSchema = new mongoose.Schema({
 | 
				
			||||||
 | 
					  name: {type: String, index: {unique: true}},
 | 
				
			||||||
 | 
					  parameters: [{
 | 
				
			||||||
 | 
					    name: String,
 | 
				
			||||||
 | 
					    range: mongoose.Schema.Types.Mixed
 | 
				
			||||||
 | 
					  }]
 | 
				
			||||||
 | 
					}, {minimize: false});  // to allow empty objects
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default mongoose.model('treatment_template', TreatmentTemplateSchema);
 | 
				
			||||||
							
								
								
									
										13
									
								
								src/models/user.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								src/models/user.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,13 @@
 | 
				
			|||||||
 | 
					import mongoose from 'mongoose';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const UserSchema = new mongoose.Schema({
 | 
				
			||||||
 | 
					  name: {type: String, index: {unique: true}},
 | 
				
			||||||
 | 
					  email: String,
 | 
				
			||||||
 | 
					  pass: String,
 | 
				
			||||||
 | 
					  key: String,
 | 
				
			||||||
 | 
					  level: String,
 | 
				
			||||||
 | 
					  location: String,
 | 
				
			||||||
 | 
					  device_name: String
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default mongoose.model('user', UserSchema);
 | 
				
			||||||
							
								
								
									
										397
									
								
								src/routes/material.spec.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										397
									
								
								src/routes/material.spec.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,397 @@
 | 
				
			|||||||
 | 
					import should from 'should/as-function';
 | 
				
			||||||
 | 
					import MaterialModel from '../models/material';
 | 
				
			||||||
 | 
					import TestHelper from "../helpers/test";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					describe('/material', () => {
 | 
				
			||||||
 | 
					  let server;
 | 
				
			||||||
 | 
					  before(done => TestHelper.before(done));
 | 
				
			||||||
 | 
					  beforeEach(done => server = TestHelper.beforeEach(server, done));
 | 
				
			||||||
 | 
					  afterEach(done => TestHelper.afterEach(server, done));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  describe('GET /materials', () => {
 | 
				
			||||||
 | 
					    it('returns all materials', done => {
 | 
				
			||||||
 | 
					      TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					        method: 'get',
 | 
				
			||||||
 | 
					        url: '/materials',
 | 
				
			||||||
 | 
					        auth: {basic: 'janedoe'},
 | 
				
			||||||
 | 
					        httpStatus: 200
 | 
				
			||||||
 | 
					      }).end((err, res) => {
 | 
				
			||||||
 | 
					        if (err) return done(err);
 | 
				
			||||||
 | 
					        const json = require('../test/db.json');
 | 
				
			||||||
 | 
					        should(res.body).have.lengthOf(json.collections.materials.length);
 | 
				
			||||||
 | 
					        should(res.body).matchEach(material => {
 | 
				
			||||||
 | 
					          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('name').be.type('string');
 | 
				
			||||||
 | 
					          should(material).have.property('supplier').be.type('string');
 | 
				
			||||||
 | 
					          should(material).have.property('group').be.type('string');
 | 
				
			||||||
 | 
					          should(material).have.property('mineral').be.type('number');
 | 
				
			||||||
 | 
					          should(material).have.property('glass_fiber').be.type('number');
 | 
				
			||||||
 | 
					          should(material).have.property('carbon_fiber').be.type('number');
 | 
				
			||||||
 | 
					          should(material.numbers).matchEach(number => {
 | 
				
			||||||
 | 
					            should(number).have.only.keys('color', 'number');
 | 
				
			||||||
 | 
					            should(number).have.property('color').be.type('string');
 | 
				
			||||||
 | 
					            should(number).have.property('number').be.type('number');
 | 
				
			||||||
 | 
					          });
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					        done();
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    it('works with an API key', done => {
 | 
				
			||||||
 | 
					      TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					        method: 'get',
 | 
				
			||||||
 | 
					        url: '/materials',
 | 
				
			||||||
 | 
					        auth: {key: 'janedoe'},
 | 
				
			||||||
 | 
					        httpStatus: 200
 | 
				
			||||||
 | 
					      }).end((err, res) => {
 | 
				
			||||||
 | 
					        if (err) return done(err);
 | 
				
			||||||
 | 
					        const json = require('../test/db.json');
 | 
				
			||||||
 | 
					        should(res.body).have.lengthOf(json.collections.materials.length);
 | 
				
			||||||
 | 
					        should(res.body).matchEach(material => {
 | 
				
			||||||
 | 
					          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('name').be.type('string');
 | 
				
			||||||
 | 
					          should(material).have.property('supplier').be.type('string');
 | 
				
			||||||
 | 
					          should(material).have.property('group').be.type('string');
 | 
				
			||||||
 | 
					          should(material).have.property('mineral').be.type('number');
 | 
				
			||||||
 | 
					          should(material).have.property('glass_fiber').be.type('number');
 | 
				
			||||||
 | 
					          should(material).have.property('carbon_fiber').be.type('number');
 | 
				
			||||||
 | 
					          should(material.numbers).matchEach(number => {
 | 
				
			||||||
 | 
					            should(number).have.only.keys('color', 'number');
 | 
				
			||||||
 | 
					            should(number).have.property('color').be.type('string');
 | 
				
			||||||
 | 
					            should(number).have.property('number').be.type('number');
 | 
				
			||||||
 | 
					          });
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					        done();
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    it('rejects unauthorized requests', done => {
 | 
				
			||||||
 | 
					      TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					        method: 'get',
 | 
				
			||||||
 | 
					        url: '/materials',
 | 
				
			||||||
 | 
					        httpStatus: 401
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  describe('GET /material/{id}', () => {
 | 
				
			||||||
 | 
					    it('returns the right material', done => {
 | 
				
			||||||
 | 
					      TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					        method: 'get',
 | 
				
			||||||
 | 
					        url: '/material/100000000000000000000001',
 | 
				
			||||||
 | 
					        auth: {basic: 'janedoe'},
 | 
				
			||||||
 | 
					        httpStatus: 200,
 | 
				
			||||||
 | 
					        res: {_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}]}
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    it('returns the right material for an API key', done => {
 | 
				
			||||||
 | 
					      TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					        method: 'get',
 | 
				
			||||||
 | 
					        url: '/material/100000000000000000000003',
 | 
				
			||||||
 | 
					        auth: {key: 'admin'},
 | 
				
			||||||
 | 
					        httpStatus: 200,
 | 
				
			||||||
 | 
					        res: {_id: '100000000000000000000003', name: 'PA GF 50 black (2706)', supplier: 'Akro-Plastic', group: 'PA66+PA6I/6T', mineral: 0, glass_fiber: 0, carbon_fiber: 0, numbers: []}
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    it('rejects an invalid id', done => {
 | 
				
			||||||
 | 
					      TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					        method: 'get',
 | 
				
			||||||
 | 
					        url: '/material/10000000000000000000000x',
 | 
				
			||||||
 | 
					        auth: {key: 'admin'},
 | 
				
			||||||
 | 
					        httpStatus: 404
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    it('rejects an unknown id', done => {
 | 
				
			||||||
 | 
					      TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					        method: 'get',
 | 
				
			||||||
 | 
					        url: '/material/100000000000000000000111',
 | 
				
			||||||
 | 
					        auth: {key: 'janedoe'},
 | 
				
			||||||
 | 
					        httpStatus: 404
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    it('rejects unauthorized requests', done => {
 | 
				
			||||||
 | 
					      TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					        method: 'get',
 | 
				
			||||||
 | 
					        url: '/material/100000000000000000000001',
 | 
				
			||||||
 | 
					        httpStatus: 401
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  describe('PUT /material/{id}', () => {
 | 
				
			||||||
 | 
					    it('returns the right material', done => {
 | 
				
			||||||
 | 
					      TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					        method: 'put',
 | 
				
			||||||
 | 
					        url: '/material/100000000000000000000001',
 | 
				
			||||||
 | 
					        auth: {basic: 'janedoe'},
 | 
				
			||||||
 | 
					        httpStatus: 200,
 | 
				
			||||||
 | 
					        req: {},
 | 
				
			||||||
 | 
					        res: {_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}]}
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    it('keeps unchanged properties', done => {
 | 
				
			||||||
 | 
					      TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					        method: 'put',
 | 
				
			||||||
 | 
					        url: '/material/100000000000000000000001',
 | 
				
			||||||
 | 
					        auth: {basic: 'janedoe'},
 | 
				
			||||||
 | 
					        httpStatus: 200,
 | 
				
			||||||
 | 
					        req: {name: 'Stanyl TW 200 F8', supplier: 'DSM', group: 'PA46', mineral: 0, glass_fiber: 40, carbon_fiber: 0, numbers: [{color: 'black', number: 5514263423}]},
 | 
				
			||||||
 | 
					        res: {_id: '100000000000000000000001', name: 'Stanyl TW 200 F8', supplier: 'DSM', group: 'PA46', mineral: 0, glass_fiber: 40, carbon_fiber: 0, numbers: [{color: 'black', number: 5514263423}]}
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    it('changes the given properties', done => {
 | 
				
			||||||
 | 
					      TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					        method: 'put',
 | 
				
			||||||
 | 
					        url: '/material/100000000000000000000001',
 | 
				
			||||||
 | 
					        auth: {basic: 'janedoe'},
 | 
				
			||||||
 | 
					        httpStatus: 200,
 | 
				
			||||||
 | 
					        req: {name: 'UltramidTKR4355G7_2', supplier: 'BASF', group: 'PA6/6T', mineral: 0, glass_fiber: 35, carbon_fiber: 0, numbers: [{color: 'black', number: 5514212901}, {color: 'signalviolet', number: 5514612901}]}
 | 
				
			||||||
 | 
					        ,
 | 
				
			||||||
 | 
					      }).end((err, res) => {
 | 
				
			||||||
 | 
					        if (err) return done(err);
 | 
				
			||||||
 | 
					        should(res.body).be.eql({_id: '100000000000000000000001', name: 'UltramidTKR4355G7_2', supplier: 'BASF', group: 'PA6/6T', mineral: 0, glass_fiber: 35, carbon_fiber: 0, numbers: [{color: 'black', number: 5514212901}, {color: 'signalviolet', number: 5514612901}]});
 | 
				
			||||||
 | 
					        MaterialModel.findById('100000000000000000000001').lean().exec((err, data:any) => {
 | 
				
			||||||
 | 
					          if (err) return done(err);
 | 
				
			||||||
 | 
					          data._id = data._id.toString({_id: '100000000000000000000001', name: 'UltramidTKR4355G7_2', supplier: 'BASF', group: 'PA6/6T', mineral: 0, glass_fiber: 35, carbon_fiber: 0, numbers: [{color: 'black', number: 5514212901}, {color: 'signalviolet', number: 5514612901}]});
 | 
				
			||||||
 | 
					          data.numbers = data.numbers.map(e => {return {color: e.color, number: e.number}});
 | 
				
			||||||
 | 
					          should(data).be.eql({_id: '100000000000000000000001', name: 'UltramidTKR4355G7_2', supplier: 'BASF', group: 'PA6/6T', mineral: '0', glass_fiber: '35', carbon_fiber: '0', numbers: [{color: 'black', number: 5514212901}, {color: 'signalviolet', number: 5514612901}], __v: 0}
 | 
				
			||||||
 | 
					          );
 | 
				
			||||||
 | 
					          done();
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    it('rejects already existing material names', done => {
 | 
				
			||||||
 | 
					      TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					        method: 'put',
 | 
				
			||||||
 | 
					        url: '/material/100000000000000000000001',
 | 
				
			||||||
 | 
					        auth: {basic: 'janedoe'},
 | 
				
			||||||
 | 
					        httpStatus: 400,
 | 
				
			||||||
 | 
					        req: {name: 'Ultramid T KR 4355 G7'},
 | 
				
			||||||
 | 
					        res: {status: 'Material name already taken'}
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    it('rejects wrong material properties', done => {
 | 
				
			||||||
 | 
					      TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					        method: 'put',
 | 
				
			||||||
 | 
					        url: '/material/100000000000000000000001',
 | 
				
			||||||
 | 
					        auth: {basic: 'janedoe'},
 | 
				
			||||||
 | 
					        httpStatus: 400,
 | 
				
			||||||
 | 
					        req: {mineral: 'x', glass_fiber: 'x', carbon_fiber: 'x', numbers: [{colorxx: 'black', number: 'xxx'}]},
 | 
				
			||||||
 | 
					        res: {status: 'Invalid body format'}
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    it('rejects an invalid id', done => {
 | 
				
			||||||
 | 
					      TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					        method: 'put',
 | 
				
			||||||
 | 
					        url: '/material/10000000000000000000000x',
 | 
				
			||||||
 | 
					        auth: {basic: 'admin'},
 | 
				
			||||||
 | 
					        httpStatus: 404,
 | 
				
			||||||
 | 
					        req: {},
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    it('rejects an API key', done => {
 | 
				
			||||||
 | 
					      TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					        method: 'put',
 | 
				
			||||||
 | 
					        url: '/material/100000000000000000000002',
 | 
				
			||||||
 | 
					        auth: {key: 'admin'},
 | 
				
			||||||
 | 
					        httpStatus: 401,
 | 
				
			||||||
 | 
					        req: {}
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    it('rejects requests from a read user', done => {
 | 
				
			||||||
 | 
					      TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					        method: 'put',
 | 
				
			||||||
 | 
					        url: '/material/100000000000000000000002',
 | 
				
			||||||
 | 
					        auth: {basic: 'user'},
 | 
				
			||||||
 | 
					        httpStatus: 403,
 | 
				
			||||||
 | 
					        req: {}
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    it('returns 404 for an unknown material', done => {
 | 
				
			||||||
 | 
					      TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					        method: 'put',
 | 
				
			||||||
 | 
					        url: '/material/100000000000000000000111',
 | 
				
			||||||
 | 
					        auth: {basic: 'janedoe'},
 | 
				
			||||||
 | 
					        httpStatus: 404,
 | 
				
			||||||
 | 
					        req: {}
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    it('rejects unauthorized requests', done => {
 | 
				
			||||||
 | 
					      TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					        method: 'put',
 | 
				
			||||||
 | 
					        url: '/material/100000000000000000000001',
 | 
				
			||||||
 | 
					        httpStatus: 401,
 | 
				
			||||||
 | 
					        req: {}
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  describe('DELETE /material/{id}', () => {
 | 
				
			||||||
 | 
					    it('deletes the material', done => {
 | 
				
			||||||
 | 
					      TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					        method: 'delete',
 | 
				
			||||||
 | 
					        url: '/material/100000000000000000000001',
 | 
				
			||||||
 | 
					        auth: {basic: 'janedoe'},
 | 
				
			||||||
 | 
					        httpStatus: 200
 | 
				
			||||||
 | 
					      }).end((err, res) => {
 | 
				
			||||||
 | 
					        if (err) return done(err);
 | 
				
			||||||
 | 
					        should(res.body).be.eql({status: 'OK'});
 | 
				
			||||||
 | 
					        MaterialModel.findById('100000000000000000000001').lean().exec((err, data) => {
 | 
				
			||||||
 | 
					          if (err) return done(err);
 | 
				
			||||||
 | 
					          should(data).be.null();
 | 
				
			||||||
 | 
					          done();
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    it('rejects deleting a material referenced by samples');
 | 
				
			||||||
 | 
					    it('rejects an invalid id', done => {
 | 
				
			||||||
 | 
					      TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					        method: 'delete',
 | 
				
			||||||
 | 
					        url: '/material/10000000000000000000000x',
 | 
				
			||||||
 | 
					        auth: {basic: 'admin'},
 | 
				
			||||||
 | 
					        httpStatus: 404
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    it('rejects an API key', done => {
 | 
				
			||||||
 | 
					      TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					        method: 'delete',
 | 
				
			||||||
 | 
					        url: '/material/100000000000000000000002',
 | 
				
			||||||
 | 
					        auth: {key: 'admin'},
 | 
				
			||||||
 | 
					        httpStatus: 401
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    it('rejects requests from a read user', done => {
 | 
				
			||||||
 | 
					      TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					        method: 'delete',
 | 
				
			||||||
 | 
					        url: '/material/100000000000000000000002',
 | 
				
			||||||
 | 
					        auth: {basic: 'user'},
 | 
				
			||||||
 | 
					        httpStatus: 403
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    it('returns 404 for an unknown id', done => {
 | 
				
			||||||
 | 
					      TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					        method: 'delete',
 | 
				
			||||||
 | 
					        url: '/material/100000000000000000000111',
 | 
				
			||||||
 | 
					        auth: {basic: 'janedoe'},
 | 
				
			||||||
 | 
					        httpStatus: 404
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    it('rejects unauthorized requests', done => {
 | 
				
			||||||
 | 
					      TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					        method: 'delete',
 | 
				
			||||||
 | 
					        url: '/material/100000000000000000000001',
 | 
				
			||||||
 | 
					        httpStatus: 401
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  describe('POST /material/new', () => {
 | 
				
			||||||
 | 
					    it('returns the right material', done => {
 | 
				
			||||||
 | 
					      TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					        method: 'post',
 | 
				
			||||||
 | 
					        url: '/material/new',
 | 
				
			||||||
 | 
					        auth: {basic: 'janedoe'},
 | 
				
			||||||
 | 
					        httpStatus: 200,
 | 
				
			||||||
 | 
					        req: {name: 'Crastin CE 2510', supplier: 'Du Pont', group: 'PBT', mineral: 0, glass_fiber: 30, carbon_fiber: 0, numbers: [{color: 'black', number: 5515798402}]}
 | 
				
			||||||
 | 
					      }).end((err, res) => {
 | 
				
			||||||
 | 
					        if (err) return done (err);
 | 
				
			||||||
 | 
					        should(res.body).have.only.keys('_id', 'name', 'supplier', 'group', 'mineral', 'glass_fiber', 'carbon_fiber', 'numbers');
 | 
				
			||||||
 | 
					        should(res.body).have.property('_id').be.type('string');
 | 
				
			||||||
 | 
					        should(res.body).have.property('name', 'Crastin CE 2510');
 | 
				
			||||||
 | 
					        should(res.body).have.property('supplier', 'Du Pont');
 | 
				
			||||||
 | 
					        should(res.body).have.property('group', 'PBT');
 | 
				
			||||||
 | 
					        should(res.body).have.property('mineral', 0);
 | 
				
			||||||
 | 
					        should(res.body).have.property('glass_fiber', 30);
 | 
				
			||||||
 | 
					        should(res.body).have.property('carbon_fiber', 0);
 | 
				
			||||||
 | 
					        should(res.body.numbers).matchEach(number => {
 | 
				
			||||||
 | 
					          should(number).have.only.keys('color', 'number');
 | 
				
			||||||
 | 
					          should(number).have.property('color', 'black');
 | 
				
			||||||
 | 
					          should(number).have.property('number', 5515798402);
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					        done();
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    it('stores the material', done => {
 | 
				
			||||||
 | 
					      TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					        method: 'post',
 | 
				
			||||||
 | 
					        url: '/material/new',
 | 
				
			||||||
 | 
					        auth: {basic: 'janedoe'},
 | 
				
			||||||
 | 
					        httpStatus: 200,
 | 
				
			||||||
 | 
					        req: {name: 'Crastin CE 2510', supplier: 'Du Pont', group: 'PBT', mineral: 0, glass_fiber: 30, carbon_fiber: 0, numbers: []}
 | 
				
			||||||
 | 
					      }).end(err => {
 | 
				
			||||||
 | 
					        if (err) return done (err);
 | 
				
			||||||
 | 
					        MaterialModel.find({name: 'Crastin CE 2510'}).lean().exec((err, data: any) => {
 | 
				
			||||||
 | 
					          if (err) return done (err);
 | 
				
			||||||
 | 
					          should(data).have.lengthOf(1);
 | 
				
			||||||
 | 
					          should(data[0]).have.only.keys('_id', 'name', 'supplier', 'group', 'mineral', 'glass_fiber', 'carbon_fiber', 'numbers', '__v');
 | 
				
			||||||
 | 
					          should(data[0]).have.property('_id');
 | 
				
			||||||
 | 
					          should(data[0]).have.property('name', 'Crastin CE 2510');
 | 
				
			||||||
 | 
					          should(data[0]).have.property('supplier', 'Du Pont');
 | 
				
			||||||
 | 
					          should(data[0]).have.property('group', 'PBT');
 | 
				
			||||||
 | 
					          should(data[0]).have.property('mineral', '0');
 | 
				
			||||||
 | 
					          should(data[0]).have.property('glass_fiber', '30');
 | 
				
			||||||
 | 
					          should(data[0]).have.property('carbon_fiber', '0');
 | 
				
			||||||
 | 
					          should(data[0].numbers).have.lengthOf(0);
 | 
				
			||||||
 | 
					          done();
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    it('rejects already existing material names', done => {
 | 
				
			||||||
 | 
					      TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					        method: 'post',
 | 
				
			||||||
 | 
					        url: '/material/new',
 | 
				
			||||||
 | 
					        auth: {basic: 'janedoe'},
 | 
				
			||||||
 | 
					        httpStatus: 400,
 | 
				
			||||||
 | 
					        req: {name: 'Stanyl TW 200 F8', supplier: 'DSM', group: 'PA46', mineral: 0, glass_fiber: 40, carbon_fiber: 0, numbers: [{color: 'black', number: 5514263423}]},
 | 
				
			||||||
 | 
					        res: {status: 'Material name already taken'}
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    it('rejects wrong material properties', done => {
 | 
				
			||||||
 | 
					      TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					        method: 'post',
 | 
				
			||||||
 | 
					        url: '/material/new',
 | 
				
			||||||
 | 
					        auth: {basic: 'janedoe'},
 | 
				
			||||||
 | 
					        httpStatus: 400,
 | 
				
			||||||
 | 
					        req: {name: 'Crastin CE 2510', supplier: 'Du Pont', group: 'PBT', mineral: 'x', glass_fiber: 'x', carbon_fiber: 'x', numbers: [{colorxx: 'black', number: 'xxx'}]},
 | 
				
			||||||
 | 
					        res: {status: 'Invalid body format'}
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    it('rejects incomplete material properties', done => {
 | 
				
			||||||
 | 
					      TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					        method: 'post',
 | 
				
			||||||
 | 
					        url: '/material/new',
 | 
				
			||||||
 | 
					        auth: {basic: 'janedoe'},
 | 
				
			||||||
 | 
					        httpStatus: 400,
 | 
				
			||||||
 | 
					        req: {name: 'Crastin CE 2510'},
 | 
				
			||||||
 | 
					        res: {status: 'Invalid body format'}
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    it('rejects an API key', done => {
 | 
				
			||||||
 | 
					      TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					        method: 'post',
 | 
				
			||||||
 | 
					        url: '/material/new',
 | 
				
			||||||
 | 
					        auth: {key: 'janedoe'},
 | 
				
			||||||
 | 
					        httpStatus: 401,
 | 
				
			||||||
 | 
					        req: {name: 'Crastin CE 2510', supplier: 'Du Pont', group: 'PBT', mineral: 0, glass_fiber: 30, carbon_fiber: 0, numbers: []}
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    it('rejects requests from a read user', done => {
 | 
				
			||||||
 | 
					      TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					        method: 'post',
 | 
				
			||||||
 | 
					        url: '/material/new',
 | 
				
			||||||
 | 
					        auth: {basic: 'user'},
 | 
				
			||||||
 | 
					        httpStatus: 403,
 | 
				
			||||||
 | 
					        req: {name: 'Crastin CE 2510', supplier: 'Du Pont', group: 'PBT', mineral: 0, glass_fiber: 30, carbon_fiber: 0, numbers: []}
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    it('rejects unauthorized requests', done => {
 | 
				
			||||||
 | 
					      TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					        method: 'post',
 | 
				
			||||||
 | 
					        url: '/material/new',
 | 
				
			||||||
 | 
					        httpStatus: 401,
 | 
				
			||||||
 | 
					        req: {name: 'Crastin CE 2510', supplier: 'Du Pont', group: 'PBT', mineral: 0, glass_fiber: 30, carbon_fiber: 0, numbers: []}
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
							
								
								
									
										110
									
								
								src/routes/material.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										110
									
								
								src/routes/material.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,110 @@
 | 
				
			|||||||
 | 
					import express from 'express';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import MaterialValidate from './validate/material';
 | 
				
			||||||
 | 
					import MaterialModel from '../models/material'
 | 
				
			||||||
 | 
					import IdValidate from './validate/id';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const router = express.Router();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					router.get('/materials', (req, res, next) => {
 | 
				
			||||||
 | 
					  if (!req.auth(res, ['read', 'write', 'maintain', 'dev', 'admin'], 'all')) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  MaterialModel.find({}).lean().exec((err, data) => {
 | 
				
			||||||
 | 
					    if (err) return next(err);
 | 
				
			||||||
 | 
					    res.json(data.map(e => MaterialValidate.output(e)).filter(e => e !== null));  // validate all and filter null values from validation errors
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					router.get('/material/' + IdValidate.parameter(), (req, res, next) => {
 | 
				
			||||||
 | 
					  if (!req.auth(res, ['read', 'write', 'maintain', 'dev', 'admin'], 'all')) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  MaterialModel.findById(req.params.id).lean().exec((err, data) => {
 | 
				
			||||||
 | 
					    if (err) return next(err);
 | 
				
			||||||
 | 
					    if (data) {
 | 
				
			||||||
 | 
					      res.json(MaterialValidate.output(data));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else {
 | 
				
			||||||
 | 
					      res.status(404).json({status: 'Not found'});
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					router.put('/material/' + IdValidate.parameter(), (req, res, next) => {
 | 
				
			||||||
 | 
					  if (!req.auth(res, ['write', 'maintain', 'dev', 'admin'], 'basic')) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const {error, value: material} = MaterialValidate.input(req.body, 'change');
 | 
				
			||||||
 | 
					  if (error) {
 | 
				
			||||||
 | 
					    res.status(400).json({status: 'Invalid body format'});
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (material.hasOwnProperty('name')) {
 | 
				
			||||||
 | 
					    MaterialModel.find({name: material.name}).lean().exec((err, data) => {
 | 
				
			||||||
 | 
					      if (err) return next(err);
 | 
				
			||||||
 | 
					      if (data.length > 0 && data[0]._id != req.params.id) {
 | 
				
			||||||
 | 
					        res.status(400).json({status: 'Material name already taken'});
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      else {
 | 
				
			||||||
 | 
					        f();
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  else {
 | 
				
			||||||
 | 
					    f();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  function f() {  // to resolve async
 | 
				
			||||||
 | 
					    MaterialModel.findByIdAndUpdate(req.params.id, material, {new: true}).lean().exec((err, data) => {
 | 
				
			||||||
 | 
					      if (err) return next(err);
 | 
				
			||||||
 | 
					      if (data) {
 | 
				
			||||||
 | 
					        res.json(MaterialValidate.output(data));
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      else {
 | 
				
			||||||
 | 
					        res.status(404).json({status: 'Not found'});
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					router.delete('/material/' + IdValidate.parameter(), (req, res, next) => {
 | 
				
			||||||
 | 
					  if (!req.auth(res, ['write', 'maintain', 'dev', 'admin'], 'basic')) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  MaterialModel.findByIdAndDelete(req.params.id).lean().exec((err, data) => {
 | 
				
			||||||
 | 
					    if (err) return next(err);
 | 
				
			||||||
 | 
					    if (data) {
 | 
				
			||||||
 | 
					      res.json({status: 'OK'})
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else {
 | 
				
			||||||
 | 
					      res.status(404).json({status: 'Not found'});
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					router.post('/material/new', (req, res, next) => {
 | 
				
			||||||
 | 
					  if (!req.auth(res, ['write', 'maintain', 'dev', 'admin'], 'basic')) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // validate input
 | 
				
			||||||
 | 
					  const {error, value: material} = MaterialValidate.input(req.body, 'new');
 | 
				
			||||||
 | 
					  if (error) {
 | 
				
			||||||
 | 
					    res.status(400).json({status: 'Invalid body format'});
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  MaterialModel.find({name: material.name}).lean().exec((err, data) => {
 | 
				
			||||||
 | 
					    if (err) return next(err);
 | 
				
			||||||
 | 
					    if (data.length > 0) {
 | 
				
			||||||
 | 
					      res.status(400).json({status: 'Material name already taken'});
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    new MaterialModel(material).save((err, data) => {
 | 
				
			||||||
 | 
					      if (err) return next(err);
 | 
				
			||||||
 | 
					      res.json(MaterialValidate.output(data.toObject()));
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module.exports = router;
 | 
				
			||||||
@@ -1,19 +1,69 @@
 | 
				
			|||||||
import supertest from 'supertest';
 | 
					import TestHelper from "../helpers/test";
 | 
				
			||||||
import should from 'should/as-function';
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
let server = supertest.agent('http://localhost:3000');
 | 
					describe('/', () => {
 | 
				
			||||||
 | 
					  let server;
 | 
				
			||||||
 | 
					  before(done => TestHelper.before(done));
 | 
				
			||||||
 | 
					  beforeEach(done => server = TestHelper.beforeEach(server, done));
 | 
				
			||||||
 | 
					  afterEach(done => TestHelper.afterEach(server, done));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
describe('Testing /', () => {
 | 
					  describe('GET /', () => {
 | 
				
			||||||
  it('returns the message object', done => {
 | 
					    it('returns the root message', done => {
 | 
				
			||||||
    server
 | 
					      TestHelper.request(server, done, {
 | 
				
			||||||
      .get('/')
 | 
					        method: 'get',
 | 
				
			||||||
      .expect('Content-type', /json/)
 | 
					        url: '/',
 | 
				
			||||||
      .expect(200)
 | 
					        httpStatus: 200,
 | 
				
			||||||
      .end(function(err, res) {
 | 
					        res: {status: 'API server up and running!'}
 | 
				
			||||||
        should(res.statusCode).equal(200);
 | 
					 | 
				
			||||||
        should(res.body).be.eql({message: 'API server up and running!'});
 | 
					 | 
				
			||||||
        done();
 | 
					 | 
				
			||||||
      });
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  describe('Unknown routes', () => {
 | 
				
			||||||
 | 
					    it('return a 404 message', done => {
 | 
				
			||||||
 | 
					      TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					        method: 'get',
 | 
				
			||||||
 | 
					        url: '/unknownroute',
 | 
				
			||||||
 | 
					        httpStatus: 404
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  describe('An unauthorized request', () => {
 | 
				
			||||||
 | 
					    it('returns a 401 message', done => {
 | 
				
			||||||
 | 
					      TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					        method: 'get',
 | 
				
			||||||
 | 
					        url: '/authorized',
 | 
				
			||||||
 | 
					        httpStatus: 401
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    it('does not work with correct username', done => {
 | 
				
			||||||
 | 
					      TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					        method: 'get',
 | 
				
			||||||
 | 
					        url: '/authorized',
 | 
				
			||||||
 | 
					        auth: {name: 'admin', pass: 'Abc123!!'},
 | 
				
			||||||
 | 
					        httpStatus: 401
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  describe('An authorized request', () => {
 | 
				
			||||||
 | 
					    it('works with an API key', done => {
 | 
				
			||||||
 | 
					      TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					        method: 'get',
 | 
				
			||||||
 | 
					        url: '/authorized',
 | 
				
			||||||
 | 
					        auth: {key: 'admin'},
 | 
				
			||||||
 | 
					        httpStatus: 200,
 | 
				
			||||||
 | 
					        res: {status: 'Authorization successful', method: 'key'}
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    it('works with basic auth', done => {
 | 
				
			||||||
 | 
					      TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					        method: 'get',
 | 
				
			||||||
 | 
					        url: '/authorized',
 | 
				
			||||||
 | 
					        auth: {basic: 'admin'},
 | 
				
			||||||
 | 
					        httpStatus: 200,
 | 
				
			||||||
 | 
					        res: {status: 'Authorization successful', method: 'basic'}
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
@@ -1,9 +1,15 @@
 | 
				
			|||||||
import express from 'express';
 | 
					import express from 'express';
 | 
				
			||||||
 | 
					import globals from '../globals';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const router = express.Router();
 | 
					const router = express.Router();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
router.get('/', (req, res) => {
 | 
					router.get('/', (req, res) => {
 | 
				
			||||||
  res.json({message: 'API server up and running!'});
 | 
					  res.json({status: 'API server up and running!'});
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					router.get('/authorized', (req, res) => {
 | 
				
			||||||
 | 
					  if (!req.auth(res, globals.levels)) return;
 | 
				
			||||||
 | 
					  res.json({status: 'Authorization successful', method: req.authDetails.method});
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
module.exports = router;
 | 
					module.exports = router;
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										336
									
								
								src/routes/sample.spec.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										336
									
								
								src/routes/sample.spec.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,336 @@
 | 
				
			|||||||
 | 
					import should from 'should/as-function';
 | 
				
			||||||
 | 
					import SampleModel from '../models/sample';
 | 
				
			||||||
 | 
					import NoteModel from '../models/note';
 | 
				
			||||||
 | 
					import NoteFieldModel from '../models/note_field';
 | 
				
			||||||
 | 
					import TestHelper from "../helpers/test";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					describe('/sample', () => {
 | 
				
			||||||
 | 
					  let server;
 | 
				
			||||||
 | 
					  before(done => TestHelper.before(done));
 | 
				
			||||||
 | 
					  beforeEach(done => server = TestHelper.beforeEach(server, done));
 | 
				
			||||||
 | 
					  afterEach(done => TestHelper.afterEach(server, done));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  describe('GET /samples', () => {
 | 
				
			||||||
 | 
					    it('returns all samples', done => {
 | 
				
			||||||
 | 
					      TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					        method: 'get',
 | 
				
			||||||
 | 
					        url: '/samples',
 | 
				
			||||||
 | 
					        auth: {basic: 'janedoe'},
 | 
				
			||||||
 | 
					        httpStatus: 200
 | 
				
			||||||
 | 
					      }).end((err, res) => {
 | 
				
			||||||
 | 
					        if (err) return done(err);
 | 
				
			||||||
 | 
					        const json = require('../test/db.json');
 | 
				
			||||||
 | 
					        should(res.body).have.lengthOf(json.collections.samples.length);
 | 
				
			||||||
 | 
					        should(res.body).matchEach(material => {
 | 
				
			||||||
 | 
					          should(material).have.only.keys('_id', 'number', 'type', 'color', 'batch', 'material_id', 'note_id', 'user_id');
 | 
				
			||||||
 | 
					          should(material).have.property('_id').be.type('string');
 | 
				
			||||||
 | 
					          should(material).have.property('number').be.type('string');
 | 
				
			||||||
 | 
					          should(material).have.property('type').be.type('string');
 | 
				
			||||||
 | 
					          should(material).have.property('color').be.type('string');
 | 
				
			||||||
 | 
					          should(material).have.property('batch').be.type('string');
 | 
				
			||||||
 | 
					          should(material).have.property('material_id').be.type('string');
 | 
				
			||||||
 | 
					          should(material).have.property('note_id');
 | 
				
			||||||
 | 
					          should(material).have.property('user_id').be.type('string');
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					        done();
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    it('works with an API key', done => {
 | 
				
			||||||
 | 
					      TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					        method: 'get',
 | 
				
			||||||
 | 
					        url: '/samples',
 | 
				
			||||||
 | 
					        auth: {key: 'janedoe'},
 | 
				
			||||||
 | 
					        httpStatus: 200
 | 
				
			||||||
 | 
					      }).end((err, res) => {
 | 
				
			||||||
 | 
					        if (err) return done(err);
 | 
				
			||||||
 | 
					        const json = require('../test/db.json');
 | 
				
			||||||
 | 
					        should(res.body).have.lengthOf(json.collections.samples.length);
 | 
				
			||||||
 | 
					        should(res.body).matchEach(material => {
 | 
				
			||||||
 | 
					          should(material).have.only.keys('_id', 'number', 'type', 'color', 'batch', 'material_id', 'note_id', 'user_id');
 | 
				
			||||||
 | 
					          should(material).have.property('_id').be.type('string');
 | 
				
			||||||
 | 
					          should(material).have.property('number').be.type('string');
 | 
				
			||||||
 | 
					          should(material).have.property('type').be.type('string');
 | 
				
			||||||
 | 
					          should(material).have.property('color').be.type('string');
 | 
				
			||||||
 | 
					          should(material).have.property('batch').be.type('string');
 | 
				
			||||||
 | 
					          should(material).have.property('material_id').be.type('string');
 | 
				
			||||||
 | 
					          should(material).have.property('note_id');
 | 
				
			||||||
 | 
					          should(material).have.property('user_id').be.type('string');
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					        done();
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    it('rejects unauthorized requests', done => {
 | 
				
			||||||
 | 
					      TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					        method: 'get',
 | 
				
			||||||
 | 
					        url: '/samples',
 | 
				
			||||||
 | 
					        httpStatus: 401
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  describe('POST /sample/new', () => {
 | 
				
			||||||
 | 
					    it('returns the right sample', done => {
 | 
				
			||||||
 | 
					      TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					        method: 'post',
 | 
				
			||||||
 | 
					        url: '/sample/new',
 | 
				
			||||||
 | 
					        auth: {basic: 'janedoe'},
 | 
				
			||||||
 | 
					        httpStatus: 200,
 | 
				
			||||||
 | 
					        req: {number: 'Rng172', color: 'black', type: 'granulate', batch: '1560237365', material_id: '100000000000000000000001', notes: {comment: 'Testcomment', sample_references: [{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', 'material_id', 'note_id', 'user_id');
 | 
				
			||||||
 | 
					        should(res.body).have.property('_id').be.type('string');
 | 
				
			||||||
 | 
					        should(res.body).have.property('number', 'Rng172');
 | 
				
			||||||
 | 
					        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('material_id', '100000000000000000000001');
 | 
				
			||||||
 | 
					        should(res.body).have.property('note_id').be.type('string');
 | 
				
			||||||
 | 
					        should(res.body).have.property('user_id', '000000000000000000000002');
 | 
				
			||||||
 | 
					        done();
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    it('stores the sample', done => {
 | 
				
			||||||
 | 
					      TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					        method: 'post',
 | 
				
			||||||
 | 
					        url: '/sample/new',
 | 
				
			||||||
 | 
					        auth: {basic: 'janedoe'},
 | 
				
			||||||
 | 
					        httpStatus: 200,
 | 
				
			||||||
 | 
					        req: {number: 'Rng172', color: 'black', type: 'granulate', batch: '1560237365', material_id: '100000000000000000000001', notes: {comment: 'Testcomment', sample_references: [{id: '400000000000000000000003', relation: 'part to this sample'}]}}
 | 
				
			||||||
 | 
					      }).end(err => {
 | 
				
			||||||
 | 
					        if (err) return done (err);
 | 
				
			||||||
 | 
					        SampleModel.find({number: 'Rng172'}).lean().exec((err, data: any) => {
 | 
				
			||||||
 | 
					          if (err) return done (err);
 | 
				
			||||||
 | 
					          should(data).have.lengthOf(1);
 | 
				
			||||||
 | 
					          should(data[0]).have.only.keys('_id', 'number', 'color', 'type', 'batch', 'material_id', 'note_id', 'user_id', '__v');
 | 
				
			||||||
 | 
					          should(data[0]).have.property('_id');
 | 
				
			||||||
 | 
					          should(data[0]).have.property('number', 'Rng172');
 | 
				
			||||||
 | 
					          should(data[0]).have.property('color', 'black');
 | 
				
			||||||
 | 
					          should(data[0]).have.property('type', 'granulate');
 | 
				
			||||||
 | 
					          should(data[0]).have.property('batch', '1560237365');
 | 
				
			||||||
 | 
					          should(data[0].material_id.toString()).be.eql('100000000000000000000001');
 | 
				
			||||||
 | 
					          should(data[0].user_id.toString()).be.eql('000000000000000000000002');
 | 
				
			||||||
 | 
					          should(data[0]).have.property('note_id');
 | 
				
			||||||
 | 
					          NoteModel.findById(data[0].note_id).lean().exec((err, data: any) => {
 | 
				
			||||||
 | 
					            if (err) return done (err);
 | 
				
			||||||
 | 
					            should(data).have.property('_id');
 | 
				
			||||||
 | 
					            should(data).have.property('comment', 'Testcomment');
 | 
				
			||||||
 | 
					            should(data).have.property('sample_references');
 | 
				
			||||||
 | 
					            should(data.sample_references).have.lengthOf(1);
 | 
				
			||||||
 | 
					            should(data.sample_references[0].id.toString()).be.eql('400000000000000000000003');
 | 
				
			||||||
 | 
					            should(data.sample_references[0]).have.property('relation', 'part to this sample');
 | 
				
			||||||
 | 
					            done();
 | 
				
			||||||
 | 
					          });
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    it('stores the custom fields', done => {
 | 
				
			||||||
 | 
					      TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					        method: 'post',
 | 
				
			||||||
 | 
					        url: '/sample/new',
 | 
				
			||||||
 | 
					        auth: {basic: 'janedoe'},
 | 
				
			||||||
 | 
					        httpStatus: 200,
 | 
				
			||||||
 | 
					        req: {number: 'Rng172', color: 'black', type: 'granulate', batch: '1560237365', material_id: '100000000000000000000001', notes: {comment: 'Testcomment', sample_references: [], custom_fields: {field1: 'a', field2: 'b', 'not allowed for new applications': true}}}
 | 
				
			||||||
 | 
					      }).end((err, res) => {
 | 
				
			||||||
 | 
					        if (err) return done (err);
 | 
				
			||||||
 | 
					        NoteModel.findById(res.body.note_id).lean().exec((err, data: any) => {
 | 
				
			||||||
 | 
					          if (err) return done(err);
 | 
				
			||||||
 | 
					          should(data).have.property('_id');
 | 
				
			||||||
 | 
					          should(data).have.property('comment', 'Testcomment');
 | 
				
			||||||
 | 
					          should(data).have.property('sample_references').have.lengthOf(0);
 | 
				
			||||||
 | 
					          should(data).have.property('custom_fields');
 | 
				
			||||||
 | 
					          should(data.custom_fields).have.property('field1', 'a');
 | 
				
			||||||
 | 
					          should(data.custom_fields).have.property('field2', 'b');
 | 
				
			||||||
 | 
					          should(data.custom_fields).have.property('not allowed for new applications', true);
 | 
				
			||||||
 | 
					          NoteFieldModel.find({name: 'field1'}).lean().exec((err, data) => {
 | 
				
			||||||
 | 
					            if (err) return done(err);
 | 
				
			||||||
 | 
					            should(data).have.lengthOf(1);
 | 
				
			||||||
 | 
					            should(data[0]).have.property('qty', 1);
 | 
				
			||||||
 | 
					            NoteFieldModel.find({name: 'field2'}).lean().exec((err, data) => {
 | 
				
			||||||
 | 
					              if (err) return done(err);
 | 
				
			||||||
 | 
					              should(data).have.lengthOf(1);
 | 
				
			||||||
 | 
					              should(data[0]).have.property('qty', 1);
 | 
				
			||||||
 | 
					              NoteFieldModel.find({name: 'not allowed for new applications'}).lean().exec((err, data) => {
 | 
				
			||||||
 | 
					                if (err) return done(err);
 | 
				
			||||||
 | 
					                should(data).have.lengthOf(1);
 | 
				
			||||||
 | 
					                should(data[0]).have.property('qty', 3);
 | 
				
			||||||
 | 
					                done();
 | 
				
			||||||
 | 
					              });
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					          });
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    it('rejects a color not defined for the material', done => {
 | 
				
			||||||
 | 
					      TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					        method: 'post',
 | 
				
			||||||
 | 
					        url: '/sample/new',
 | 
				
			||||||
 | 
					        auth: {basic: 'janedoe'},
 | 
				
			||||||
 | 
					        httpStatus: 400,
 | 
				
			||||||
 | 
					        req: {number: 'Rng172', color: 'green', type: 'granulate', batch: '1560237365', material_id: '100000000000000000000001', notes: {comment: 'Testcomment', sample_references: [{id: '400000000000000000000003', relation: 'part to this sample'}]}},
 | 
				
			||||||
 | 
					        res: {status: 'Color not available for material'}
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    it('rejects an unknown material id', done => {
 | 
				
			||||||
 | 
					      TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					        method: 'post',
 | 
				
			||||||
 | 
					        url: '/sample/new',
 | 
				
			||||||
 | 
					        auth: {basic: 'janedoe'},
 | 
				
			||||||
 | 
					        httpStatus: 400,
 | 
				
			||||||
 | 
					        req: {number: 'Rng172', color: 'black', type: 'granulate', batch: '1560237365', material_id: '000000000000000000000001', notes: {comment: 'Testcomment', sample_references: [{id: '400000000000000000000003', relation: 'part to this sample'}]}},
 | 
				
			||||||
 | 
					        res: {status: 'Material not available'}
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    it('rejects a sample number in use', done => {
 | 
				
			||||||
 | 
					      TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					        method: 'post',
 | 
				
			||||||
 | 
					        url: '/sample/new',
 | 
				
			||||||
 | 
					        auth: {basic: 'janedoe'},
 | 
				
			||||||
 | 
					        httpStatus: 400,
 | 
				
			||||||
 | 
					        req: {number: '1', color: 'black', type: 'granulate', batch: '1560237365', material_id: '100000000000000000000001', notes: {comment: 'Testcomment', sample_references: [{id: '400000000000000000000003', relation: 'part to this sample'}]}},
 | 
				
			||||||
 | 
					        res: {status: 'Sample number already taken'}
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    it('rejects an invalid sample reference', done => {
 | 
				
			||||||
 | 
					      TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					        method: 'post',
 | 
				
			||||||
 | 
					        url: '/sample/new',
 | 
				
			||||||
 | 
					        auth: {basic: 'janedoe'},
 | 
				
			||||||
 | 
					        httpStatus: 400,
 | 
				
			||||||
 | 
					        req: {number: 'Rng172', color: 'black', type: 'granulate', batch: '1560237365', material_id: '100000000000000000000001', notes: {comment: 'Testcomment', sample_references: [{id: '000000000000000000000003', relation: 'part to this sample'}]}},
 | 
				
			||||||
 | 
					        res: {status: 'Sample reference not available'}
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    it('rejects a missing color', done => {
 | 
				
			||||||
 | 
					      TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					        method: 'post',
 | 
				
			||||||
 | 
					        url: '/sample/new',
 | 
				
			||||||
 | 
					        auth: {basic: 'janedoe'},
 | 
				
			||||||
 | 
					        httpStatus: 400,
 | 
				
			||||||
 | 
					        req: {number: 'Rng172', type: 'granulate', batch: '1560237365', material_id: '100000000000000000000001', notes: {comment: 'Testcomment', sample_references: [{id: '400000000000000000000003', relation: 'part to this sample'}]}},
 | 
				
			||||||
 | 
					        res: {status: 'Invalid body format'}
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    it('rejects a missing sample number', done => {
 | 
				
			||||||
 | 
					      TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					        method: 'post',
 | 
				
			||||||
 | 
					        url: '/sample/new',
 | 
				
			||||||
 | 
					        auth: {basic: 'janedoe'},
 | 
				
			||||||
 | 
					        httpStatus: 400,
 | 
				
			||||||
 | 
					        req: {color: 'black', type: 'granulate', batch: '1560237365', material_id: '100000000000000000000001', notes: {comment: 'Testcomment', sample_references: [{id: '400000000000000000000003', relation: 'part to this sample'}]}},
 | 
				
			||||||
 | 
					        res: {status: 'Invalid body format'}
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    it('rejects a missing type', done => {
 | 
				
			||||||
 | 
					      TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					        method: 'post',
 | 
				
			||||||
 | 
					        url: '/sample/new',
 | 
				
			||||||
 | 
					        auth: {basic: 'janedoe'},
 | 
				
			||||||
 | 
					        httpStatus: 400,
 | 
				
			||||||
 | 
					        req: {number: 'Rng172', color: 'black', batch: '1560237365', material_id: '100000000000000000000001', notes: {comment: 'Testcomment', sample_references: [{id: '400000000000000000000003', relation: 'part to this sample'}]}},
 | 
				
			||||||
 | 
					        res: {status: 'Invalid body format'}
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    it('rejects a missing batch', done => {
 | 
				
			||||||
 | 
					      TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					        method: 'post',
 | 
				
			||||||
 | 
					        url: '/sample/new',
 | 
				
			||||||
 | 
					        auth: {basic: 'janedoe'},
 | 
				
			||||||
 | 
					        httpStatus: 400,
 | 
				
			||||||
 | 
					        req: {number: 'Rng172', color: 'black', type: 'granulate', material_id: '100000000000000000000001', notes: {comment: 'Testcomment', sample_references: [{id: '400000000000000000000003', relation: 'part to this sample'}]}},
 | 
				
			||||||
 | 
					        res: {status: 'Invalid body format'}
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    it('rejects a missing material id', done => {
 | 
				
			||||||
 | 
					      TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					        method: 'post',
 | 
				
			||||||
 | 
					        url: '/sample/new',
 | 
				
			||||||
 | 
					        auth: {basic: 'janedoe'},
 | 
				
			||||||
 | 
					        httpStatus: 400,
 | 
				
			||||||
 | 
					        req: {number: 'Rng172', color: 'black', type: 'granulate', batch: '1560237365', notes: {comment: 'Testcomment', sample_references: [{id: '400000000000000000000003', relation: 'part to this sample'}]}},
 | 
				
			||||||
 | 
					        res: {status: 'Invalid body format'}
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    it('rejects an invalid material id', done => {
 | 
				
			||||||
 | 
					      TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					        method: 'post',
 | 
				
			||||||
 | 
					        url: '/sample/new',
 | 
				
			||||||
 | 
					        auth: {basic: 'janedoe'},
 | 
				
			||||||
 | 
					        httpStatus: 400,
 | 
				
			||||||
 | 
					        req: {number: 'Rng172', color: 'black', type: 'granulate', batch: '1560237365', material_id: '10000000000h000000000001', notes: {comment: 'Testcomment', sample_references: [{id: '400000000000000000000003', relation: 'part to this sample'}]}},
 | 
				
			||||||
 | 
					        res: {status: 'Invalid body format'}
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    it('rejects an API key', done => {
 | 
				
			||||||
 | 
					      TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					        method: 'post',
 | 
				
			||||||
 | 
					        url: '/sample/new',
 | 
				
			||||||
 | 
					        auth: {key: 'janedoe'},
 | 
				
			||||||
 | 
					        httpStatus: 401,
 | 
				
			||||||
 | 
					        req: {number: 'Rng172', color: 'black', type: 'granulate', batch: '1560237365', material_id: '100000000000000000000001', notes: {comment: 'Testcomment', sample_references: [{id: '400000000000000000000003', relation: 'part to this sample'}]}}
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    it('rejects requests from a read user', done => {
 | 
				
			||||||
 | 
					      TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					        method: 'post',
 | 
				
			||||||
 | 
					        url: '/sample/new',
 | 
				
			||||||
 | 
					        auth: {basic: 'user'},
 | 
				
			||||||
 | 
					        httpStatus: 403,
 | 
				
			||||||
 | 
					        req: {number: 'Rng172', color: 'black', type: 'granulate', batch: '1560237365', material_id: '100000000000000000000001', notes: {comment: 'Testcomment', sample_references: [{id: '400000000000000000000003', relation: 'part to this sample'}]}}
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    it('rejects unauthorized requests', done => {
 | 
				
			||||||
 | 
					      TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					        method: 'post',
 | 
				
			||||||
 | 
					        url: '/sample/new',
 | 
				
			||||||
 | 
					        httpStatus: 401,
 | 
				
			||||||
 | 
					        req: {number: 'Rng172', color: 'black', type: 'granulate', batch: '1560237365', material_id: '100000000000000000000001', notes: {comment: 'Testcomment', sample_references: [{id: '400000000000000000000003', relation: 'part to this sample'}]}}
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  describe('GET /sample/notes/fields', () => {
 | 
				
			||||||
 | 
					    it('returns all fields', done => {
 | 
				
			||||||
 | 
					      TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					        method: 'get',
 | 
				
			||||||
 | 
					        url: '/sample/notes/fields',
 | 
				
			||||||
 | 
					        auth: {basic: 'user'},
 | 
				
			||||||
 | 
					        httpStatus: 200
 | 
				
			||||||
 | 
					      }).end((err, res) => {
 | 
				
			||||||
 | 
					        if (err) return done(err);
 | 
				
			||||||
 | 
					        const json = require('../test/db.json');
 | 
				
			||||||
 | 
					        should(res.body).have.lengthOf(json.collections.note_fields.length);
 | 
				
			||||||
 | 
					        should(res.body).matchEach(material => {
 | 
				
			||||||
 | 
					          should(material).have.only.keys('name', 'qty');
 | 
				
			||||||
 | 
					          should(material).have.property('qty').be.type('number');
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					        done();
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    it('works with an API key', done => {
 | 
				
			||||||
 | 
					      TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					        method: 'get',
 | 
				
			||||||
 | 
					        url: '/sample/notes/fields',
 | 
				
			||||||
 | 
					        auth: {key: 'user'},
 | 
				
			||||||
 | 
					        httpStatus: 200
 | 
				
			||||||
 | 
					      }).end((err, res) => {
 | 
				
			||||||
 | 
					        if (err) return done(err);
 | 
				
			||||||
 | 
					        const json = require('../test/db.json');
 | 
				
			||||||
 | 
					        should(res.body).have.lengthOf(json.collections.note_fields.length);
 | 
				
			||||||
 | 
					        should(res.body).matchEach(material => {
 | 
				
			||||||
 | 
					          should(material).have.only.keys('name', 'qty');
 | 
				
			||||||
 | 
					          should(material).have.property('qty').be.type('number');
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					        done();
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    it('rejects unauthorized requests', done => {
 | 
				
			||||||
 | 
					      TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					        method: 'get',
 | 
				
			||||||
 | 
					        url: '/sample/notes/fields',
 | 
				
			||||||
 | 
					        httpStatus: 401
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
							
								
								
									
										109
									
								
								src/routes/sample.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										109
									
								
								src/routes/sample.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,109 @@
 | 
				
			|||||||
 | 
					import express from 'express';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import SampleValidate from './validate/sample';
 | 
				
			||||||
 | 
					import NoteFieldValidate from './validate/note_field';
 | 
				
			||||||
 | 
					import SampleModel from '../models/sample'
 | 
				
			||||||
 | 
					import MaterialModel from '../models/material';
 | 
				
			||||||
 | 
					import NoteModel from '../models/note';
 | 
				
			||||||
 | 
					import NoteFieldModel from '../models/note_field';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const router = express.Router();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					router.get('/samples', (req, res, next) => {
 | 
				
			||||||
 | 
					  if (!req.auth(res, ['read', 'write', 'maintain', 'dev', 'admin'], 'all')) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  SampleModel.find({}).lean().exec((err, data) => {
 | 
				
			||||||
 | 
					    if (err) return next(err);
 | 
				
			||||||
 | 
					    res.json(data.map(e => SampleValidate.output(e)).filter(e => e !== null));  // validate all and filter null values from validation errors
 | 
				
			||||||
 | 
					  })
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					router.post('/sample/new', (req, res, next) => {
 | 
				
			||||||
 | 
					  if (!req.auth(res, ['write', 'maintain', 'dev', 'admin'], 'basic')) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const {error, value: sample} = SampleValidate.input(req.body, 'new');
 | 
				
			||||||
 | 
					  if (error) {
 | 
				
			||||||
 | 
					    return res.status(400).json({status: 'Invalid body format'});
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  MaterialModel.findById(sample.material_id).lean().exec((err, data: any) => {  // validate material_id
 | 
				
			||||||
 | 
					    if (err) return next(err);
 | 
				
			||||||
 | 
					    if (!data) {  // could not find material_id
 | 
				
			||||||
 | 
					      return res.status(400).json({status: 'Material not available'});
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (!data.numbers.find(e => e.color === sample.color)) {  // color for material not specified
 | 
				
			||||||
 | 
					      return res.status(400).json({status: 'Color not available for material'});
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    SampleModel.findOne({number: sample.number}).lean().exec((err, data) => {  // validate sample number
 | 
				
			||||||
 | 
					      if (err) return next(err);
 | 
				
			||||||
 | 
					      if (data) {  // found entry with sample number
 | 
				
			||||||
 | 
					        return res.status(400).json({status: 'Sample number already taken'});
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      if (sample.notes.sample_references.length > 0) {  // validate sample_references
 | 
				
			||||||
 | 
					        let referencesCount = sample.notes.sample_references.length;
 | 
				
			||||||
 | 
					        sample.notes.sample_references.forEach(reference => {
 | 
				
			||||||
 | 
					          SampleModel.findById(reference.id).lean().exec((err, data) => {
 | 
				
			||||||
 | 
					            if (err) return next(err);
 | 
				
			||||||
 | 
					            if (!data) {
 | 
				
			||||||
 | 
					              return res.status(400).json({status: 'Sample reference not available'});
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            referencesCount --;
 | 
				
			||||||
 | 
					            if (referencesCount <= 0) {
 | 
				
			||||||
 | 
					              f();
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					          });
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      else {
 | 
				
			||||||
 | 
					        f();
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      if (sample.notes.hasOwnProperty('custom_fields') && Object.keys(sample.notes.custom_fields).length > 0) {
 | 
				
			||||||
 | 
					        customFieldsAdd(Object.keys(sample.notes.custom_fields));
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      function f() {  // to resolve async
 | 
				
			||||||
 | 
					        new NoteModel(sample.notes).save((err, data) => {
 | 
				
			||||||
 | 
					          if (err) return next(err);
 | 
				
			||||||
 | 
					          delete sample.notes;
 | 
				
			||||||
 | 
					          sample.note_id = data._id;
 | 
				
			||||||
 | 
					          sample.user_id = req.authDetails.id;
 | 
				
			||||||
 | 
					          new SampleModel(sample).save((err, data) => {
 | 
				
			||||||
 | 
					            if (err) return next(err);
 | 
				
			||||||
 | 
					            res.json(SampleValidate.output(data.toObject()));
 | 
				
			||||||
 | 
					          });
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  })
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					router.get('/sample/notes/fields', (req, res, next) => {
 | 
				
			||||||
 | 
					  if (!req.auth(res, ['read', 'write', 'maintain', 'dev', 'admin'], 'all')) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  NoteFieldModel.find({}).lean().exec((err, data) => {
 | 
				
			||||||
 | 
					    if (err) return next(err);
 | 
				
			||||||
 | 
					    res.json(data.map(e => NoteFieldValidate.output(e)).filter(e => e !== null));  // validate all and filter null values from validation errors
 | 
				
			||||||
 | 
					  })
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module.exports = router;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function customFieldsAdd (fields) {
 | 
				
			||||||
 | 
					  fields.forEach(field => {
 | 
				
			||||||
 | 
					    NoteFieldModel.findOneAndUpdate({name: field}, {$inc: {qty: 1}}).lean().exec((err, data) => {  // check if field exists
 | 
				
			||||||
 | 
					      if (err) return console.error(err);
 | 
				
			||||||
 | 
					      if (!data) {  // new field
 | 
				
			||||||
 | 
					        new NoteFieldModel({name: field, qty: 1}).save(err => {
 | 
				
			||||||
 | 
					          if (err) return console.error(err);
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										578
									
								
								src/routes/template.spec.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										578
									
								
								src/routes/template.spec.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,578 @@
 | 
				
			|||||||
 | 
					import should from 'should/as-function';
 | 
				
			||||||
 | 
					import TemplateTreatmentModel from '../models/treatment_template';
 | 
				
			||||||
 | 
					import TemplateMeasurementModel from '../models/measurement_template';
 | 
				
			||||||
 | 
					import TestHelper from "../helpers/test";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					describe('/template', () => {
 | 
				
			||||||
 | 
					  let server;
 | 
				
			||||||
 | 
					  before(done => TestHelper.before(done));
 | 
				
			||||||
 | 
					  beforeEach(done => server = TestHelper.beforeEach(server, done));
 | 
				
			||||||
 | 
					  afterEach(done => TestHelper.afterEach(server, done));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  describe('/template/treatment', () => {
 | 
				
			||||||
 | 
					    describe('GET /template/treatments', () => {
 | 
				
			||||||
 | 
					      it('returns all treatment templates', done => {
 | 
				
			||||||
 | 
					        TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					          method: 'get',
 | 
				
			||||||
 | 
					          url: '/template/treatments',
 | 
				
			||||||
 | 
					          auth: {basic: 'janedoe'},
 | 
				
			||||||
 | 
					          httpStatus: 200
 | 
				
			||||||
 | 
					        }).end((err, res) => {
 | 
				
			||||||
 | 
					          if (err) return done(err);
 | 
				
			||||||
 | 
					          const json = require('../test/db.json');
 | 
				
			||||||
 | 
					          should(res.body).have.lengthOf(json.collections.treatment_templates.length);
 | 
				
			||||||
 | 
					          should(res.body).matchEach(treatment => {
 | 
				
			||||||
 | 
					            should(treatment).have.only.keys('_id', 'name', 'parameters');
 | 
				
			||||||
 | 
					            should(treatment).have.property('_id').be.type('string');
 | 
				
			||||||
 | 
					            should(treatment).have.property('name').be.type('string');
 | 
				
			||||||
 | 
					            should(treatment.parameters).matchEach(number => {
 | 
				
			||||||
 | 
					              should(number).have.only.keys('name', 'range');
 | 
				
			||||||
 | 
					              should(number).have.property('name').be.type('string');
 | 
				
			||||||
 | 
					              should(number).have.property('range').be.type('object');
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					          });
 | 
				
			||||||
 | 
					          done();
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      it('rejects an API key', done => {
 | 
				
			||||||
 | 
					        TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					          method: 'get',
 | 
				
			||||||
 | 
					          url: '/template/treatments',
 | 
				
			||||||
 | 
					          auth: {key: 'janedoe'},
 | 
				
			||||||
 | 
					          httpStatus: 401
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      it('rejects unauthorized requests', done => {
 | 
				
			||||||
 | 
					        TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					          method: 'get',
 | 
				
			||||||
 | 
					          url: '/template/treatments',
 | 
				
			||||||
 | 
					          httpStatus: 401
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    describe('GET /template/treatment/{name}', () => {
 | 
				
			||||||
 | 
					      it('returns the right treatment template', done => {
 | 
				
			||||||
 | 
					        TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					          method: 'get',
 | 
				
			||||||
 | 
					          url: '/template/treatment/heat%20treatment',
 | 
				
			||||||
 | 
					          auth: {basic: 'janedoe'},
 | 
				
			||||||
 | 
					          httpStatus: 200,
 | 
				
			||||||
 | 
					          res: {_id: '200000000000000000000001', name: 'heat treatment', parameters: [{name: 'material', range: {values: ['copper', 'hot air']}}, {name: 'weeks', range: {min: 1, max: 10}}]}
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      it('rejects an API key', done => {
 | 
				
			||||||
 | 
					        TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					          method: 'get',
 | 
				
			||||||
 | 
					          url: '/template/treatment/heat%20treatment',
 | 
				
			||||||
 | 
					          auth: {key: 'janedoe'},
 | 
				
			||||||
 | 
					          httpStatus: 401
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      it('rejects an unknown name', done => {
 | 
				
			||||||
 | 
					        TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					          method: 'get',
 | 
				
			||||||
 | 
					          url: '/template/treatment/xxx',
 | 
				
			||||||
 | 
					          auth: {basic: 'janedoe'},
 | 
				
			||||||
 | 
					          httpStatus: 404
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      it('rejects unauthorized requests', done => {
 | 
				
			||||||
 | 
					        TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					          method: 'get',
 | 
				
			||||||
 | 
					          url: '/template/treatment/heat%20treatment',
 | 
				
			||||||
 | 
					          httpStatus: 401
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    describe('PUT /template/treatment/{name}', () => {
 | 
				
			||||||
 | 
					      it('returns the right treatment template', done => {
 | 
				
			||||||
 | 
					        TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					          method: 'put',
 | 
				
			||||||
 | 
					          url: '/template/treatment/heat%20treatment',
 | 
				
			||||||
 | 
					          auth: {basic: 'admin'},
 | 
				
			||||||
 | 
					          httpStatus: 200,
 | 
				
			||||||
 | 
					          req: {},
 | 
				
			||||||
 | 
					          res: {_id: '200000000000000000000001', name: 'heat treatment', parameters: [{name: 'material', range: {values: ['copper', 'hot air']}}, {name: 'weeks', range: {min: 1, max: 10}}]}
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      it('keeps unchanged properties', done => {
 | 
				
			||||||
 | 
					        TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					          method: 'put',
 | 
				
			||||||
 | 
					          url: '/template/treatment/heat%20treatment',
 | 
				
			||||||
 | 
					          auth: {basic: 'admin'},
 | 
				
			||||||
 | 
					          httpStatus: 200,
 | 
				
			||||||
 | 
					          req: {name: 'heat treatment', parameters: [{name: 'material', range: {values: ['copper', 'hot air']}}, {name: 'weeks', range: {min: 1, max: 10}}]},
 | 
				
			||||||
 | 
					          res: {_id: '200000000000000000000001', name: 'heat treatment', parameters: [{name: 'material', range: {values: ['copper', 'hot air']}}, {name: 'weeks', range: {min: 1, max: 10}}]}
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      it('changes the given properties', done => {
 | 
				
			||||||
 | 
					        TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					          method: 'put',
 | 
				
			||||||
 | 
					          url: '/template/treatment/heat%20treatment',
 | 
				
			||||||
 | 
					          auth: {basic: 'admin'},
 | 
				
			||||||
 | 
					          httpStatus: 200,
 | 
				
			||||||
 | 
					          req: {name: 'heat aging', parameters: [{name: 'time', range: {min: 1}}]}
 | 
				
			||||||
 | 
					        }).end((err, res) => {
 | 
				
			||||||
 | 
					            if (err) return done(err);
 | 
				
			||||||
 | 
					            should(res.body).be.eql({_id: '200000000000000000000001', name: 'heat aging', parameters: [{name: 'time', range: {min: 1}}]});
 | 
				
			||||||
 | 
					            TemplateTreatmentModel.find({name: 'heat aging'}).lean().exec((err, data:any) => {
 | 
				
			||||||
 | 
					              if (err) return done(err);
 | 
				
			||||||
 | 
					              should(data).have.lengthOf(1);
 | 
				
			||||||
 | 
					              should(data[0]).have.only.keys('_id', 'name', 'parameters');
 | 
				
			||||||
 | 
					              should(data[0]).have.property('name', 'heat aging');
 | 
				
			||||||
 | 
					              should(data[0]).have.property('parameters').have.lengthOf(1);
 | 
				
			||||||
 | 
					              should(data[0].parameters[0]).have.property('name', 'time');
 | 
				
			||||||
 | 
					              should(data[0].parameters[0]).have.property('range');
 | 
				
			||||||
 | 
					              should(data[0].parameters[0].range).have.property('min', 1);
 | 
				
			||||||
 | 
					              done();
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					          });
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      it('supports values ranges', done => {
 | 
				
			||||||
 | 
					        TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					          method: 'put',
 | 
				
			||||||
 | 
					          url: '/template/treatment/heat%20treatment',
 | 
				
			||||||
 | 
					          auth: {basic: 'admin'},
 | 
				
			||||||
 | 
					          httpStatus: 200,
 | 
				
			||||||
 | 
					          req: {parameters: [{name: 'time', range: {values: [1, 2, 5]}}]},
 | 
				
			||||||
 | 
					          res: {_id: '200000000000000000000001', name: 'heat treatment', parameters: [{name: 'time', range: {values: [1, 2, 5]}}]}
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      it('supports min max ranges', done => {
 | 
				
			||||||
 | 
					        TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					          method: 'put',
 | 
				
			||||||
 | 
					          url: '/template/treatment/heat%20treatment',
 | 
				
			||||||
 | 
					          auth: {basic: 'admin'},
 | 
				
			||||||
 | 
					          httpStatus: 200,
 | 
				
			||||||
 | 
					          req: {parameters: [{name: 'time', range: {min: 1, max: 11}}]},
 | 
				
			||||||
 | 
					          res: {_id: '200000000000000000000001', name: 'heat treatment', parameters: [{name: 'time', range: {min: 1, max: 11}}]}
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      it('supports empty ranges', done => {
 | 
				
			||||||
 | 
					        TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					          method: 'put',
 | 
				
			||||||
 | 
					          url: '/template/treatment/heat%20treatment',
 | 
				
			||||||
 | 
					          auth: {basic: 'admin'},
 | 
				
			||||||
 | 
					          httpStatus: 200,
 | 
				
			||||||
 | 
					          req: {parameters: [{name: 'time', range: {}}]},
 | 
				
			||||||
 | 
					          res: {_id: '200000000000000000000001', name: 'heat treatment', parameters: [{name: 'time', range: {}}]}
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      it('adds a new template for an unknown name', done => {
 | 
				
			||||||
 | 
					        TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					          method: 'put',
 | 
				
			||||||
 | 
					          url: '/template/treatment/heat%20aging',
 | 
				
			||||||
 | 
					          auth: {basic: 'admin'},
 | 
				
			||||||
 | 
					          httpStatus: 200,
 | 
				
			||||||
 | 
					          req: {name: 'heat aging', parameters: [{name: 'time', range: {min: 1}}]}
 | 
				
			||||||
 | 
					        }).end(err => {
 | 
				
			||||||
 | 
					          if (err) return done(err);
 | 
				
			||||||
 | 
					          TemplateTreatmentModel.find({name: 'heat aging'}).lean().exec((err, data:any) => {
 | 
				
			||||||
 | 
					            if (err) return done(err);
 | 
				
			||||||
 | 
					            should(data).have.lengthOf(1);
 | 
				
			||||||
 | 
					            should(data[0]).have.only.keys('_id', 'name', 'parameters', '__v');
 | 
				
			||||||
 | 
					            should(data[0]).have.property('name', 'heat aging');
 | 
				
			||||||
 | 
					            should(data[0].parameters[0]).have.property('name', 'time');
 | 
				
			||||||
 | 
					            should(data[0].parameters[0]).have.property('range');
 | 
				
			||||||
 | 
					            should(data[0].parameters[0].range).have.property('min', 1);
 | 
				
			||||||
 | 
					            done();
 | 
				
			||||||
 | 
					          });
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      it('rejects an incomplete template for a new name', done => {
 | 
				
			||||||
 | 
					        TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					          method: 'put',
 | 
				
			||||||
 | 
					          url: '/template/treatment/heat%20aging',
 | 
				
			||||||
 | 
					          auth: {basic: 'admin'},
 | 
				
			||||||
 | 
					          httpStatus: 400,
 | 
				
			||||||
 | 
					          req: {parameters: [{name: 'time'}]},
 | 
				
			||||||
 | 
					          res: {status: 'Invalid body format'}
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      it('rejects already existing names', done => {
 | 
				
			||||||
 | 
					        TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					          method: 'put',
 | 
				
			||||||
 | 
					          url: '/template/treatment/heat%20treatment',
 | 
				
			||||||
 | 
					          auth: {basic: 'admin'},
 | 
				
			||||||
 | 
					          httpStatus: 400,
 | 
				
			||||||
 | 
					          req: {name: 'heat treatment 2', parameters: [{name: 'time', range: {min: 1}}]},
 | 
				
			||||||
 | 
					          res: {status: 'Template name already taken'}
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      it('rejects wrong properties', done => {
 | 
				
			||||||
 | 
					        TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					          method: 'put',
 | 
				
			||||||
 | 
					          url: '/template/treatment/heat%20aging',
 | 
				
			||||||
 | 
					          auth: {basic: 'admin'},
 | 
				
			||||||
 | 
					          httpStatus: 400,
 | 
				
			||||||
 | 
					          req: {parameters: [{name: 'time'}], xx: 33},
 | 
				
			||||||
 | 
					          res: {status: 'Invalid body format'}
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      it('rejects an API key', done => {
 | 
				
			||||||
 | 
					        TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					          method: 'put',
 | 
				
			||||||
 | 
					          url: '/template/treatment/heat%20treatment',
 | 
				
			||||||
 | 
					          auth: {key: 'admin'},
 | 
				
			||||||
 | 
					          httpStatus: 401,
 | 
				
			||||||
 | 
					          req: {}
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      it('rejects requests from a write user', done => {
 | 
				
			||||||
 | 
					        TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					          method: 'put',
 | 
				
			||||||
 | 
					          url: '/template/treatment/heat%20treatment',
 | 
				
			||||||
 | 
					          auth: {basic: 'janedoe'},
 | 
				
			||||||
 | 
					          httpStatus: 403,
 | 
				
			||||||
 | 
					          req: {}
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      it('rejects unauthorized requests', done => {
 | 
				
			||||||
 | 
					        TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					          method: 'put',
 | 
				
			||||||
 | 
					          url: '/template/treatment/heat%20treatment',
 | 
				
			||||||
 | 
					          httpStatus: 401,
 | 
				
			||||||
 | 
					          req: {}
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    describe('DELETE /template/treatment/{name}', () => {
 | 
				
			||||||
 | 
					      it('deletes the template', done => {
 | 
				
			||||||
 | 
					        TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					          method: 'delete',
 | 
				
			||||||
 | 
					          url: '/template/treatment/heat%20treatment',
 | 
				
			||||||
 | 
					          auth: {basic: 'admin'},
 | 
				
			||||||
 | 
					          httpStatus: 200
 | 
				
			||||||
 | 
					        }).end((err, res) => {
 | 
				
			||||||
 | 
					          if (err) return done(err);
 | 
				
			||||||
 | 
					          should(res.body).be.eql({status: 'OK'});
 | 
				
			||||||
 | 
					          TemplateTreatmentModel.find({name: 'heat treatment'}).lean().exec((err, data:any) => {
 | 
				
			||||||
 | 
					            if (err) return done(err);
 | 
				
			||||||
 | 
					            should(data).have.lengthOf(0);
 | 
				
			||||||
 | 
					            done();
 | 
				
			||||||
 | 
					          });
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      it('rejects deleting a template still in use');
 | 
				
			||||||
 | 
					      it('rejects an API key', done => {
 | 
				
			||||||
 | 
					        TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					          method: 'delete',
 | 
				
			||||||
 | 
					          url: '/template/treatment/heat%20treatment',
 | 
				
			||||||
 | 
					          auth: {key: 'admin'},
 | 
				
			||||||
 | 
					          httpStatus: 401
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      it('rejects requests from a write user', done => {
 | 
				
			||||||
 | 
					        TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					          method: 'delete',
 | 
				
			||||||
 | 
					          url: '/template/treatment/heat%20treatment',
 | 
				
			||||||
 | 
					          auth: {basic: 'janedoe'},
 | 
				
			||||||
 | 
					          httpStatus: 403
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      it('returns 404 for an unknown name', done => {
 | 
				
			||||||
 | 
					        TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					          method: 'delete',
 | 
				
			||||||
 | 
					          url: '/template/treatment/xxx',
 | 
				
			||||||
 | 
					          auth: {basic: 'admin'},
 | 
				
			||||||
 | 
					          httpStatus: 404
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      it('rejects unauthorized requests', done => {
 | 
				
			||||||
 | 
					        TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					          method: 'delete',
 | 
				
			||||||
 | 
					          url: '/template/treatment/heat%20treatment',
 | 
				
			||||||
 | 
					          httpStatus: 401
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  describe('/template/measurement', () => {
 | 
				
			||||||
 | 
					    describe('GET /template/measurements', () => {
 | 
				
			||||||
 | 
					      it('returns all measurement templates', done => {
 | 
				
			||||||
 | 
					        TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					          method: 'get',
 | 
				
			||||||
 | 
					          url: '/template/measurements',
 | 
				
			||||||
 | 
					          auth: {basic: 'janedoe'},
 | 
				
			||||||
 | 
					          httpStatus: 200
 | 
				
			||||||
 | 
					        }).end((err, res) => {
 | 
				
			||||||
 | 
					          if (err) return done(err);
 | 
				
			||||||
 | 
					          const json = require('../test/db.json');
 | 
				
			||||||
 | 
					          should(res.body).have.lengthOf(json.collections.measurement_templates.length);
 | 
				
			||||||
 | 
					          should(res.body).matchEach(measurement => {
 | 
				
			||||||
 | 
					            should(measurement).have.only.keys('_id', 'name', 'parameters');
 | 
				
			||||||
 | 
					            should(measurement).have.property('_id').be.type('string');
 | 
				
			||||||
 | 
					            should(measurement).have.property('name').be.type('string');
 | 
				
			||||||
 | 
					            should(measurement.parameters).matchEach(number => {
 | 
				
			||||||
 | 
					              should(number).have.only.keys('name', 'range');
 | 
				
			||||||
 | 
					              should(number).have.property('name').be.type('string');
 | 
				
			||||||
 | 
					              should(number).have.property('range').be.type('object');
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					          });
 | 
				
			||||||
 | 
					          done();
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      it('rejects an API key', done => {
 | 
				
			||||||
 | 
					        TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					          method: 'get',
 | 
				
			||||||
 | 
					          url: '/template/measurements',
 | 
				
			||||||
 | 
					          auth: {key: 'janedoe'},
 | 
				
			||||||
 | 
					          httpStatus: 401
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      it('rejects unauthorized requests', done => {
 | 
				
			||||||
 | 
					        TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					          method: 'get',
 | 
				
			||||||
 | 
					          url: '/template/measurements',
 | 
				
			||||||
 | 
					          httpStatus: 401
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    describe('GET /template/measurement/{name}', () => {
 | 
				
			||||||
 | 
					      it('returns the right measurement template', done => {
 | 
				
			||||||
 | 
					        TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					          method: 'get',
 | 
				
			||||||
 | 
					          url: '/template/measurement/spectrum',
 | 
				
			||||||
 | 
					          auth: {basic: 'janedoe'},
 | 
				
			||||||
 | 
					          httpStatus: 200,
 | 
				
			||||||
 | 
					          res: {_id: '300000000000000000000001', name: 'spectrum', parameters: [{name: 'dpt', range: {}}]}
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      it('rejects an API key', done => {
 | 
				
			||||||
 | 
					        TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					          method: 'get',
 | 
				
			||||||
 | 
					          url: '/template/measurement/spectrum',
 | 
				
			||||||
 | 
					          auth: {key: 'janedoe'},
 | 
				
			||||||
 | 
					          httpStatus: 401
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      it('rejects an unknown name', done => {
 | 
				
			||||||
 | 
					        TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					          method: 'get',
 | 
				
			||||||
 | 
					          url: '/template/measurement/xxx',
 | 
				
			||||||
 | 
					          auth: {basic: 'janedoe'},
 | 
				
			||||||
 | 
					          httpStatus: 404
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      it('rejects unauthorized requests', done => {
 | 
				
			||||||
 | 
					        TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					          method: 'get',
 | 
				
			||||||
 | 
					          url: '/template/measurement/spectrum',
 | 
				
			||||||
 | 
					          httpStatus: 401
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    describe('PUT /template/measurement/{name}', () => {
 | 
				
			||||||
 | 
					      it('returns the right measurement template', done => {
 | 
				
			||||||
 | 
					        TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					          method: 'put',
 | 
				
			||||||
 | 
					          url: '/template/measurement/spectrum',
 | 
				
			||||||
 | 
					          auth: {basic: 'admin'},
 | 
				
			||||||
 | 
					          httpStatus: 200,
 | 
				
			||||||
 | 
					          req: {},
 | 
				
			||||||
 | 
					          res: {_id: '300000000000000000000001', name: 'spectrum', parameters: [{name: 'dpt', range: {}}]}
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      it('keeps unchanged properties', done => {
 | 
				
			||||||
 | 
					        TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					          method: 'put',
 | 
				
			||||||
 | 
					          url: '/template/measurement/spectrum',
 | 
				
			||||||
 | 
					          auth: {basic: 'admin'},
 | 
				
			||||||
 | 
					          httpStatus: 200,
 | 
				
			||||||
 | 
					          req: {name: 'spectrum', parameters: [{name: 'dpt', range: {}}]},
 | 
				
			||||||
 | 
					          res: {_id: '300000000000000000000001', name: 'spectrum', parameters: [{name: 'dpt', range: {}}]}
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      it('changes the given properties', done => {
 | 
				
			||||||
 | 
					        TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					          method: 'put',
 | 
				
			||||||
 | 
					          url: '/template/measurement/spectrum',
 | 
				
			||||||
 | 
					          auth: {basic: 'admin'},
 | 
				
			||||||
 | 
					          httpStatus: 200,
 | 
				
			||||||
 | 
					          req: {name: 'IR spectrum', parameters: [{name: 'data point table', range: {min: 0, max: 1000}}]},
 | 
				
			||||||
 | 
					        }).end((err, res) => {
 | 
				
			||||||
 | 
					          if (err) return done(err);
 | 
				
			||||||
 | 
					          should(res.body).be.eql({_id: '300000000000000000000001', name: 'IR spectrum', parameters: [{name: 'data point table', range: {min: 0, max: 1000}}]});
 | 
				
			||||||
 | 
					          TemplateMeasurementModel.find({name: 'IR spectrum'}).lean().exec((err, data:any) => {
 | 
				
			||||||
 | 
					            if (err) return done(err);
 | 
				
			||||||
 | 
					            should(data).have.lengthOf(1);
 | 
				
			||||||
 | 
					            should(data[0]).have.only.keys('_id', 'name', 'parameters');
 | 
				
			||||||
 | 
					            should(data[0]).have.property('name', 'IR spectrum');
 | 
				
			||||||
 | 
					            should(data[0]).have.property('parameters').have.lengthOf(1);
 | 
				
			||||||
 | 
					            should(data[0].parameters[0]).have.property('name', 'data point table');
 | 
				
			||||||
 | 
					            should(data[0].parameters[0]).have.property('range');
 | 
				
			||||||
 | 
					            should(data[0].parameters[0].range).have.property('min', 0);
 | 
				
			||||||
 | 
					            should(data[0].parameters[0].range).have.property('max', 1000);
 | 
				
			||||||
 | 
					            done();
 | 
				
			||||||
 | 
					          });
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      it('supports values ranges', done => {
 | 
				
			||||||
 | 
					        TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					          method: 'put',
 | 
				
			||||||
 | 
					          url: '/template/measurement/spectrum',
 | 
				
			||||||
 | 
					          auth: {basic: 'admin'},
 | 
				
			||||||
 | 
					          httpStatus: 200,
 | 
				
			||||||
 | 
					          req: {parameters: [{name: 'dpt', range: {values: [1, 2, 5]}}]},
 | 
				
			||||||
 | 
					          res: {_id: '300000000000000000000001', name: 'spectrum', parameters: [{name: 'dpt', range: {values: [1, 2, 5]}}]}
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      it('supports min max ranges', done => {
 | 
				
			||||||
 | 
					        TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					          method: 'put',
 | 
				
			||||||
 | 
					          url: '/template/measurement/spectrum',
 | 
				
			||||||
 | 
					          auth: {basic: 'admin'},
 | 
				
			||||||
 | 
					          httpStatus: 200,
 | 
				
			||||||
 | 
					          req: {parameters: [{name: 'dpt', range: {min: 0, max: 1000}}]},
 | 
				
			||||||
 | 
					          res: {_id: '300000000000000000000001', name: 'spectrum', parameters: [{name: 'dpt', range: {min: 0, max: 1000}}]}
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      it('supports empty ranges', done => {
 | 
				
			||||||
 | 
					        TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					          method: 'put',
 | 
				
			||||||
 | 
					          url: '/template/measurement/kf',
 | 
				
			||||||
 | 
					          auth: {basic: 'admin'},
 | 
				
			||||||
 | 
					          httpStatus: 200,
 | 
				
			||||||
 | 
					          req: {parameters: [{name: 'weight %', range: {}}]},
 | 
				
			||||||
 | 
					          res: {_id: '300000000000000000000002', name: 'kf', parameters: [{name: 'weight %', range: {}}]}
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      it('adds a new template for an unknown name', done => {
 | 
				
			||||||
 | 
					        TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					          method: 'put',
 | 
				
			||||||
 | 
					          url: '/template/measurement/vz',
 | 
				
			||||||
 | 
					          auth: {basic: 'admin'},
 | 
				
			||||||
 | 
					          httpStatus: 200,
 | 
				
			||||||
 | 
					          req: {name: 'vz', parameters: [{name: 'vz', range: {min: 1}}]}
 | 
				
			||||||
 | 
					        }).end(err => {
 | 
				
			||||||
 | 
					          if (err) return done(err);
 | 
				
			||||||
 | 
					          TemplateMeasurementModel.find({name: 'vz'}).lean().exec((err, data:any) => {
 | 
				
			||||||
 | 
					            if (err) return done(err);
 | 
				
			||||||
 | 
					            should(data).have.lengthOf(1);
 | 
				
			||||||
 | 
					            should(data[0]).have.only.keys('_id', 'name', 'parameters', '__v');
 | 
				
			||||||
 | 
					            should(data[0]).have.property('name', 'vz');
 | 
				
			||||||
 | 
					            should(data[0]).have.property('parameters').have.lengthOf(1);
 | 
				
			||||||
 | 
					            should(data[0].parameters[0]).have.property('name', 'vz');
 | 
				
			||||||
 | 
					            should(data[0].parameters[0]).have.property('range');
 | 
				
			||||||
 | 
					            should(data[0].parameters[0].range).have.property('min', 1);
 | 
				
			||||||
 | 
					            done();
 | 
				
			||||||
 | 
					          });
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      it('rejects an incomplete template for a new name', done => {
 | 
				
			||||||
 | 
					        TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					          method: 'put',
 | 
				
			||||||
 | 
					          url: '/template/measurement/vz',
 | 
				
			||||||
 | 
					          auth: {basic: 'admin'},
 | 
				
			||||||
 | 
					          httpStatus: 400,
 | 
				
			||||||
 | 
					          req: {parameters: [{name: 'vz'}]},
 | 
				
			||||||
 | 
					          res: {status: 'Invalid body format'}
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      it('rejects already existing names', done => {
 | 
				
			||||||
 | 
					        TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					          method: 'put',
 | 
				
			||||||
 | 
					          url: '/template/measurement/spectrum',
 | 
				
			||||||
 | 
					          auth: {basic: 'admin'},
 | 
				
			||||||
 | 
					          httpStatus: 400,
 | 
				
			||||||
 | 
					          req: {name: 'kf', parameters: [{name: 'dpt', range: {min: 1}}]},
 | 
				
			||||||
 | 
					          res: {status: 'Template name already taken'}
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      it('rejects wrong properties', done => {
 | 
				
			||||||
 | 
					        TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					          method: 'put',
 | 
				
			||||||
 | 
					          url: '/template/measurement/spectrum',
 | 
				
			||||||
 | 
					          auth: {basic: 'admin'},
 | 
				
			||||||
 | 
					          httpStatus: 400,
 | 
				
			||||||
 | 
					          req: {parameters: [{name: 'dpt'}], xx: 33},
 | 
				
			||||||
 | 
					          res: {status: 'Invalid body format'}
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      it('rejects an API key', done => {
 | 
				
			||||||
 | 
					        TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					          method: 'put',
 | 
				
			||||||
 | 
					          url: '/template/measurement/spectrum',
 | 
				
			||||||
 | 
					          auth: {key: 'admin'},
 | 
				
			||||||
 | 
					          httpStatus: 401,
 | 
				
			||||||
 | 
					          req: {}
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      it('rejects requests from a write user', done => {
 | 
				
			||||||
 | 
					        TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					          method: 'put',
 | 
				
			||||||
 | 
					          url: '/template/measurement/spectrum',
 | 
				
			||||||
 | 
					          auth: {basic: 'janedoe'},
 | 
				
			||||||
 | 
					          httpStatus: 403,
 | 
				
			||||||
 | 
					          req: {}
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      it('rejects unauthorized requests', done => {
 | 
				
			||||||
 | 
					        TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					          method: 'put',
 | 
				
			||||||
 | 
					          url: '/template/measurement/spectrum',
 | 
				
			||||||
 | 
					          httpStatus: 401,
 | 
				
			||||||
 | 
					          req: {}
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    describe('DELETE /template/measurement/{name}', () => {
 | 
				
			||||||
 | 
					      it('deletes the template', done => {
 | 
				
			||||||
 | 
					        TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					          method: 'delete',
 | 
				
			||||||
 | 
					          url: '/template/measurement/spectrum',
 | 
				
			||||||
 | 
					          auth: {basic: 'admin'},
 | 
				
			||||||
 | 
					          httpStatus: 200
 | 
				
			||||||
 | 
					        }).end((err, res) => {
 | 
				
			||||||
 | 
					          if (err) return done(err);
 | 
				
			||||||
 | 
					          should(res.body).be.eql({status: 'OK'});
 | 
				
			||||||
 | 
					          TemplateMeasurementModel.find({name: 'spectrum'}).lean().exec((err, data:any) => {
 | 
				
			||||||
 | 
					            if (err) return done(err);
 | 
				
			||||||
 | 
					            should(data).have.lengthOf(0);
 | 
				
			||||||
 | 
					            done();
 | 
				
			||||||
 | 
					          });
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      it('rejects deleting a template still in use');
 | 
				
			||||||
 | 
					      it('rejects an API key', done => {
 | 
				
			||||||
 | 
					        TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					          method: 'delete',
 | 
				
			||||||
 | 
					          url: '/template/measurement/spectrum',
 | 
				
			||||||
 | 
					          auth: {key: 'admin'},
 | 
				
			||||||
 | 
					          httpStatus: 401
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      it('rejects requests from a write user', done => {
 | 
				
			||||||
 | 
					        TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					          method: 'delete',
 | 
				
			||||||
 | 
					          url: '/template/measurement/spectrum',
 | 
				
			||||||
 | 
					          auth: {basic: 'janedoe'},
 | 
				
			||||||
 | 
					          httpStatus: 403
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      it('returns 404 for an unknown name', done => {
 | 
				
			||||||
 | 
					        TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					          method: 'delete',
 | 
				
			||||||
 | 
					          url: '/template/measurement/xxx',
 | 
				
			||||||
 | 
					          auth: {basic: 'admin'},
 | 
				
			||||||
 | 
					          httpStatus: 404
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      it('rejects unauthorized requests', done => {
 | 
				
			||||||
 | 
					        TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					          method: 'delete',
 | 
				
			||||||
 | 
					          url: '/template/measurement/spectrum',
 | 
				
			||||||
 | 
					          httpStatus: 401
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
							
								
								
									
										90
									
								
								src/routes/template.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										90
									
								
								src/routes/template.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,90 @@
 | 
				
			|||||||
 | 
					import express from 'express';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import TemplateValidate from './validate/template';
 | 
				
			||||||
 | 
					import TemplateTreatmentModel from '../models/treatment_template';
 | 
				
			||||||
 | 
					import TemplateMeasurementModel from '../models/measurement_template';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const router = express.Router();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					router.get('/template/:collection(measurements|treatments)', (req, res, next) => {
 | 
				
			||||||
 | 
					  if (!req.auth(res, ['read', 'write', 'maintain', 'dev', 'admin'], 'basic')) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  (req.params.collection === 'treatments' ? TemplateTreatmentModel : TemplateMeasurementModel)
 | 
				
			||||||
 | 
					    .find({}).lean().exec((err, data) => {
 | 
				
			||||||
 | 
					     if (err) next (err);
 | 
				
			||||||
 | 
					     res.json(data.map(e => TemplateValidate.output(e)).filter(e => e !== null));  // validate all and filter null values from validation errors
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					router.get('/template/:collection(measurement|treatment)/:name', (req, res, next) => {
 | 
				
			||||||
 | 
					  if (!req.auth(res, ['read', 'write', 'maintain', 'dev', 'admin'], 'basic')) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  (req.params.collection === 'treatment' ? TemplateTreatmentModel : TemplateMeasurementModel)
 | 
				
			||||||
 | 
					    .findOne({name: req.params.name}).lean().exec((err, data) => {
 | 
				
			||||||
 | 
					    if (err) next (err);
 | 
				
			||||||
 | 
					    if (data) {
 | 
				
			||||||
 | 
					      res.json(TemplateValidate.output(data));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else {
 | 
				
			||||||
 | 
					      res.status(404).json({status: 'Not found'});
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					router.put('/template/:collection(measurement|treatment)/:name', (req, res, next) => {
 | 
				
			||||||
 | 
					  if (!req.auth(res, ['maintain', 'admin'], 'basic')) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const collectionModel = req.params.collection === 'treatment' ? TemplateTreatmentModel : TemplateMeasurementModel;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  collectionModel.findOne({name: req.params.name}).lean().exec((err, data) => {
 | 
				
			||||||
 | 
					    if (err) next (err);
 | 
				
			||||||
 | 
					    const templateState = data? 'change': 'new';
 | 
				
			||||||
 | 
					    const {error, value: template} = TemplateValidate.input(req.body, templateState);
 | 
				
			||||||
 | 
					    if (error) {
 | 
				
			||||||
 | 
					      res.status(400).json({status: 'Invalid body format'});
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (template.hasOwnProperty('name') && template.name !== req.params.name) {
 | 
				
			||||||
 | 
					      collectionModel.find({name: template.name}).lean().exec((err, data) => {
 | 
				
			||||||
 | 
					        if (err) next (err);
 | 
				
			||||||
 | 
					        if (data.length > 0) {
 | 
				
			||||||
 | 
					          res.status(400).json({status: 'Template name already taken'});
 | 
				
			||||||
 | 
					          return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else {
 | 
				
			||||||
 | 
					          f();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else {
 | 
				
			||||||
 | 
					      f();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function f() {  // to resolve async
 | 
				
			||||||
 | 
					      collectionModel.findOneAndUpdate({name: req.params.name}, template, {new: true, upsert: true}).lean().exec((err, data) => {
 | 
				
			||||||
 | 
					        if (err) return next(err);
 | 
				
			||||||
 | 
					        res.json(TemplateValidate.output(data));
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					router.delete('/template/:collection(measurement|treatment)/:name', (req, res, next) => {
 | 
				
			||||||
 | 
					  if (!req.auth(res, ['maintain', 'admin'], 'basic')) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  (req.params.collection === 'treatment' ? TemplateTreatmentModel : TemplateMeasurementModel)
 | 
				
			||||||
 | 
					    .findOneAndDelete({name: req.params.name}).lean().exec((err, data) => {
 | 
				
			||||||
 | 
					    if (err) return next(err);
 | 
				
			||||||
 | 
					    if (data) {
 | 
				
			||||||
 | 
					      res.json({status: 'OK'})
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else {
 | 
				
			||||||
 | 
					      res.status(404).json({status: 'Not found'});
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module.exports = router;
 | 
				
			||||||
							
								
								
									
										626
									
								
								src/routes/user.spec.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										626
									
								
								src/routes/user.spec.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,626 @@
 | 
				
			|||||||
 | 
					import should from 'should/as-function';
 | 
				
			||||||
 | 
					import UserModel from '../models/user';
 | 
				
			||||||
 | 
					import TestHelper from "../helpers/test";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					describe('/user', () => {
 | 
				
			||||||
 | 
					  let server;
 | 
				
			||||||
 | 
					  before(done => TestHelper.before(done));
 | 
				
			||||||
 | 
					  beforeEach(done => server = TestHelper.beforeEach(server, done));
 | 
				
			||||||
 | 
					  afterEach(done => TestHelper.afterEach(server, done));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  describe('GET /users', () => {
 | 
				
			||||||
 | 
					    it('returns all users', done => {
 | 
				
			||||||
 | 
					      TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					        method: 'get',
 | 
				
			||||||
 | 
					        url: '/users',
 | 
				
			||||||
 | 
					        auth: {basic: 'admin'},
 | 
				
			||||||
 | 
					        httpStatus: 200
 | 
				
			||||||
 | 
					      }).end((err, res) => {
 | 
				
			||||||
 | 
					        if (err) return done(err);
 | 
				
			||||||
 | 
					        const json = require('../test/db.json');
 | 
				
			||||||
 | 
					        should(res.body).have.lengthOf(json.collections.users.length);
 | 
				
			||||||
 | 
					        should(res.body).matchEach(user => {
 | 
				
			||||||
 | 
					          should(user).have.only.keys('_id', 'email', 'name', 'level', 'location', 'device_name');
 | 
				
			||||||
 | 
					          should(user).have.property('_id').be.type('string');
 | 
				
			||||||
 | 
					          should(user).have.property('email').be.type('string');
 | 
				
			||||||
 | 
					          should(user).have.property('name').be.type('string');
 | 
				
			||||||
 | 
					          should(user).have.property('level').be.type('string');
 | 
				
			||||||
 | 
					          should(user).have.property('location').be.type('string');
 | 
				
			||||||
 | 
					          should(user).have.property('device_name').be.type('string');
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					        done();
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    it('rejects requests from non-admins', done => {
 | 
				
			||||||
 | 
					      TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					        method: 'get',
 | 
				
			||||||
 | 
					        url: '/users',
 | 
				
			||||||
 | 
					        auth: {basic: 'janedoe'},
 | 
				
			||||||
 | 
					        httpStatus: 403
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    it('rejects requests from an admin API key', done => {
 | 
				
			||||||
 | 
					      TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					        method: 'get',
 | 
				
			||||||
 | 
					        url: '/users',
 | 
				
			||||||
 | 
					        auth: {key: 'admin'},
 | 
				
			||||||
 | 
					        httpStatus: 401
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    it('rejects unauthorized requests', done => {
 | 
				
			||||||
 | 
					      TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					        method: 'get',
 | 
				
			||||||
 | 
					        url: '/users',
 | 
				
			||||||
 | 
					        httpStatus: 401
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  describe('GET /user/{name}', () => {
 | 
				
			||||||
 | 
					    it('returns own user details', done => {
 | 
				
			||||||
 | 
					      TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					        method: 'get',
 | 
				
			||||||
 | 
					        url: '/user',
 | 
				
			||||||
 | 
					        auth: {basic: 'janedoe'},
 | 
				
			||||||
 | 
					        httpStatus: 200
 | 
				
			||||||
 | 
					      }).end((err, res) => {
 | 
				
			||||||
 | 
					        if (err) return done (err);
 | 
				
			||||||
 | 
					        should(res.body).have.only.keys('_id', 'email', 'name', 'level', 'location', 'device_name');
 | 
				
			||||||
 | 
					        should(res.body).have.property('_id').be.type('string');
 | 
				
			||||||
 | 
					        should(res.body).have.property('email', 'jane.doe@bosch.com');
 | 
				
			||||||
 | 
					        should(res.body).have.property('name', 'janedoe');
 | 
				
			||||||
 | 
					        should(res.body).have.property('level', 'write');
 | 
				
			||||||
 | 
					        should(res.body).have.property('location', 'Rng');
 | 
				
			||||||
 | 
					        should(res.body).have.property('device_name', 'Alpha I');
 | 
				
			||||||
 | 
					        done();
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    it('returns other user details for admin', done => {
 | 
				
			||||||
 | 
					      TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					        method: 'get',
 | 
				
			||||||
 | 
					        url: '/user/janedoe',
 | 
				
			||||||
 | 
					        auth: {basic: 'admin'},
 | 
				
			||||||
 | 
					        httpStatus: 200
 | 
				
			||||||
 | 
					      }).end((err, res) => {
 | 
				
			||||||
 | 
					          if (err) return done (err);
 | 
				
			||||||
 | 
					          should(res.body).have.only.keys('_id', 'email', 'name', 'level', 'location', 'device_name');
 | 
				
			||||||
 | 
					          should(res.body).have.property('_id').be.type('string');
 | 
				
			||||||
 | 
					          should(res.body).have.property('email', 'jane.doe@bosch.com');
 | 
				
			||||||
 | 
					          should(res.body).have.property('name', 'janedoe');
 | 
				
			||||||
 | 
					          should(res.body).have.property('level', 'write');
 | 
				
			||||||
 | 
					          should(res.body).have.property('location', 'Rng');
 | 
				
			||||||
 | 
					          should(res.body).have.property('device_name', 'Alpha I');
 | 
				
			||||||
 | 
					          done();
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    it('rejects requests from non-admins for another user', done => {
 | 
				
			||||||
 | 
					      TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					        method: 'get',
 | 
				
			||||||
 | 
					        url: '/user/admin',
 | 
				
			||||||
 | 
					        auth: {basic: 'janedoe'},
 | 
				
			||||||
 | 
					        httpStatus: 403
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    it('rejects requests from a user API key', done => {
 | 
				
			||||||
 | 
					      TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					        method: 'get',
 | 
				
			||||||
 | 
					        url: '/user',
 | 
				
			||||||
 | 
					        auth: {key: 'janedoe'},
 | 
				
			||||||
 | 
					        httpStatus: 401
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    it('rejects requests from an admin API key', done => {
 | 
				
			||||||
 | 
					      TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					        method: 'get',
 | 
				
			||||||
 | 
					        url: '/user/janedoe',
 | 
				
			||||||
 | 
					        auth: {key: 'janedoe'},
 | 
				
			||||||
 | 
					        httpStatus: 401
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    it('returns 404 for an unknown user', done => {
 | 
				
			||||||
 | 
					      TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					        method: 'get',
 | 
				
			||||||
 | 
					        url: '/user/unknown',
 | 
				
			||||||
 | 
					        auth: {basic: 'admin'},
 | 
				
			||||||
 | 
					        httpStatus: 404
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    it('rejects requests from an admin API key', done => {
 | 
				
			||||||
 | 
					      TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					        method: 'get',
 | 
				
			||||||
 | 
					        url: '/user/janedoe',
 | 
				
			||||||
 | 
					        httpStatus: 401
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  describe('PUT /user/{name}', () => {
 | 
				
			||||||
 | 
					    it('returns own user details', done => {
 | 
				
			||||||
 | 
					      TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					        method: 'put',
 | 
				
			||||||
 | 
					        url: '/user',
 | 
				
			||||||
 | 
					        auth: {basic: 'janedoe'},
 | 
				
			||||||
 | 
					        httpStatus: 200,
 | 
				
			||||||
 | 
					        req: {}
 | 
				
			||||||
 | 
					      }).end((err, res) => {
 | 
				
			||||||
 | 
					          if (err) return done (err);
 | 
				
			||||||
 | 
					          should(res.body).have.only.keys('_id', 'email', 'name', 'level', 'location', 'device_name');
 | 
				
			||||||
 | 
					          should(res.body).have.property('_id').be.type('string');
 | 
				
			||||||
 | 
					          should(res.body).have.property('email', 'jane.doe@bosch.com');
 | 
				
			||||||
 | 
					          should(res.body).have.property('name', 'janedoe');
 | 
				
			||||||
 | 
					          should(res.body).have.property('level', 'write');
 | 
				
			||||||
 | 
					          should(res.body).have.property('location', 'Rng');
 | 
				
			||||||
 | 
					          should(res.body).have.property('device_name', 'Alpha I');
 | 
				
			||||||
 | 
					          done();
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    it('returns other user details for admin', done => {
 | 
				
			||||||
 | 
					      TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					        method: 'put',
 | 
				
			||||||
 | 
					        url: '/user/janedoe',
 | 
				
			||||||
 | 
					        auth: {basic: 'admin'},
 | 
				
			||||||
 | 
					        httpStatus: 200,
 | 
				
			||||||
 | 
					        req: {}
 | 
				
			||||||
 | 
					      }).end((err, res) => {
 | 
				
			||||||
 | 
					          if (err) return done (err);
 | 
				
			||||||
 | 
					          should(res.body).have.only.keys('_id', 'email', 'name', 'level', 'location', 'device_name');
 | 
				
			||||||
 | 
					          should(res.body).have.property('_id').be.type('string');
 | 
				
			||||||
 | 
					          should(res.body).have.property('email', 'jane.doe@bosch.com');
 | 
				
			||||||
 | 
					          should(res.body).have.property('name', 'janedoe');
 | 
				
			||||||
 | 
					          should(res.body).have.property('level', 'write');
 | 
				
			||||||
 | 
					          should(res.body).have.property('location', 'Rng');
 | 
				
			||||||
 | 
					          should(res.body).have.property('device_name', 'Alpha I');
 | 
				
			||||||
 | 
					          done();
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    it('changes user details as given', done => {
 | 
				
			||||||
 | 
					      TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					        method: 'put',
 | 
				
			||||||
 | 
					        url: '/user',
 | 
				
			||||||
 | 
					        auth: {basic: 'admin'},
 | 
				
			||||||
 | 
					        httpStatus: 200,
 | 
				
			||||||
 | 
					        req: {name: 'adminnew', email: 'adminnew@bosch.com', pass: 'Abc123##', location: 'Abt', device_name: 'test'}
 | 
				
			||||||
 | 
					      }).end(err => {
 | 
				
			||||||
 | 
					          if (err) return done (err);
 | 
				
			||||||
 | 
					          UserModel.find({name: 'adminnew'}).lean().exec( (err, data) => {
 | 
				
			||||||
 | 
					            if (err) return done(err);
 | 
				
			||||||
 | 
					            should(data).have.lengthOf(1);
 | 
				
			||||||
 | 
					            should(data[0]).have.only.keys('_id', 'name', 'pass', 'email', 'level', 'location', 'device_name', 'key', '__v');
 | 
				
			||||||
 | 
					            should(data[0]).have.property('_id');
 | 
				
			||||||
 | 
					            should(data[0]).have.property('name', 'adminnew');
 | 
				
			||||||
 | 
					            should(data[0]).have.property('email', 'adminnew@bosch.com');
 | 
				
			||||||
 | 
					            should(data[0]).have.property('pass').not.eql('Abc123##');
 | 
				
			||||||
 | 
					            should(data[0]).have.property('level', 'admin');
 | 
				
			||||||
 | 
					            should(data[0]).have.property('location', 'Abt');
 | 
				
			||||||
 | 
					            should(data[0]).have.property('device_name', 'test');
 | 
				
			||||||
 | 
					            done();
 | 
				
			||||||
 | 
					          });
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    it('lets the admin change a user level', done => {
 | 
				
			||||||
 | 
					      TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					        method: 'put',
 | 
				
			||||||
 | 
					        url: '/user/janedoe',
 | 
				
			||||||
 | 
					        auth: {basic: 'admin'},
 | 
				
			||||||
 | 
					        httpStatus: 200,
 | 
				
			||||||
 | 
					        req: {level: 'read'}
 | 
				
			||||||
 | 
					      }).end(err => {
 | 
				
			||||||
 | 
					          if (err) return done (err);
 | 
				
			||||||
 | 
					          UserModel.find({name: 'janedoe'}).lean().exec( (err, data) => {
 | 
				
			||||||
 | 
					            if (err) return done(err);
 | 
				
			||||||
 | 
					            should(data).have.lengthOf(1);
 | 
				
			||||||
 | 
					            should(data[0]).have.property('level', 'read');
 | 
				
			||||||
 | 
					            done();
 | 
				
			||||||
 | 
					          });
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    it('does not change the level', done => {
 | 
				
			||||||
 | 
					      TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					        method: 'put',
 | 
				
			||||||
 | 
					        url: '/user',
 | 
				
			||||||
 | 
					        auth: {basic: 'janedoe'},
 | 
				
			||||||
 | 
					        httpStatus: 400, default: false,
 | 
				
			||||||
 | 
					        req: {level: 'read'}
 | 
				
			||||||
 | 
					      }).end((err, res) => {
 | 
				
			||||||
 | 
					          if (err) return done (err);
 | 
				
			||||||
 | 
					          should(res.body).be.eql({status: 'Invalid body format'});
 | 
				
			||||||
 | 
					          UserModel.find({name: 'janedoe'}).lean().exec( (err, data) => {
 | 
				
			||||||
 | 
					            if (err) return done(err);
 | 
				
			||||||
 | 
					            should(data).have.lengthOf(1);
 | 
				
			||||||
 | 
					            should(data[0]).have.property('level', 'write');
 | 
				
			||||||
 | 
					            done();
 | 
				
			||||||
 | 
					          });
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    it('rejects a username already in use', done => {
 | 
				
			||||||
 | 
					      TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					        method: 'put',
 | 
				
			||||||
 | 
					        url: '/user',
 | 
				
			||||||
 | 
					        auth: {basic: 'admin'},
 | 
				
			||||||
 | 
					        httpStatus: 400, default: false,
 | 
				
			||||||
 | 
					        req: {name: 'janedoe'}
 | 
				
			||||||
 | 
					      }).end((err, res) => {
 | 
				
			||||||
 | 
					          if (err) return done (err);
 | 
				
			||||||
 | 
					          should(res.body).be.eql({status: 'Username already taken'});
 | 
				
			||||||
 | 
					          UserModel.find({name: 'janedoe'}).lean().exec( (err, data) => {
 | 
				
			||||||
 | 
					            if (err) return done(err);
 | 
				
			||||||
 | 
					            should(data).have.lengthOf(1);
 | 
				
			||||||
 | 
					            done();
 | 
				
			||||||
 | 
					          });
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    it('rejects a username which is in the special names', done => {
 | 
				
			||||||
 | 
					      TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					        method: 'post',
 | 
				
			||||||
 | 
					        url: '/user/new',
 | 
				
			||||||
 | 
					        auth: {basic: 'admin'},
 | 
				
			||||||
 | 
					        httpStatus: 400, default: false,
 | 
				
			||||||
 | 
					        req: {email: 'j.doe@bosch.com', name: 'passreset', pass: 'Abc123!#', level: 'read', location: 'Rng', device_name: 'Alpha II'},
 | 
				
			||||||
 | 
					        res: {status: 'Username already taken'}
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    it('rejects invalid user details', done => {
 | 
				
			||||||
 | 
					      TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					        method: 'put',
 | 
				
			||||||
 | 
					        url: '/user',
 | 
				
			||||||
 | 
					        auth: {basic: 'admin'},
 | 
				
			||||||
 | 
					        httpStatus: 400,
 | 
				
			||||||
 | 
					        req: {email: 'john.doe@bosch.com', name: 'johndoe', pass: 'Abc123!#', location: 44, device_name: 'Alpha II'},
 | 
				
			||||||
 | 
					        res: {status: 'Invalid body format'}
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    it('rejects an invalid email address', done => {
 | 
				
			||||||
 | 
					      TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					        method: 'put',
 | 
				
			||||||
 | 
					        url: '/user',
 | 
				
			||||||
 | 
					        auth: {basic: 'admin'},
 | 
				
			||||||
 | 
					        httpStatus: 400,
 | 
				
			||||||
 | 
					        req: {email: 'john.doe'},
 | 
				
			||||||
 | 
					        res: {status: 'Invalid body format'}
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    it('rejects an invalid password', done => {
 | 
				
			||||||
 | 
					      TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					        method: 'put',
 | 
				
			||||||
 | 
					        url: '/user',
 | 
				
			||||||
 | 
					        auth: {basic: 'admin'},
 | 
				
			||||||
 | 
					        httpStatus: 400,
 | 
				
			||||||
 | 
					        req: {pass: 'password'},
 | 
				
			||||||
 | 
					        res: {status: 'Invalid body format'}
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    it('rejects requests from non-admins for another user', done => {
 | 
				
			||||||
 | 
					      TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					        method: 'put',
 | 
				
			||||||
 | 
					        url: '/user/admin',
 | 
				
			||||||
 | 
					        auth: {basic: 'janedoe'},
 | 
				
			||||||
 | 
					        httpStatus: 403,
 | 
				
			||||||
 | 
					        req: {}
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    it('rejects requests from a user API key', done => {
 | 
				
			||||||
 | 
					      TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					        method: 'put',
 | 
				
			||||||
 | 
					        url: '/user',
 | 
				
			||||||
 | 
					        auth: {key: 'janedoe'},
 | 
				
			||||||
 | 
					        httpStatus: 401,
 | 
				
			||||||
 | 
					        req: {}
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    it('rejects requests from an admin API key', done => {
 | 
				
			||||||
 | 
					      TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					        method: 'put',
 | 
				
			||||||
 | 
					        url: '/user/janedoe',
 | 
				
			||||||
 | 
					        auth: {key: 'admin'},
 | 
				
			||||||
 | 
					        httpStatus: 401,
 | 
				
			||||||
 | 
					        req: {}
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    it('returns 404 for an unknown user', done => {
 | 
				
			||||||
 | 
					      TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					        method: 'put',
 | 
				
			||||||
 | 
					        url: '/user/unknown',
 | 
				
			||||||
 | 
					        auth: {basic: 'admin'},
 | 
				
			||||||
 | 
					        httpStatus: 404,
 | 
				
			||||||
 | 
					        req: {}
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    it('rejects unauthorized requests', done => {
 | 
				
			||||||
 | 
					      TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					        method: 'put',
 | 
				
			||||||
 | 
					        url: '/user/janedoe',
 | 
				
			||||||
 | 
					        httpStatus: 401,
 | 
				
			||||||
 | 
					        req: {}
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  describe('DELETE /user/{name}', () => {
 | 
				
			||||||
 | 
					    it('deletes own user details', done => {
 | 
				
			||||||
 | 
					      TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					        method: 'delete',
 | 
				
			||||||
 | 
					        url: '/user',
 | 
				
			||||||
 | 
					        auth: {basic: 'janedoe'},
 | 
				
			||||||
 | 
					        httpStatus: 200
 | 
				
			||||||
 | 
					      }).end((err, res) => {
 | 
				
			||||||
 | 
					        if (err) return done (err);
 | 
				
			||||||
 | 
					        should(res.body).be.eql({status: 'OK'});
 | 
				
			||||||
 | 
					        UserModel.find({name: 'janedoe'}).lean().exec( (err, data) => {
 | 
				
			||||||
 | 
					          if (err) return done(err);
 | 
				
			||||||
 | 
					          should(data).have.lengthOf(0);
 | 
				
			||||||
 | 
					          done();
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    it('deletes other user details for admin', done => {
 | 
				
			||||||
 | 
					      TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					        method: 'delete',
 | 
				
			||||||
 | 
					        url: '/user/janedoe',
 | 
				
			||||||
 | 
					        auth: {basic: 'admin'},
 | 
				
			||||||
 | 
					        httpStatus: 200
 | 
				
			||||||
 | 
					      }).end((err, res) => {
 | 
				
			||||||
 | 
					        if (err) return done (err);
 | 
				
			||||||
 | 
					        should(res.body).be.eql({status: 'OK'});
 | 
				
			||||||
 | 
					        UserModel.find({name: 'janedoe'}).lean().exec( (err, data) => {
 | 
				
			||||||
 | 
					          if (err) return done(err);
 | 
				
			||||||
 | 
					          should(data).have.lengthOf(0);
 | 
				
			||||||
 | 
					          done();
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    it('rejects requests from non-admins for another user', done => {
 | 
				
			||||||
 | 
					      TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					        method: 'delete',
 | 
				
			||||||
 | 
					        url: '/user/admin',
 | 
				
			||||||
 | 
					        auth: {basic: 'janedoe'},
 | 
				
			||||||
 | 
					        httpStatus: 403
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    it('rejects requests from a user API key', done => {
 | 
				
			||||||
 | 
					      TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					        method: 'delete',
 | 
				
			||||||
 | 
					        url: '/user',
 | 
				
			||||||
 | 
					        auth: {key: 'janedoe'},
 | 
				
			||||||
 | 
					        httpStatus: 401
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    it('rejects requests from an admin API key', done => {
 | 
				
			||||||
 | 
					      TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					        method: 'delete',
 | 
				
			||||||
 | 
					        url: '/user/janedoe',
 | 
				
			||||||
 | 
					        auth: {key: 'admin'},
 | 
				
			||||||
 | 
					        httpStatus: 401
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    it('returns 404 for an unknown user', done => {
 | 
				
			||||||
 | 
					      TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					        method: 'delete',
 | 
				
			||||||
 | 
					        url: '/user/unknown',
 | 
				
			||||||
 | 
					        auth: {basic: 'admin'},
 | 
				
			||||||
 | 
					        httpStatus: 404
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    it('rejects unauthorized requests', done => {
 | 
				
			||||||
 | 
					      TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					        method: 'delete',
 | 
				
			||||||
 | 
					        url: '/user/janedoe',
 | 
				
			||||||
 | 
					        httpStatus: 401
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  describe('GET /user/key', () => {
 | 
				
			||||||
 | 
					    it('returns the right API key', done => {
 | 
				
			||||||
 | 
					      TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					        method: 'get',
 | 
				
			||||||
 | 
					        url: '/user/key',
 | 
				
			||||||
 | 
					        auth: {basic: 'janedoe'},
 | 
				
			||||||
 | 
					        httpStatus: 200,
 | 
				
			||||||
 | 
					        res: {key: TestHelper.auth.janedoe.key}
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    it('rejects requests from an API key', done => {
 | 
				
			||||||
 | 
					      TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					        method: 'get',
 | 
				
			||||||
 | 
					        url: '/user/key',
 | 
				
			||||||
 | 
					        auth: {key: 'janedoe'},
 | 
				
			||||||
 | 
					        httpStatus: 401
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    it('rejects requests from an API key', done => {
 | 
				
			||||||
 | 
					      TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					        method: 'get',
 | 
				
			||||||
 | 
					        url: '/user/key',
 | 
				
			||||||
 | 
					        httpStatus: 401
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  describe('POST /user/new', () => {
 | 
				
			||||||
 | 
					    it('returns the added user data', done => {
 | 
				
			||||||
 | 
					      TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					        method: 'post',
 | 
				
			||||||
 | 
					        url: '/user/new',
 | 
				
			||||||
 | 
					        auth: {basic: 'admin'},
 | 
				
			||||||
 | 
					        httpStatus: 200,
 | 
				
			||||||
 | 
					        req: {email: 'john.doe@bosch.com', name: 'johndoe', pass: 'Abc123!#', level: 'read', location: 'Rng', device_name: 'Alpha II'}
 | 
				
			||||||
 | 
					      }).end((err, res) => {
 | 
				
			||||||
 | 
					          if (err) return done (err);
 | 
				
			||||||
 | 
					          should(res.body).have.only.keys('_id', 'email', 'name', 'level', 'location', 'device_name');
 | 
				
			||||||
 | 
					          should(res.body).have.property('_id').be.type('string');
 | 
				
			||||||
 | 
					          should(res.body).have.property('email', 'john.doe@bosch.com');
 | 
				
			||||||
 | 
					          should(res.body).have.property('name', 'johndoe');
 | 
				
			||||||
 | 
					          should(res.body).have.property('level', 'read');
 | 
				
			||||||
 | 
					          should(res.body).have.property('location', 'Rng');
 | 
				
			||||||
 | 
					          should(res.body).have.property('device_name', 'Alpha II');
 | 
				
			||||||
 | 
					          done();
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    it('stores the data', done => {
 | 
				
			||||||
 | 
					      TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					        method: 'post',
 | 
				
			||||||
 | 
					        url: '/user/new',
 | 
				
			||||||
 | 
					        auth: {basic: 'admin'},
 | 
				
			||||||
 | 
					        httpStatus: 200,
 | 
				
			||||||
 | 
					        req: {email: 'john.doe@bosch.com', name: 'johndoe', pass: 'Abc123!#', level: 'read', location: 'Rng', device_name: 'Alpha II'}
 | 
				
			||||||
 | 
					      }).end(err => {
 | 
				
			||||||
 | 
					          if (err) return done (err);
 | 
				
			||||||
 | 
					          UserModel.find({name: 'johndoe'}).lean().exec( (err, data) => {
 | 
				
			||||||
 | 
					            if (err) return done(err);
 | 
				
			||||||
 | 
					            should(data).have.lengthOf(1);
 | 
				
			||||||
 | 
					            should(data[0]).have.only.keys('_id', 'name', 'pass', 'email', 'level', 'location', 'device_name', 'key', '__v');
 | 
				
			||||||
 | 
					            should(data[0]).have.property('_id');
 | 
				
			||||||
 | 
					            should(data[0]).have.property('name', 'johndoe');
 | 
				
			||||||
 | 
					            should(data[0]).have.property('email', 'john.doe@bosch.com');
 | 
				
			||||||
 | 
					            should(data[0]).have.property('pass').not.eql('Abc123!#');
 | 
				
			||||||
 | 
					            should(data[0]).have.property('level', 'read');
 | 
				
			||||||
 | 
					            should(data[0]).have.property('location', 'Rng');
 | 
				
			||||||
 | 
					            should(data[0]).have.property('device_name', 'Alpha II');
 | 
				
			||||||
 | 
					            done();
 | 
				
			||||||
 | 
					          });
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    it('rejects a username already in use', done => {
 | 
				
			||||||
 | 
					      TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					        method: 'post',
 | 
				
			||||||
 | 
					        url: '/user/new',
 | 
				
			||||||
 | 
					        auth: {basic: 'admin'},
 | 
				
			||||||
 | 
					        httpStatus: 400, default: false,
 | 
				
			||||||
 | 
					        req: {email: 'j.doe@bosch.com', name: 'janedoe', pass: 'Abc123!#', level: 'read', location: 'Rng', device_name: 'Alpha II'}
 | 
				
			||||||
 | 
					      }).end((err, res) => {
 | 
				
			||||||
 | 
					          if (err) return done (err);
 | 
				
			||||||
 | 
					          should(res.body).be.eql({status: 'Username already taken'});
 | 
				
			||||||
 | 
					          UserModel.find({name: 'janedoe'}).lean().exec( (err, data) => {
 | 
				
			||||||
 | 
					            if (err) return done(err);
 | 
				
			||||||
 | 
					            should(data).have.lengthOf(1);
 | 
				
			||||||
 | 
					            done();
 | 
				
			||||||
 | 
					          });
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    it('rejects a username which is in the special names', done => {
 | 
				
			||||||
 | 
					      TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					        method: 'post',
 | 
				
			||||||
 | 
					        url: '/user/new',
 | 
				
			||||||
 | 
					        auth: {basic: 'admin'},
 | 
				
			||||||
 | 
					        httpStatus: 400, default: false,
 | 
				
			||||||
 | 
					        req: {email: 'j.doe@bosch.com', name: 'passreset', pass: 'Abc123!#', level: 'read', location: 'Rng', device_name: 'Alpha II'},
 | 
				
			||||||
 | 
					        res: {status: 'Username already taken'}
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    it('rejects invalid user details', done => {
 | 
				
			||||||
 | 
					      TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					        method: 'post',
 | 
				
			||||||
 | 
					        url: '/user/new',
 | 
				
			||||||
 | 
					        auth: {basic: 'admin'},
 | 
				
			||||||
 | 
					        httpStatus: 400,
 | 
				
			||||||
 | 
					        req: {email: 'john.doe@bosch.com', name: 'johndoe', pass: 'Abc123!#', level: 'read', location: 44, device_name: 'Alpha II'},
 | 
				
			||||||
 | 
					        res: {status: 'Invalid body format'}
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    it('rejects an invalid user level', done => {
 | 
				
			||||||
 | 
					      TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					        method: 'post',
 | 
				
			||||||
 | 
					        url: '/user/new',
 | 
				
			||||||
 | 
					        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'}
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    it('rejects an invalid email address', done => {
 | 
				
			||||||
 | 
					      TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					        method: 'post',
 | 
				
			||||||
 | 
					        url: '/user/new',
 | 
				
			||||||
 | 
					        auth: {basic: 'admin'},
 | 
				
			||||||
 | 
					        httpStatus: 400,
 | 
				
			||||||
 | 
					        req: {email: 'john.doe', name: 'johndoe', pass: 'Abc123!#', level: 'read', location: 'Rng', device_name: 'Alpha II'},
 | 
				
			||||||
 | 
					        res: {status: 'Invalid body format'}
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    it('rejects an invalid password', done => {
 | 
				
			||||||
 | 
					      TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					        method: 'post',
 | 
				
			||||||
 | 
					        url: '/user/new',
 | 
				
			||||||
 | 
					        auth: {basic: 'admin'},
 | 
				
			||||||
 | 
					        httpStatus: 400,
 | 
				
			||||||
 | 
					        req: {email: 'john.doe@bosch.com', name: 'johndoe', pass: 'password', level: 'read', location: 'Rng', device_name: 'Alpha II'},
 | 
				
			||||||
 | 
					        res: {status: 'Invalid body format'}
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    it('rejects requests from non-admins', done => {
 | 
				
			||||||
 | 
					      TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					        method: 'post',
 | 
				
			||||||
 | 
					        url: '/user/new',
 | 
				
			||||||
 | 
					        auth: {basic: 'janedoe'},
 | 
				
			||||||
 | 
					        httpStatus: 403,
 | 
				
			||||||
 | 
					        req: {email: 'john.doe@bosch.com', name: 'johndoe', pass: 'Abc123!#', level: 'read', location: 'Rng', device_name: 'Alpha II'}
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    it('rejects requests from an admin API key', done => {
 | 
				
			||||||
 | 
					      TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					        method: 'post',
 | 
				
			||||||
 | 
					        url: '/user/new',
 | 
				
			||||||
 | 
					        auth: {key: 'admin'},
 | 
				
			||||||
 | 
					        httpStatus: 401,
 | 
				
			||||||
 | 
					        req: {email: 'john.doe@bosch.com', name: 'johndoe', pass: 'Abc123!#', level: 'read', location: 'Rng', device_name: 'Alpha II'}
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    it('rejects unauthorized requests', done => {
 | 
				
			||||||
 | 
					      TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					        method: 'post',
 | 
				
			||||||
 | 
					        url: '/user/new',
 | 
				
			||||||
 | 
					        httpStatus: 401,
 | 
				
			||||||
 | 
					        req: {email: 'john.doe@bosch.com', name: 'johndoe', pass: 'Abc123!#', level: 'read', location: 'Rng', device_name: 'Alpha II'}
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  describe('POST /user/passreset', () => {
 | 
				
			||||||
 | 
					    it('returns the ok response', done => {
 | 
				
			||||||
 | 
					      TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					        method: 'post',
 | 
				
			||||||
 | 
					        url: '/user/passreset',
 | 
				
			||||||
 | 
					        httpStatus: 200,
 | 
				
			||||||
 | 
					        req: {email: 'jane.doe@bosch.com', name: 'janedoe'},
 | 
				
			||||||
 | 
					        res: {status: 'OK'}
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    it('returns 404 for wrong username/email combo', done => {
 | 
				
			||||||
 | 
					      TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					        method: 'post',
 | 
				
			||||||
 | 
					        url: '/user/passreset',
 | 
				
			||||||
 | 
					        httpStatus: 404,
 | 
				
			||||||
 | 
					        req: {email: 'jane.doe@bosch.com', name: 'admin'}
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    it('returns 404 for unknown username', done => {
 | 
				
			||||||
 | 
					      TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					        method: 'post',
 | 
				
			||||||
 | 
					        url: '/user/passreset',
 | 
				
			||||||
 | 
					        httpStatus: 404,
 | 
				
			||||||
 | 
					        req: {email: 'jane.doe@bosch.com', name: 'username'}
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    it('changes the user password', done => {
 | 
				
			||||||
 | 
					      UserModel.find({name: 'janedoe'}).lean().exec( (err, data: any) => {
 | 
				
			||||||
 | 
					        if (err) return done(err);
 | 
				
			||||||
 | 
					        const oldpass = data[0].pass;
 | 
				
			||||||
 | 
					        TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					          method: 'post',
 | 
				
			||||||
 | 
					          url: '/user/passreset',
 | 
				
			||||||
 | 
					          httpStatus: 200,
 | 
				
			||||||
 | 
					          req: {email: 'jane.doe@bosch.com', name: 'janedoe'}
 | 
				
			||||||
 | 
					        }).end((err, res) => {
 | 
				
			||||||
 | 
					            if (err) return done(err);
 | 
				
			||||||
 | 
					            should(res.body).be.eql({status: 'OK'});
 | 
				
			||||||
 | 
					            UserModel.find({name: 'janedoe'}).lean().exec(  (err, data: any) => {
 | 
				
			||||||
 | 
					              if (err) return done(err);
 | 
				
			||||||
 | 
					              should(data[0].pass).not.eql(oldpass);
 | 
				
			||||||
 | 
					              done();
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					          });
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
							
								
								
									
										173
									
								
								src/routes/user.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										173
									
								
								src/routes/user.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,173 @@
 | 
				
			|||||||
 | 
					import express from 'express';
 | 
				
			||||||
 | 
					import mongoose from 'mongoose';
 | 
				
			||||||
 | 
					import bcrypt from 'bcryptjs';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import UserValidate from './validate/user';
 | 
				
			||||||
 | 
					import UserModel from '../models/user';
 | 
				
			||||||
 | 
					import mail from '../helpers/mail';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const router = express.Router();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					router.get('/users', (req, res) => {
 | 
				
			||||||
 | 
					  if (!req.auth(res, ['admin'], 'basic')) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  UserModel.find({}).lean().exec(  (err, data:any) => {
 | 
				
			||||||
 | 
					    res.json(data.map(e => UserValidate.output(e)).filter(e => e !== null));  // validate all and filter null values from validation errors
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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
 | 
				
			||||||
 | 
					  req.params.username = req.params[0];
 | 
				
			||||||
 | 
					  if (!req.auth(res, ['read', 'write', 'maintain', 'dev', 'admin'], 'basic')) return;
 | 
				
			||||||
 | 
					  let username = req.authDetails.username;
 | 
				
			||||||
 | 
					  if (req.params.username !== undefined) {
 | 
				
			||||||
 | 
					    if (!req.auth(res, ['admin'], 'basic')) return;
 | 
				
			||||||
 | 
					    username = req.params.username;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  UserModel.findOne({name: username}).lean().exec(  (err, data:any) => {
 | 
				
			||||||
 | 
					    if (err) return next(err);
 | 
				
			||||||
 | 
					    if (data) {
 | 
				
			||||||
 | 
					      res.json(UserValidate.output(data));  // validate all and filter null values from validation errors
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else {
 | 
				
			||||||
 | 
					      res.status(404).json({status: 'Not found'});
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					router.put('/user:username([/](?!key|new).?*|/?)', (req, res, next) => {  // this path matches /user, /user/ and /user/xxx, but not /user/key or user/new
 | 
				
			||||||
 | 
					  req.params.username = req.params[0];
 | 
				
			||||||
 | 
					  if (!req.auth(res, ['read', 'write', 'maintain', 'dev', 'admin'], 'basic')) return;
 | 
				
			||||||
 | 
					  let username = req.authDetails.username;
 | 
				
			||||||
 | 
					  if (req.params.username !== undefined) {
 | 
				
			||||||
 | 
					    if (!req.auth(res, ['admin'], 'basic')) return;
 | 
				
			||||||
 | 
					    username = req.params.username;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  const {error, value: user} = UserValidate.input(req.body, 'change' + (req.authDetails.level === 'admin'? 'admin' : ''));
 | 
				
			||||||
 | 
					  if (error) {
 | 
				
			||||||
 | 
					    res.status(400).json({status: 'Invalid body format'});
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (user.hasOwnProperty('pass')) {
 | 
				
			||||||
 | 
					    user.pass = bcrypt.hashSync(user.pass, 10);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // check that user does not already exist if new name was specified
 | 
				
			||||||
 | 
					  if (user.hasOwnProperty('name') && user.name !== username) {
 | 
				
			||||||
 | 
					    UserModel.find({name: user.name}).lean().exec(  (err, data:any) => {
 | 
				
			||||||
 | 
					      if (err) return next(err);
 | 
				
			||||||
 | 
					      if (data.length > 0 || UserValidate.isSpecialName(user.name)) {
 | 
				
			||||||
 | 
					        res.status(400).json({status: 'Username already taken'});
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      UserModel.findOneAndUpdate({name: username}, user, {new: true}).lean().exec(  (err, data:any) => {
 | 
				
			||||||
 | 
					        if (err) return next(err);
 | 
				
			||||||
 | 
					        if (data) {
 | 
				
			||||||
 | 
					          res.json(UserValidate.output(data));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else {
 | 
				
			||||||
 | 
					          res.status(404).json({status: 'Not found'});
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  else {
 | 
				
			||||||
 | 
					    UserModel.findOneAndUpdate({name: username}, user, {new: true}).lean().exec(  (err, data:any) => {
 | 
				
			||||||
 | 
					      if (err) return next(err);
 | 
				
			||||||
 | 
					      if (data) {
 | 
				
			||||||
 | 
					        res.json(UserValidate.output(data));  // validate all and filter null values from validation errors
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      else {
 | 
				
			||||||
 | 
					        res.status(404).json({status: 'Not found'});
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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
 | 
				
			||||||
 | 
					  req.params.username = req.params[0];
 | 
				
			||||||
 | 
					  if (!req.auth(res, ['read', 'write', 'maintain', 'dev', 'admin'], 'basic')) return;
 | 
				
			||||||
 | 
					  let username = req.authDetails.username;
 | 
				
			||||||
 | 
					  if (req.params.username !== undefined) {
 | 
				
			||||||
 | 
					    if (!req.auth(res, ['admin'], 'basic')) return;
 | 
				
			||||||
 | 
					    username = req.params.username;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  UserModel.findOneAndDelete({name: username}).lean().exec(  (err, data:any) => {
 | 
				
			||||||
 | 
					    if (err) return next(err);
 | 
				
			||||||
 | 
					    if (data) {
 | 
				
			||||||
 | 
					      res.json({status: 'OK'})
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else {
 | 
				
			||||||
 | 
					      res.status(404).json({status: 'Not found'});
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					router.get('/user/key', (req, res, next) => {
 | 
				
			||||||
 | 
					  if (!req.auth(res, ['read', 'write', 'maintain', 'dev', 'admin'], 'basic')) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  UserModel.findOne({name: req.authDetails.username}).lean().exec(  (err, data:any) => {
 | 
				
			||||||
 | 
					    if (err) return next(err);
 | 
				
			||||||
 | 
					    res.json({key: data.key});
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					router.post('/user/new', (req, res, next) => {
 | 
				
			||||||
 | 
					  if (!req.auth(res, ['admin'], 'basic')) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // validate input
 | 
				
			||||||
 | 
					  const {error, value: user} = UserValidate.input(req.body, 'new');
 | 
				
			||||||
 | 
					  if (error) {
 | 
				
			||||||
 | 
					    res.status(400).json({status: 'Invalid body format'});
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // check that user does not already exist
 | 
				
			||||||
 | 
					  UserModel.find({name: user.name}).lean().exec(  (err, data:any) => {
 | 
				
			||||||
 | 
					    if (err) return next(err);
 | 
				
			||||||
 | 
					    if (data.length > 0  || UserValidate.isSpecialName(user.name)) {
 | 
				
			||||||
 | 
					      res.status(400).json({status: 'Username already taken'});
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    user.key = mongoose.Types.ObjectId();  // use object id as unique API key
 | 
				
			||||||
 | 
					    bcrypt.hash(user.pass, 10, (err, hash) => {  // password hashing
 | 
				
			||||||
 | 
					      user.pass = hash;
 | 
				
			||||||
 | 
					      new UserModel(user).save((err, data) => {  // store user
 | 
				
			||||||
 | 
					        if (err) return next(err);
 | 
				
			||||||
 | 
					        res.json(UserValidate.output(data.toObject()));
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					router.post('/user/passreset', (req, res, next) => {
 | 
				
			||||||
 | 
					  // check if user/email combo exists
 | 
				
			||||||
 | 
					  UserModel.find({name: req.body.name, email: req.body.email}).lean().exec( (err, data: any) => {
 | 
				
			||||||
 | 
					    if (err) return next(err);
 | 
				
			||||||
 | 
					    if (data.length === 1) {  // it exists
 | 
				
			||||||
 | 
					      const newPass = Math.random().toString(36).substring(2);
 | 
				
			||||||
 | 
					      bcrypt.hash(newPass, 10, (err, hash) => {  // password hashing
 | 
				
			||||||
 | 
					        if (err) return next(err);
 | 
				
			||||||
 | 
					        UserModel.findByIdAndUpdate(data[0]._id, {pass: hash}, err => {  // write new password
 | 
				
			||||||
 | 
					          if (err) return next(err);
 | 
				
			||||||
 | 
					          mail(data[0].email, 'Your new password for the DFOP database', 'Hi, <br><br> You requested to reset your password.<br>Your new password is:<br><br>' + newPass + '<br><br>If you did not request a password reset, talk to the sysadmin quickly!<br><br>Have a nice day.<br><br>The DFOP team', err => {
 | 
				
			||||||
 | 
					            if (err) return next(err);
 | 
				
			||||||
 | 
					            res.json({status: 'OK'});
 | 
				
			||||||
 | 
					          });
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else {
 | 
				
			||||||
 | 
					      res.status(404).json({status: 'Not found'});
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module.exports = router;
 | 
				
			||||||
							
								
								
									
										26
									
								
								src/routes/validate/id.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								src/routes/validate/id.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,26 @@
 | 
				
			|||||||
 | 
					import joi from '@hapi/joi';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default class IdValidate {
 | 
				
			||||||
 | 
					  private static id = joi.string().pattern(new RegExp('[0-9a-f]{24}')).length(24);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  static get () {
 | 
				
			||||||
 | 
					    return this.id;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  static valid (id) {
 | 
				
			||||||
 | 
					    return this.id.validate(id).error === undefined;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  static parameter () {  // :id url parameter
 | 
				
			||||||
 | 
					    return ':id([0-9a-f]{24})';
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  static stringify (data) {
 | 
				
			||||||
 | 
					    Object.keys(data).forEach(key => {
 | 
				
			||||||
 | 
					      if (data[key] !== null && data[key].hasOwnProperty('_bsontype') && data[key]._bsontype === 'ObjectID') {
 | 
				
			||||||
 | 
					        data[key] = data[key].toString();
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    return data;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										82
									
								
								src/routes/validate/material.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										82
									
								
								src/routes/validate/material.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,82 @@
 | 
				
			|||||||
 | 
					import joi from '@hapi/joi';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import IdValidate from './id';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default class MaterialValidate {  // validate input for material
 | 
				
			||||||
 | 
					  private static material = {
 | 
				
			||||||
 | 
					    name: joi.string()
 | 
				
			||||||
 | 
					      .max(128),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    supplier: joi.string()
 | 
				
			||||||
 | 
					      .max(128),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    group: joi.string()
 | 
				
			||||||
 | 
					      .max(128),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    mineral: joi.number()
 | 
				
			||||||
 | 
					      .integer()
 | 
				
			||||||
 | 
					      .min(0)
 | 
				
			||||||
 | 
					      .max(100),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    glass_fiber: joi.number()
 | 
				
			||||||
 | 
					      .integer()
 | 
				
			||||||
 | 
					      .min(0)
 | 
				
			||||||
 | 
					      .max(100),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    carbon_fiber: joi.number()
 | 
				
			||||||
 | 
					      .integer()
 | 
				
			||||||
 | 
					      .min(0)
 | 
				
			||||||
 | 
					      .max(100),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    numbers: joi.array()
 | 
				
			||||||
 | 
					      .items(joi.object({
 | 
				
			||||||
 | 
					        color: joi.string()
 | 
				
			||||||
 | 
					          .max(128),
 | 
				
			||||||
 | 
					        number: joi.number()
 | 
				
			||||||
 | 
					          .min(0)
 | 
				
			||||||
 | 
					      }))
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  static input (data, param) {  // validate data, param: new(everything required)/change(available attributes are validated)
 | 
				
			||||||
 | 
					    if (param === 'new') {
 | 
				
			||||||
 | 
					      return joi.object({
 | 
				
			||||||
 | 
					        name: this.material.name.required(),
 | 
				
			||||||
 | 
					        supplier: this.material.supplier.required(),
 | 
				
			||||||
 | 
					        group: this.material.group.required(),
 | 
				
			||||||
 | 
					        mineral: this.material.mineral.required(),
 | 
				
			||||||
 | 
					        glass_fiber: this.material.glass_fiber.required(),
 | 
				
			||||||
 | 
					        carbon_fiber: this.material.carbon_fiber.required(),
 | 
				
			||||||
 | 
					        numbers: this.material.numbers
 | 
				
			||||||
 | 
					      }).validate(data);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else if (param === 'change') {
 | 
				
			||||||
 | 
					      return joi.object({
 | 
				
			||||||
 | 
					        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
 | 
				
			||||||
 | 
					      }).validate(data);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else {
 | 
				
			||||||
 | 
					      return{error: 'No parameter specified!', value: {}};
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  static output (data) {  // validate output from database for needed properties, strip everything else
 | 
				
			||||||
 | 
					    data = IdValidate.stringify(data);
 | 
				
			||||||
 | 
					    const {value, error} = 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
 | 
				
			||||||
 | 
					    }).validate(data, {stripUnknown: true});
 | 
				
			||||||
 | 
					    return error !== undefined? null : value;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										18
									
								
								src/routes/validate/note_field.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								src/routes/validate/note_field.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,18 @@
 | 
				
			|||||||
 | 
					import joi from '@hapi/joi';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default class NoteFieldValidate {
 | 
				
			||||||
 | 
					  private static note_field = {
 | 
				
			||||||
 | 
					    name: joi.string()
 | 
				
			||||||
 | 
					      .max(128),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    qty: joi.number()
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  static output (data) {
 | 
				
			||||||
 | 
					    const {value, error} = joi.object({
 | 
				
			||||||
 | 
					      name: this.note_field.name,
 | 
				
			||||||
 | 
					      qty: this.note_field.qty
 | 
				
			||||||
 | 
					    }).validate(data, {stripUnknown: true});
 | 
				
			||||||
 | 
					    return error !== undefined? null : value;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										77
									
								
								src/routes/validate/sample.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										77
									
								
								src/routes/validate/sample.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,77 @@
 | 
				
			|||||||
 | 
					import joi from '@hapi/joi';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import IdValidate from './id';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default class SampleValidate {
 | 
				
			||||||
 | 
					  private static sample = {
 | 
				
			||||||
 | 
					    number: joi.string()
 | 
				
			||||||
 | 
					      .max(128),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    color: joi.string()
 | 
				
			||||||
 | 
					      .max(128),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    type: joi.string()
 | 
				
			||||||
 | 
					      .max(128),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    batch: joi.string()
 | 
				
			||||||
 | 
					      .max(128)
 | 
				
			||||||
 | 
					      .allow(''),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    notes: joi.object({
 | 
				
			||||||
 | 
					      comment: joi.string()
 | 
				
			||||||
 | 
					        .max(512),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      sample_references: joi.array()
 | 
				
			||||||
 | 
					        .items(joi.object({
 | 
				
			||||||
 | 
					          id: IdValidate.get(),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          relation: joi.string()
 | 
				
			||||||
 | 
					            .max(128)
 | 
				
			||||||
 | 
					        })),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      custom_fields: joi.object()
 | 
				
			||||||
 | 
					        .pattern(/.*/, joi.alternatives()
 | 
				
			||||||
 | 
					          .try(
 | 
				
			||||||
 | 
					            joi.string().max(128),
 | 
				
			||||||
 | 
					            joi.number(),
 | 
				
			||||||
 | 
					            joi.boolean(),
 | 
				
			||||||
 | 
					            joi.date()
 | 
				
			||||||
 | 
					          )
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  static input (data, param) {  // validate data, param: new(everything required)/change(available attributes are validated)
 | 
				
			||||||
 | 
					    if (param === 'new') {
 | 
				
			||||||
 | 
					      return joi.object({
 | 
				
			||||||
 | 
					        number: this.sample.number.required(),
 | 
				
			||||||
 | 
					        color: this.sample.color.required(),
 | 
				
			||||||
 | 
					        type: this.sample.type.required(),
 | 
				
			||||||
 | 
					        batch: this.sample.batch.required(),
 | 
				
			||||||
 | 
					        material_id: IdValidate.get().required(),
 | 
				
			||||||
 | 
					        notes: this.sample.notes.required()
 | 
				
			||||||
 | 
					      }).validate(data);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else if (param === 'change') {
 | 
				
			||||||
 | 
					      return{error: 'Not implemented!', value: {}};
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else {
 | 
				
			||||||
 | 
					      return{error: 'No parameter specified!', value: {}};
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  static output (data) {
 | 
				
			||||||
 | 
					    data = IdValidate.stringify(data);
 | 
				
			||||||
 | 
					    const {value, error} = joi.object({
 | 
				
			||||||
 | 
					      _id: IdValidate.get(),
 | 
				
			||||||
 | 
					      number: this.sample.number,
 | 
				
			||||||
 | 
					      color: this.sample.color,
 | 
				
			||||||
 | 
					      type: this.sample.type,
 | 
				
			||||||
 | 
					      batch: this.sample.batch,
 | 
				
			||||||
 | 
					      material_id: IdValidate.get(),
 | 
				
			||||||
 | 
					      note_id: IdValidate.get().allow(null),
 | 
				
			||||||
 | 
					      user_id: IdValidate.get()
 | 
				
			||||||
 | 
					    }).validate(data, {stripUnknown: true});
 | 
				
			||||||
 | 
					    return error !== undefined? null : value;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										59
									
								
								src/routes/validate/template.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								src/routes/validate/template.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,59 @@
 | 
				
			|||||||
 | 
					import joi from '@hapi/joi';
 | 
				
			||||||
 | 
					import IdValidate from './id';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default class TemplateValidate {
 | 
				
			||||||
 | 
					  private static template = {
 | 
				
			||||||
 | 
					    name: joi.string()
 | 
				
			||||||
 | 
					      .max(128),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    parameters: joi.array()
 | 
				
			||||||
 | 
					      .min(1)
 | 
				
			||||||
 | 
					      .items(
 | 
				
			||||||
 | 
					        joi.object({
 | 
				
			||||||
 | 
					          name: joi.string()
 | 
				
			||||||
 | 
					            .max(128)
 | 
				
			||||||
 | 
					            .required(),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          range: joi.object({
 | 
				
			||||||
 | 
					            values: joi.array()
 | 
				
			||||||
 | 
					              .min(1),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            min: joi.number(),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            max: joi.number()
 | 
				
			||||||
 | 
					          })
 | 
				
			||||||
 | 
					            .oxor('values', 'min')
 | 
				
			||||||
 | 
					            .oxor('values', 'max')
 | 
				
			||||||
 | 
					            .required()
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					      )
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  static input (data, param) {  // validate data, param: new(everything required)/change(available attributes are validated)
 | 
				
			||||||
 | 
					    if (param === 'new') {
 | 
				
			||||||
 | 
					      return joi.object({
 | 
				
			||||||
 | 
					        name: this.template.name.required(),
 | 
				
			||||||
 | 
					        parameters: this.template.parameters.required()
 | 
				
			||||||
 | 
					      }).validate(data);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else if (param === 'change') {
 | 
				
			||||||
 | 
					      return joi.object({
 | 
				
			||||||
 | 
					        name: this.template.name,
 | 
				
			||||||
 | 
					        parameters: this.template.parameters
 | 
				
			||||||
 | 
					      }).validate(data);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else {
 | 
				
			||||||
 | 
					      return{error: 'No parameter specified!', value: {}};
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  static output (data) {  // validate output from database for needed properties, strip everything else
 | 
				
			||||||
 | 
					    data = IdValidate.stringify(data);
 | 
				
			||||||
 | 
					    const {value, error} = joi.object({
 | 
				
			||||||
 | 
					      _id: IdValidate.get(),
 | 
				
			||||||
 | 
					      name: this.template.name,
 | 
				
			||||||
 | 
					      parameters: this.template.parameters
 | 
				
			||||||
 | 
					    }).validate(data, {stripUnknown: true});
 | 
				
			||||||
 | 
					    return error !== undefined? null : value;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										87
									
								
								src/routes/validate/user.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										87
									
								
								src/routes/validate/user.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,87 @@
 | 
				
			|||||||
 | 
					import joi from '@hapi/joi';
 | 
				
			||||||
 | 
					import globals from '../../globals';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import IdValidate from './id';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default class UserValidate {  // validate input for user
 | 
				
			||||||
 | 
					  private static user = {
 | 
				
			||||||
 | 
					    name: joi.string()
 | 
				
			||||||
 | 
					      .alphanum()
 | 
				
			||||||
 | 
					      .lowercase()
 | 
				
			||||||
 | 
					      .max(128),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    email: joi.string()
 | 
				
			||||||
 | 
					      .email({minDomainSegments: 2})
 | 
				
			||||||
 | 
					      .lowercase()
 | 
				
			||||||
 | 
					      .max(128),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pass: joi.string()
 | 
				
			||||||
 | 
					      .pattern(new RegExp('^(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[!"#%&\'()*+,-.\\/:;<=>?@[\\]^_`{|}~])(?=\\S+$).{8,}$'))
 | 
				
			||||||
 | 
					      .max(128),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    level: joi.string()
 | 
				
			||||||
 | 
					      .valid(...globals.levels),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    location: joi.string()
 | 
				
			||||||
 | 
					      .alphanum()
 | 
				
			||||||
 | 
					      .max(128),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    device_name: joi.string()
 | 
				
			||||||
 | 
					      .allow('')
 | 
				
			||||||
 | 
					      .max(128),
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  private static specialUsernames = ['admin', 'user', 'key', 'new', 'passreset'];  // names a user cannot take
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  static input (data, param) {
 | 
				
			||||||
 | 
					    if (param === 'new') {
 | 
				
			||||||
 | 
					      return joi.object({
 | 
				
			||||||
 | 
					        name: this.user.name.required(),
 | 
				
			||||||
 | 
					        email: this.user.email.required(),
 | 
				
			||||||
 | 
					        pass: this.user.pass.required(),
 | 
				
			||||||
 | 
					        level: this.user.level.required(),
 | 
				
			||||||
 | 
					        location: this.user.location.required(),
 | 
				
			||||||
 | 
					        device_name: this.user.device_name.required()
 | 
				
			||||||
 | 
					      }).validate(data);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else if (param === 'change') {
 | 
				
			||||||
 | 
					      return joi.object({
 | 
				
			||||||
 | 
					        name: this.user.name,
 | 
				
			||||||
 | 
					        email: this.user.email,
 | 
				
			||||||
 | 
					        pass: this.user.pass,
 | 
				
			||||||
 | 
					        location: this.user.location,
 | 
				
			||||||
 | 
					        device_name: this.user.device_name
 | 
				
			||||||
 | 
					      }).validate(data);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else if (param === 'changeadmin') {
 | 
				
			||||||
 | 
					      return joi.object({
 | 
				
			||||||
 | 
					        name: this.user.name,
 | 
				
			||||||
 | 
					        email: this.user.email,
 | 
				
			||||||
 | 
					        pass: this.user.pass,
 | 
				
			||||||
 | 
					        level: this.user.level,
 | 
				
			||||||
 | 
					        location: this.user.location,
 | 
				
			||||||
 | 
					        device_name: this.user.device_name
 | 
				
			||||||
 | 
					      }).validate(data);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else {
 | 
				
			||||||
 | 
					      return{error: 'No parameter specified!', value: {}};
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  static output (data) {  // validate output from database for needed properties, strip everything else
 | 
				
			||||||
 | 
					    data = IdValidate.stringify(data);
 | 
				
			||||||
 | 
					    const {value, error} = joi.object({
 | 
				
			||||||
 | 
					      _id: IdValidate.get(),
 | 
				
			||||||
 | 
					      name: this.user.name,
 | 
				
			||||||
 | 
					      email: this.user.email,
 | 
				
			||||||
 | 
					      level: this.user.level,
 | 
				
			||||||
 | 
					      location: this.user.location,
 | 
				
			||||||
 | 
					      device_name: this.user.device_name
 | 
				
			||||||
 | 
					    }).validate(data, {stripUnknown: true});
 | 
				
			||||||
 | 
					    return error !== undefined? null : value;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  static isSpecialName (name) {  // true if name belongs to special names
 | 
				
			||||||
 | 
					    return this.specialUsernames.indexOf(name) > -1;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										281
									
								
								src/test/db.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										281
									
								
								src/test/db.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,281 @@
 | 
				
			|||||||
 | 
					{
 | 
				
			||||||
 | 
					  "collections": {
 | 
				
			||||||
 | 
					    "samples": [
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        "_id": {"$oid":"400000000000000000000001"},
 | 
				
			||||||
 | 
					        "number": "1",
 | 
				
			||||||
 | 
					        "type": "granulate",
 | 
				
			||||||
 | 
					        "color": "black",
 | 
				
			||||||
 | 
					        "batch": "",
 | 
				
			||||||
 | 
					        "validated": true,
 | 
				
			||||||
 | 
					        "material_id": {"$oid":"100000000000000000000004"},
 | 
				
			||||||
 | 
					        "note_id": null,
 | 
				
			||||||
 | 
					        "user_id": {"$oid":"000000000000000000000002"},
 | 
				
			||||||
 | 
					        "__v": 0
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        "_id": {"$oid":"400000000000000000000002"},
 | 
				
			||||||
 | 
					        "number": "21",
 | 
				
			||||||
 | 
					        "type": "granulate",
 | 
				
			||||||
 | 
					        "color": "natural",
 | 
				
			||||||
 | 
					        "batch": "1560237365",
 | 
				
			||||||
 | 
					        "validated": true,
 | 
				
			||||||
 | 
					        "material_id": {"$oid":"100000000000000000000001"},
 | 
				
			||||||
 | 
					        "note_id": {"$oid":"500000000000000000000001"},
 | 
				
			||||||
 | 
					        "user_id": {"$oid":"000000000000000000000002"},
 | 
				
			||||||
 | 
					        "__v": 0
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        "_id": {"$oid":"400000000000000000000003"},
 | 
				
			||||||
 | 
					        "number": "33",
 | 
				
			||||||
 | 
					        "type": "part",
 | 
				
			||||||
 | 
					        "color": "black",
 | 
				
			||||||
 | 
					        "batch": "1704-005",
 | 
				
			||||||
 | 
					        "validated": false,
 | 
				
			||||||
 | 
					        "material_id": {"$oid":"100000000000000000000005"},
 | 
				
			||||||
 | 
					        "note_id": {"$oid":"500000000000000000000002"},
 | 
				
			||||||
 | 
					        "user_id": {"$oid":"000000000000000000000003"},
 | 
				
			||||||
 | 
					        "__v": 0
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        "_id": {"$oid":"400000000000000000000004"},
 | 
				
			||||||
 | 
					        "number": "32",
 | 
				
			||||||
 | 
					        "type": "granulate",
 | 
				
			||||||
 | 
					        "color": "black",
 | 
				
			||||||
 | 
					        "batch": "1653000308",
 | 
				
			||||||
 | 
					        "validated": false,
 | 
				
			||||||
 | 
					        "material_id": {"$oid":"100000000000000000000005"},
 | 
				
			||||||
 | 
					        "note_id": {"$oid":"500000000000000000000003"},
 | 
				
			||||||
 | 
					        "user_id": {"$oid":"000000000000000000000003"},
 | 
				
			||||||
 | 
					        "__v": 0
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					    "notes": [
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        "_id": {"$oid":"500000000000000000000001"},
 | 
				
			||||||
 | 
					        "comment": "Stoff gesperrt",
 | 
				
			||||||
 | 
					        "sample_references": [],
 | 
				
			||||||
 | 
					        "__v": 0
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        "_id": {"$oid":"500000000000000000000002"},
 | 
				
			||||||
 | 
					        "comment": "",
 | 
				
			||||||
 | 
					        "sample_references": [{
 | 
				
			||||||
 | 
					          "id": "400000000000000000000004",
 | 
				
			||||||
 | 
					          "relation": "granulate to sample"
 | 
				
			||||||
 | 
					        }],
 | 
				
			||||||
 | 
					        "custom_fields": {
 | 
				
			||||||
 | 
					          "not allowed for new applications": true
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "__v": 0
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        "_id": {"$oid":"500000000000000000000003"},
 | 
				
			||||||
 | 
					        "comment": "",
 | 
				
			||||||
 | 
					        "sample_references": [{
 | 
				
			||||||
 | 
					          "id": "400000000000000000000003",
 | 
				
			||||||
 | 
					          "relation": "part to sample"
 | 
				
			||||||
 | 
					        }],
 | 
				
			||||||
 | 
					        "custom_fields": {
 | 
				
			||||||
 | 
					          "not allowed for new applications": true
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "__v": 0
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					    "note_fields": [
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        "_id": {"$oid":"600000000000000000000001"},
 | 
				
			||||||
 | 
					        "name": "not allowed for new applications",
 | 
				
			||||||
 | 
					        "qty": 2,
 | 
				
			||||||
 | 
					        "__v": 0
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					    "materials": [
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        "_id": {"$oid":"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
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        ],
 | 
				
			||||||
 | 
					        "__v": 0
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        "_id": {"$oid":"100000000000000000000002"},
 | 
				
			||||||
 | 
					        "name": "Ultramid T KR 4355 G7",
 | 
				
			||||||
 | 
					        "supplier": "BASF",
 | 
				
			||||||
 | 
					        "group": "PA6/6T",
 | 
				
			||||||
 | 
					        "mineral": 0,
 | 
				
			||||||
 | 
					        "glass_fiber": 35,
 | 
				
			||||||
 | 
					        "carbon_fiber": 0,
 | 
				
			||||||
 | 
					        "numbers": [
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            "color": "black",
 | 
				
			||||||
 | 
					            "number": 5514212901
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            "color": "signalviolet",
 | 
				
			||||||
 | 
					            "number": 5514612901
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        ],
 | 
				
			||||||
 | 
					        "__v": 0
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        "_id": {"$oid":"100000000000000000000003"},
 | 
				
			||||||
 | 
					        "name": "PA GF 50 black (2706)",
 | 
				
			||||||
 | 
					        "supplier": "Akro-Plastic",
 | 
				
			||||||
 | 
					        "group": "PA66+PA6I/6T",
 | 
				
			||||||
 | 
					        "mineral": 0,
 | 
				
			||||||
 | 
					        "glass_fiber": 0,
 | 
				
			||||||
 | 
					        "carbon_fiber": 0,
 | 
				
			||||||
 | 
					        "numbers": [
 | 
				
			||||||
 | 
					        ],
 | 
				
			||||||
 | 
					        "__v": 0
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        "_id": {"$oid":"100000000000000000000004"},
 | 
				
			||||||
 | 
					        "name": "Schulamid 66 GF 25 H",
 | 
				
			||||||
 | 
					        "supplier": "Schulmann",
 | 
				
			||||||
 | 
					        "group": "PA66",
 | 
				
			||||||
 | 
					        "mineral": 0,
 | 
				
			||||||
 | 
					        "glass_fiber": 25,
 | 
				
			||||||
 | 
					        "carbon_fiber": 0,
 | 
				
			||||||
 | 
					        "numbers": [
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            "color": "black",
 | 
				
			||||||
 | 
					            "number": 5513933405
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        ],
 | 
				
			||||||
 | 
					        "__v": 0
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        "_id": {"$oid":"100000000000000000000005"},
 | 
				
			||||||
 | 
					        "name": "Amodel A 1133 HS",
 | 
				
			||||||
 | 
					        "supplier": "Solvay",
 | 
				
			||||||
 | 
					        "group": "PPA",
 | 
				
			||||||
 | 
					        "mineral": 0,
 | 
				
			||||||
 | 
					        "glass_fiber": 33,
 | 
				
			||||||
 | 
					        "carbon_fiber": 0,
 | 
				
			||||||
 | 
					        "numbers": [
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            "color": "black",
 | 
				
			||||||
 | 
					            "number": 5514262406
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        ],
 | 
				
			||||||
 | 
					        "__v": 0
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					    "treatment_templates": [
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        "_id": {"$oid":"200000000000000000000001"},
 | 
				
			||||||
 | 
					        "name": "heat treatment",
 | 
				
			||||||
 | 
					        "parameters": [
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            "name": "material",
 | 
				
			||||||
 | 
					            "range": {
 | 
				
			||||||
 | 
					              "values": [
 | 
				
			||||||
 | 
					                "copper",
 | 
				
			||||||
 | 
					                "hot air"
 | 
				
			||||||
 | 
					              ]
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            "name": "weeks",
 | 
				
			||||||
 | 
					            "range": {
 | 
				
			||||||
 | 
					              "min": 1,
 | 
				
			||||||
 | 
					              "max": 10
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        ]
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        "_id": {"$oid":"200000000000000000000002"},
 | 
				
			||||||
 | 
					        "name": "heat treatment 2",
 | 
				
			||||||
 | 
					        "parameters": [
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            "name": "material",
 | 
				
			||||||
 | 
					            "range": {}
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        ]
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					    "measurement_templates": [
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        "_id": {"$oid":"300000000000000000000001"},
 | 
				
			||||||
 | 
					        "name": "spectrum",
 | 
				
			||||||
 | 
					        "parameters": [
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            "name": "dpt",
 | 
				
			||||||
 | 
					            "range": {}
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        ]
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        "_id": {"$oid":"300000000000000000000002"},
 | 
				
			||||||
 | 
					        "name": "kf",
 | 
				
			||||||
 | 
					        "parameters": [
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            "name": "weight %",
 | 
				
			||||||
 | 
					            "range": {
 | 
				
			||||||
 | 
					              "min": 0,
 | 
				
			||||||
 | 
					              "max": 1.5
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            "name": "standard deviation",
 | 
				
			||||||
 | 
					            "range": {
 | 
				
			||||||
 | 
					              "min": 0,
 | 
				
			||||||
 | 
					              "max": 0.5
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        ]
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					    "users": [
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        "_id": {"$oid":"000000000000000000000001"},
 | 
				
			||||||
 | 
					        "email": "user@bosch.com",
 | 
				
			||||||
 | 
					        "name": "user",
 | 
				
			||||||
 | 
					        "pass": "$2a$10$di26XKF63OG0V00PL1kSK.ceCcTxDExBMOg.jkHiCnXcY7cN7DlPi",
 | 
				
			||||||
 | 
					        "level": "read",
 | 
				
			||||||
 | 
					        "location": "Rng",
 | 
				
			||||||
 | 
					        "device_name": "Alpha I",
 | 
				
			||||||
 | 
					        "key": "000000000000000000001001",
 | 
				
			||||||
 | 
					        "__v": 0
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        "_id": {"$oid":"000000000000000000000002"},
 | 
				
			||||||
 | 
					        "email": "jane.doe@bosch.com",
 | 
				
			||||||
 | 
					        "name": "janedoe",
 | 
				
			||||||
 | 
					        "pass": "$2a$10$di26XKF63OG0V00PL1kSK.ceCcTxDExBMOg.jkHiCnXcY7cN7DlPi",
 | 
				
			||||||
 | 
					        "level": "write",
 | 
				
			||||||
 | 
					        "location": "Rng",
 | 
				
			||||||
 | 
					        "device_name": "Alpha I",
 | 
				
			||||||
 | 
					        "key": "000000000000000000001002",
 | 
				
			||||||
 | 
					        "__v": 0
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        "_id": {"$oid":"000000000000000000000003"},
 | 
				
			||||||
 | 
					        "email": "a.d.m.i.n@bosch.com",
 | 
				
			||||||
 | 
					        "name": "admin",
 | 
				
			||||||
 | 
					        "pass": "$2a$10$i872o3qR5V3JnbDArD8Z.eDo.BNPDBaR7dUX9KSEtl9pUjLyucy2K",
 | 
				
			||||||
 | 
					        "level": "admin",
 | 
				
			||||||
 | 
					        "location": "Rng",
 | 
				
			||||||
 | 
					        "device_name": "",
 | 
				
			||||||
 | 
					        "key": "000000000000000000001003",
 | 
				
			||||||
 | 
					        "__v": "0"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										201
									
								
								static/img/bosch-logo.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										201
									
								
								static/img/bosch-logo.svg
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,201 @@
 | 
				
			|||||||
 | 
					<?xml version="1.0" encoding="utf-8"?>
 | 
				
			||||||
 | 
					<!-- Generator: Adobe Illustrator 23.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
 | 
				
			||||||
 | 
					    <svg version="1.1" id="bosch-lifeclip" xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" viewBox="0 0 435 155"
 | 
				
			||||||
 | 
					         style="enable-background:new 0 0 435 155;" xml:space="preserve">
 | 
				
			||||||
 | 
					<style type="text/css">
 | 
				
			||||||
 | 
						.anker{fill:#606061;}
 | 
				
			||||||
 | 
						.bosch{fill-rule:evenodd;clip-rule:evenodd;fill:#EA0016;}
 | 
				
			||||||
 | 
						.claim{fill:#000000;}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						.st0{fill-rule:evenodd;clip-rule:evenodd;fill:#FFFFFF;}
 | 
				
			||||||
 | 
						.st1{fill:url(#SVGID_1_);}
 | 
				
			||||||
 | 
						.st2{fill:#942432;}
 | 
				
			||||||
 | 
						.st3{fill:#B22739;}
 | 
				
			||||||
 | 
						.st4{fill:#931915;}
 | 
				
			||||||
 | 
						.st5{fill:#AF1A19;}
 | 
				
			||||||
 | 
						.st6{fill:#D5151A;}
 | 
				
			||||||
 | 
						.st7{fill:url(#SVGID_2_);}
 | 
				
			||||||
 | 
						.st8{fill:url(#SVGID_3_);}
 | 
				
			||||||
 | 
						.st9{fill:url(#SVGID_4_);}
 | 
				
			||||||
 | 
						.st10{fill:url(#SVGID_5_);}
 | 
				
			||||||
 | 
						.st11{fill:url(#SVGID_6_);}
 | 
				
			||||||
 | 
						.st12{fill:#253783;}
 | 
				
			||||||
 | 
						.st13{fill:url(#SVGID_7_);}
 | 
				
			||||||
 | 
						.st14{fill:url(#SVGID_8_);}
 | 
				
			||||||
 | 
						.st15{fill:url(#SVGID_9_);}
 | 
				
			||||||
 | 
						.st16{fill:url(#SVGID_10_);}
 | 
				
			||||||
 | 
						.st17{fill:url(#SVGID_11_);}
 | 
				
			||||||
 | 
						.st18{fill:url(#SVGID_12_);}
 | 
				
			||||||
 | 
						.st19{fill:#159A39;}
 | 
				
			||||||
 | 
						.st20{fill:url(#SVGID_13_);}
 | 
				
			||||||
 | 
						.st21{fill:url(#SVGID_14_);}
 | 
				
			||||||
 | 
						.st22{fill:url(#SVGID_15_);}
 | 
				
			||||||
 | 
						.st23{fill:url(#SVGID_16_);}
 | 
				
			||||||
 | 
						.st24{fill:url(#SVGID_17_);}
 | 
				
			||||||
 | 
						.st25{fill:url(#SVGID_18_);}
 | 
				
			||||||
 | 
						.st26{fill:url(#SVGID_19_);}
 | 
				
			||||||
 | 
						.st27{fill:url(#SVGID_20_);}
 | 
				
			||||||
 | 
						.st28{fill:url(#SVGID_21_);}
 | 
				
			||||||
 | 
						.st29{fill:url(#SVGID_22_);}
 | 
				
			||||||
 | 
						.st30{fill:url(#SVGID_23_);}
 | 
				
			||||||
 | 
						.st31{fill:url(#SVGID_24_);}
 | 
				
			||||||
 | 
						.st32{fill:url(#SVGID_25_);}
 | 
				
			||||||
 | 
						.st33{fill:url(#SVGID_26_);}
 | 
				
			||||||
 | 
						.st34{fill:url(#SVGID_27_);}
 | 
				
			||||||
 | 
						.st35{fill:url(#SVGID_28_);}
 | 
				
			||||||
 | 
						.st36{fill:url(#SVGID_29_);}
 | 
				
			||||||
 | 
						.st37{fill:url(#SVGID_30_);}
 | 
				
			||||||
 | 
						.st38{fill:url(#SVGID_31_);}
 | 
				
			||||||
 | 
						.st39{fill:url(#SVGID_32_);}
 | 
				
			||||||
 | 
						.st40{fill:url(#SVGID_33_);}
 | 
				
			||||||
 | 
						.st41{fill:url(#SVGID_34_);}
 | 
				
			||||||
 | 
						.st42{fill:url(#SVGID_35_);}
 | 
				
			||||||
 | 
						.st43{fill:url(#SVGID_36_);}
 | 
				
			||||||
 | 
						.st44{fill:url(#SVGID_37_);}
 | 
				
			||||||
 | 
						.st45{fill:url(#SVGID_38_);}
 | 
				
			||||||
 | 
						.st46{fill:url(#SVGID_39_);}
 | 
				
			||||||
 | 
						.st47{fill:url(#SVGID_40_);}
 | 
				
			||||||
 | 
						.st48{fill:url(#SVGID_41_);}
 | 
				
			||||||
 | 
						.st49{fill:url(#SVGID_42_);}
 | 
				
			||||||
 | 
						.st50{fill:url(#SVGID_43_);}
 | 
				
			||||||
 | 
						.st51{fill:url(#SVGID_44_);}
 | 
				
			||||||
 | 
						.st52{fill:url(#SVGID_45_);}
 | 
				
			||||||
 | 
						.st53{fill:url(#SVGID_46_);}
 | 
				
			||||||
 | 
						.st54{fill:url(#SVGID_47_);}
 | 
				
			||||||
 | 
						.st55{fill:url(#SVGID_48_);}
 | 
				
			||||||
 | 
						.st56{fill:url(#SVGID_49_);}
 | 
				
			||||||
 | 
						.st57{fill:url(#SVGID_50_);}
 | 
				
			||||||
 | 
						.st58{fill:url(#SVGID_51_);}
 | 
				
			||||||
 | 
						.st59{fill:url(#SVGID_52_);}
 | 
				
			||||||
 | 
						.st60{fill:url(#SVGID_53_);}
 | 
				
			||||||
 | 
						.st61{fill:url(#SVGID_54_);}
 | 
				
			||||||
 | 
						.st62{fill:url(#SVGID_55_);}
 | 
				
			||||||
 | 
						.st63{fill:url(#SVGID_56_);}
 | 
				
			||||||
 | 
					</style>
 | 
				
			||||||
 | 
					    <g id="box">
 | 
				
			||||||
 | 
					        <g id="claim-english">
 | 
				
			||||||
 | 
					            <path class="claim" d="M147.66699,107.6748v27.80957h-3.22852V107.6748H147.66699z"/>
 | 
				
			||||||
 | 
					            <path class="claim" d="M157.896,115.14258v3.11133c1.24463-2.29492,3.30615-3.46191,6.18408-3.46191
 | 
				
			||||||
 | 
					                c4.35645,0,6.729,2.83984,6.729,8.09082v12.60156h-3.22852v-12.83496c0-3.50098-1.32227-5.05664-4.31689-5.05664
 | 
				
			||||||
 | 
					                c-3.26758,0-5.36768,2.13965-5.36768,5.44531v12.44629h-3.22803v-20.3418H157.896z"/>
 | 
				
			||||||
 | 
					            <path class="claim" d="M178.39355,115.14258l5.44531,17.07422l5.32861-17.07422h3.34473l-6.84521,20.3418h-3.81201
 | 
				
			||||||
 | 
					                l-6.96191-20.3418H178.39355z"/>
 | 
				
			||||||
 | 
					            <path class="claim" d="M213.16455,132.25586c-1.8667,2.68359-4.47266,3.57812-7.73975,3.57812
 | 
				
			||||||
 | 
					                c-6.45654,0-10.07373-4.23926-10.07373-10.46191c0-6.2627,3.77246-10.58008,9.25684-10.58008
 | 
				
			||||||
 | 
					                c5.40625,0,8.7124,3.8125,8.7124,10.11328v1.0498H198.6958c0.07764,2.91699,0.73926,4.55078,2.13916,5.83398
 | 
				
			||||||
 | 
					                c1.05029,0.93359,2.41162,1.36133,4.51172,1.36133c2.25586,0,3.88965-0.62207,5.44531-2.7998L213.16455,132.25586z
 | 
				
			||||||
 | 
					                 M210.01416,123.34961c-0.42773-4.16211-1.9834-5.87305-5.36719-5.87305c-3.22852,0-5.09521,1.90527-5.83447,5.87305H210.01416z"
 | 
				
			||||||
 | 
					                />
 | 
				
			||||||
 | 
					            <path class="claim" d="M222.69336,115.14258v3.11133c1.24414-2.29492,3.30566-3.46191,6.18359-3.46191
 | 
				
			||||||
 | 
					                c4.35645,0,6.72852,2.83984,6.72852,8.09082v12.60156h-3.22754v-12.83496c0-3.50098-1.32227-5.05664-4.31738-5.05664
 | 
				
			||||||
 | 
					                c-3.26758,0-5.36719,2.13965-5.36719,5.44531v12.44629h-3.22852v-20.3418H222.69336z"/>
 | 
				
			||||||
 | 
					            <path class="claim" d="M243.9668,115.14258v-5.29004l3.22754-0.77734v6.06738h5.13477v2.68359h-5.13477v12.40723
 | 
				
			||||||
 | 
					                c0,1.9834,0.73926,2.91699,2.33398,2.91699c1.0498,0,1.82812-0.27148,2.76172-0.97168l1.24414,2.2168
 | 
				
			||||||
 | 
					                c-1.36133,1.0498-2.52734,1.43848-4.2002,1.43848c-3.30566,0-5.36719-1.90527-5.36719-4.97852v-13.0293h-3.1123v-2.68359H243.9668
 | 
				
			||||||
 | 
					                z"/>
 | 
				
			||||||
 | 
					            <path class="claim" d="M274.61426,132.25586c-1.86719,2.68359-4.47266,3.57812-7.74023,3.57812
 | 
				
			||||||
 | 
					                c-6.45605,0-10.07324-4.23926-10.07324-10.46191c0-6.2627,3.77246-10.58008,9.25684-10.58008
 | 
				
			||||||
 | 
					                c5.40625,0,8.71191,3.8125,8.71191,10.11328v1.0498h-14.62402c0.07812,2.91699,0.73926,4.55078,2.13965,5.83398
 | 
				
			||||||
 | 
					                c1.0498,0.93359,2.41113,1.36133,4.51172,1.36133c2.25586,0,3.88867-0.62207,5.44531-2.7998L274.61426,132.25586z
 | 
				
			||||||
 | 
					                 M271.46387,123.34961c-0.42773-4.16211-1.9834-5.87305-5.36719-5.87305c-3.22852,0-5.0957,1.90527-5.83398,5.87305H271.46387z"/>
 | 
				
			||||||
 | 
					            <path class="claim" d="M294.64453,132.2168c-1.51758,2.37305-3.8125,3.61719-6.72949,3.61719
 | 
				
			||||||
 | 
					                c-5.28906,0-8.71191-4.16113-8.71191-10.61816c0-6.30078,3.46191-10.42383,8.67383-10.42383
 | 
				
			||||||
 | 
					                c2.87793,0,5.21094,1.28418,6.76758,3.69531v-12.29102h3.22754v29.28809h-3.22754V132.2168z M282.54785,125.41113
 | 
				
			||||||
 | 
					                c0,5.13379,1.94434,7.73926,5.83398,7.73926c4.08398,0,6.37891-2.83887,6.37891-7.81738c0-4.8623-2.37207-7.85645-6.26172-7.85645
 | 
				
			||||||
 | 
					                C284.6875,117.47656,282.54785,120.35449,282.54785,125.41113z"/>
 | 
				
			||||||
 | 
					            <path class="claim" d="M318.79688,115.14258v-2.83984c0-4.16113,2.2168-6.53418,6.02832-6.53418
 | 
				
			||||||
 | 
					                c1.36133,0,2.4502,0.27246,3.65625,0.93359l-0.81738,2.48926c-1.20508-0.58301-1.75-0.73926-2.68359-0.73926
 | 
				
			||||||
 | 
					                c-1.86719,0-2.95605,1.32324-2.95605,3.50098v3.18945h4.66797v2.68359h-4.66797v17.6582h-3.22754v-17.6582h-2.91797v-2.68359
 | 
				
			||||||
 | 
					                H318.79688z"/>
 | 
				
			||||||
 | 
					            <path class="claim" d="M348.08398,125.29395c0,6.14551-4.00586,10.54004-9.64551,10.54004
 | 
				
			||||||
 | 
					                c-5.52344,0-9.56836-4.43359-9.56836-10.50098c0-6.14551,4.00586-10.54102,9.68457-10.54102
 | 
				
			||||||
 | 
					                C344.07812,114.79199,348.08398,119.22656,348.08398,125.29395z M332.21484,125.37207c0,4.78418,2.41113,7.77832,6.22363,7.77832
 | 
				
			||||||
 | 
					                c3.85059,0,6.30078-3.0332,6.30078-7.81738c0-4.74512-2.4502-7.85645-6.18457-7.85645
 | 
				
			||||||
 | 
					                C334.62598,117.47656,332.21484,120.43262,332.21484,125.37207z"/>
 | 
				
			||||||
 | 
					            <path class="claim" d="M356.05664,115.14258v3.2666c1.32227-2.4502,3.07227-3.61719,5.44531-3.61719
 | 
				
			||||||
 | 
					                c1.24414,0,2.2168,0.2334,3.30566,0.81738l-1.32227,2.72266c-0.89453-0.4668-1.43848-0.62207-2.37207-0.62207
 | 
				
			||||||
 | 
					                c-3.15039,0-5.05664,2.52734-5.05664,6.61133v11.16309h-3.22852v-20.3418H356.05664z"/>
 | 
				
			||||||
 | 
					            <path class="claim" d="M387.52148,134.8623c-0.97266,0.58301-1.98438,0.93359-3.5791,0.93359
 | 
				
			||||||
 | 
					                c-2.95508,0-4.93945-1.32324-4.93945-5.36816v-24.23145h3.22852v24.50391c0,1.90625,1.01172,2.41113,2.2168,2.41113
 | 
				
			||||||
 | 
					                c0.93359,0,1.51758-0.27148,2.02246-0.66113L387.52148,134.8623z"/>
 | 
				
			||||||
 | 
					            <path class="claim" d="M395.96094,108.80273c0,1.16699-0.97266,2.13867-2.13965,2.13867s-2.13867-0.97168-2.13867-2.13867
 | 
				
			||||||
 | 
					                s0.97168-2.13965,2.13867-2.13965S395.96094,107.63574,395.96094,108.80273z M395.49414,115.14258v20.3418h-3.22852v-20.3418
 | 
				
			||||||
 | 
					                H395.49414z"/>
 | 
				
			||||||
 | 
					            <path class="claim" d="M403.93359,115.14258v-2.83984c0-4.16113,2.2168-6.53418,6.02832-6.53418
 | 
				
			||||||
 | 
					                c1.36133,0,2.4502,0.27246,3.65625,0.93359l-0.81738,2.48926c-1.20508-0.58301-1.75-0.73926-2.68359-0.73926
 | 
				
			||||||
 | 
					                c-1.86719,0-2.95605,1.32324-2.95605,3.50098v3.18945h4.66797v2.68359h-4.66797v17.6582h-3.22754v-17.6582h-2.91797v-2.68359
 | 
				
			||||||
 | 
					                H403.93359z"/>
 | 
				
			||||||
 | 
					            <path class="claim" d="M431.89844,132.25586c-1.86719,2.68359-4.47266,3.57812-7.74023,3.57812
 | 
				
			||||||
 | 
					                c-6.45605,0-10.07324-4.23926-10.07324-10.46191c0-6.2627,3.77246-10.58008,9.25684-10.58008
 | 
				
			||||||
 | 
					                c5.40625,0,8.71191,3.8125,8.71191,10.11328v1.0498h-14.62402c0.07812,2.91699,0.73926,4.55078,2.13965,5.83398
 | 
				
			||||||
 | 
					                c1.0498,0.93359,2.41113,1.36133,4.51172,1.36133c2.25586,0,3.88965-0.62207,5.44531-2.7998L431.89844,132.25586z
 | 
				
			||||||
 | 
					                 M428.74805,123.34961c-0.42773-4.16211-1.9834-5.87305-5.36719-5.87305c-3.22852,0-5.0957,1.90527-5.83398,5.87305H428.74805z"/>
 | 
				
			||||||
 | 
					        </g>
 | 
				
			||||||
 | 
					        <g id="bosch">
 | 
				
			||||||
 | 
					        <g>
 | 
				
			||||||
 | 
					            <path class="bosch" d="M185.19998,46.7c0,0,8.79999-3,8.79999-13c0-11.7-8.29999-17.5-19.70001-17.5h-29.89996v63.59999h32.5
 | 
				
			||||||
 | 
					                c10,0,19.79999-7,19.79999-17.7C196.69998,49.39999,185.19998,46.8,185.19998,46.7z M160,29.39999h11.60001
 | 
				
			||||||
 | 
					                c3.60001,0,6,2.39999,6,6c0,2.8-2.20001,5.8-6.29999,5.8h-11.39999L160,29.39999L160,29.39999z M171.69998,66.5h-11.60001V54
 | 
				
			||||||
 | 
					                h11.30002c5.70001,0,8.39999,2.5,8.39999,6.2C179.79999,64.8,176.39999,66.5,171.69998,66.5z"/>
 | 
				
			||||||
 | 
					            <path class="bosch" d="M231.10001,14.60001c-18.39999,0-29.20001,14.7-29.20001,33.3c0,18.7,10.79999,33.3,29.20001,33.3
 | 
				
			||||||
 | 
					                c18.5,0,29.20001-14.60001,29.20001-33.3C260.29999,29.3,249.60001,14.60001,231.10001,14.60001z M231.10001,66
 | 
				
			||||||
 | 
					                c-9,0-13.5-8.10001-13.5-18.10001s4.5-18,13.5-18s13.60001,8.10001,13.60001,18C244.69998,58,240.10001,66,231.10001,66z"/>
 | 
				
			||||||
 | 
					            <path class="bosch" d="M294.19998,41.2l-2.20001-0.5c-5.39999-1.10001-9.70001-2.5-9.70001-6.39999
 | 
				
			||||||
 | 
					                c0-4.2,4.10001-5.89999,7.70001-5.89999c5.29999,0,10,2.60001,13,5.89999l9.89999-9.8c-4.5-5.10001-11.79999-10-23.20001-10
 | 
				
			||||||
 | 
					                c-13.39999,0-23.60001,7.5-23.60001,20c0,11.39999,8.20001,17,18.20001,19.10001l2.20001,0.5c8.29999,1.7,11.39999,3,11.39999,7
 | 
				
			||||||
 | 
					                c0,3.8-3.39999,6.3-8.60001,6.3c-6.20001,0-11.79999-2.7-16.10001-8.2l-10.10001,10
 | 
				
			||||||
 | 
					                c5.60001,6.7,12.70001,11.89999,26.39999,11.89999c11.89999,0,24.60001-6.8,24.60001-20.7
 | 
				
			||||||
 | 
					                C314.29999,45.89999,303.29999,43.10001,294.19998,41.2z"/>
 | 
				
			||||||
 | 
					            <path class="bosch" d="M349.69998,66c-7,0-14.29999-5.8-14.29999-18.5c0-11.3,6.79999-17.60001,13.89999-17.60001
 | 
				
			||||||
 | 
					                c5.60001,0,8.89999,2.60001,11.5,7.10001l12.79999-8.5c-6.39999-9.7-14-13.8-24.5-13.8
 | 
				
			||||||
 | 
					                c-19.20001,0-29.60001,14.89999-29.60001,32.90001c0,18.89999,11.5,33.7,29.39999,33.7
 | 
				
			||||||
 | 
					                c12.60001,0,18.60001-4.39999,25.10001-13.8l-12.89999-8.7C358.5,63,355.69998,66,349.69998,66z"/>
 | 
				
			||||||
 | 
					            <polygon class="bosch" points="416.30002,16.2 416.30002,39.60001 396.99997,39.60001 396.99997,16.2 380.29999,16.2
 | 
				
			||||||
 | 
					                380.29999,79.8 396.99997,79.8 396.99997,54.7 416.30002,54.7 416.30002,79.8 432.99997,79.8 432.99997,16.2 			"/>
 | 
				
			||||||
 | 
					        </g>
 | 
				
			||||||
 | 
					            <g>
 | 
				
			||||||
 | 
					            <path class="bosch" d="M185.19998,46.7c0,0,8.79999-3,8.79999-13c0-11.7-8.29999-17.5-19.70001-17.5h-29.89996v63.59999h32.5
 | 
				
			||||||
 | 
					                c10,0,19.79999-7,19.79999-17.7C196.69998,49.39999,185.19998,46.8,185.19998,46.7z M160,29.39999h11.60001
 | 
				
			||||||
 | 
					                c3.60001,0,6,2.39999,6,6c0,2.8-2.20001,5.8-6.29999,5.8h-11.39999L160,29.39999L160,29.39999z M171.69998,66.5h-11.60001V54
 | 
				
			||||||
 | 
					                h11.30002c5.70001,0,8.39999,2.5,8.39999,6.2C179.79999,64.8,176.39999,66.5,171.69998,66.5z"/>
 | 
				
			||||||
 | 
					                <path class="bosch" d="M231.10001,14.60001c-18.39999,0-29.20001,14.7-29.20001,33.3c0,18.7,10.79999,33.3,29.20001,33.3
 | 
				
			||||||
 | 
					                c18.5,0,29.20001-14.60001,29.20001-33.3C260.29999,29.3,249.60001,14.60001,231.10001,14.60001z M231.10001,66
 | 
				
			||||||
 | 
					                c-9,0-13.5-8.10001-13.5-18.10001s4.5-18,13.5-18s13.60001,8.10001,13.60001,18C244.69998,58,240.10001,66,231.10001,66z"/>
 | 
				
			||||||
 | 
					                <path class="bosch" d="M294.19998,41.2l-2.20001-0.5c-5.39999-1.10001-9.70001-2.5-9.70001-6.39999
 | 
				
			||||||
 | 
					                c0-4.2,4.10001-5.89999,7.70001-5.89999c5.29999,0,10,2.60001,13,5.89999l9.89999-9.8c-4.5-5.10001-11.79999-10-23.20001-10
 | 
				
			||||||
 | 
					                c-13.39999,0-23.60001,7.5-23.60001,20c0,11.39999,8.20001,17,18.20001,19.10001l2.20001,0.5c8.29999,1.7,11.39999,3,11.39999,7
 | 
				
			||||||
 | 
					                c0,3.8-3.39999,6.3-8.60001,6.3c-6.20001,0-11.79999-2.7-16.10001-8.2l-10.10001,10
 | 
				
			||||||
 | 
					                c5.60001,6.7,12.70001,11.89999,26.39999,11.89999c11.89999,0,24.60001-6.8,24.60001-20.7
 | 
				
			||||||
 | 
					                C314.29999,45.89999,303.29999,43.10001,294.19998,41.2z"/>
 | 
				
			||||||
 | 
					                <path class="bosch" d="M349.69998,66c-7,0-14.29999-5.8-14.29999-18.5c0-11.3,6.79999-17.60001,13.89999-17.60001
 | 
				
			||||||
 | 
					                c5.60001,0,8.89999,2.60001,11.5,7.10001l12.79999-8.5c-6.39999-9.7-14-13.8-24.5-13.8
 | 
				
			||||||
 | 
					                c-19.20001,0-29.60001,14.89999-29.60001,32.90001c0,18.89999,11.5,33.7,29.39999,33.7
 | 
				
			||||||
 | 
					                c12.60001,0,18.60001-4.39999,25.10001-13.8l-12.89999-8.7C358.5,63,355.69998,66,349.69998,66z"/>
 | 
				
			||||||
 | 
					                <polygon class="bosch" points="416.30002,16.2 416.30002,39.60001 396.99997,39.60001 396.99997,16.2 380.29999,16.2
 | 
				
			||||||
 | 
					                380.29999,79.8 396.99997,79.8 396.99997,54.7 416.30002,54.7 416.30002,79.8 432.99997,79.8 432.99997,16.2 			"/>
 | 
				
			||||||
 | 
					        </g>
 | 
				
			||||||
 | 
					    </g>
 | 
				
			||||||
 | 
					        <g id="anker">
 | 
				
			||||||
 | 
					        <g>
 | 
				
			||||||
 | 
					            <path class="anker" d="M48.2,0C21.59999,0,0,21.60001,0,48.2s21.60001,48.2,48.2,48.2s48.2-21.60001,48.2-48.2S74.79999,0,48.2,0
 | 
				
			||||||
 | 
					                z M48.2,91.89999c-24.10001,0-43.7-19.60001-43.7-43.7S24.10001,4.5,48.2,4.5s43.7,19.60001,43.7,43.7
 | 
				
			||||||
 | 
					                S72.29999,91.89999,48.2,91.89999z"/>
 | 
				
			||||||
 | 
					            <path class="anker" d="M68.09999,18.10001h-3.3v16.5H31.69998v-16.5h-3.39999c-9.7,6.5-16.2,17.5-16.2,30.10001
 | 
				
			||||||
 | 
					                s6.5,23.60001,16.2,30.10001h3.39999v-16.5h33.10001v16.5h3.3c9.8-6.5,16.2-17.5,16.2-30.10001
 | 
				
			||||||
 | 
					                S77.89999,24.60001,68.09999,18.10001z M27.09999,71.8c-6.7-5.89999-10.60001-14.39999-10.60001-23.60001
 | 
				
			||||||
 | 
					                c0-9.2,3.89999-17.7,10.60001-23.60001V71.8z M64.79999,57.2H31.69998V39.09999h33.10001V57.2z M69.29999,71.7v-10l0,0V34.59999
 | 
				
			||||||
 | 
					                l0,0v-10c6.60001,5.89999,10.5,14.39999,10.5,23.5C79.79999,57.3,75.89999,65.8,69.29999,71.7z"/>
 | 
				
			||||||
 | 
					        </g>
 | 
				
			||||||
 | 
					            <g>
 | 
				
			||||||
 | 
					            <path class="anker" d="M48.2,0C21.59999,0,0,21.60001,0,48.2s21.60001,48.2,48.2,48.2s48.2-21.60001,48.2-48.2S74.79999,0,48.2,0
 | 
				
			||||||
 | 
					                z M48.2,91.89999c-24.10001,0-43.7-19.60001-43.7-43.7S24.10001,4.5,48.2,4.5s43.7,19.60001,43.7,43.7
 | 
				
			||||||
 | 
					                S72.29999,91.89999,48.2,91.89999z"/>
 | 
				
			||||||
 | 
					                <path class="anker" d="M68.09999,18.10001h-3.3v16.5H31.69998v-16.5h-3.39999c-9.7,6.5-16.2,17.5-16.2,30.10001
 | 
				
			||||||
 | 
					                s6.5,23.60001,16.2,30.10001h3.39999v-16.5h33.10001v16.5h3.3c9.8-6.5,16.2-17.5,16.2-30.10001
 | 
				
			||||||
 | 
					                S77.89999,24.60001,68.09999,18.10001z M27.09999,71.8c-6.7-5.89999-10.60001-14.39999-10.60001-23.60001
 | 
				
			||||||
 | 
					                c0-9.2,3.89999-17.7,10.60001-23.60001V71.8z M64.79999,57.2H31.69998V39.09999h33.10001V57.2z M69.29999,71.7v-10l0,0V34.59999
 | 
				
			||||||
 | 
					                l0,0v-10c6.60001,5.89999,10.5,14.39999,10.5,23.5C79.79999,57.3,75.89999,65.8,69.29999,71.7z"/>
 | 
				
			||||||
 | 
					        </g>
 | 
				
			||||||
 | 
					    </g>
 | 
				
			||||||
 | 
					</g>
 | 
				
			||||||
 | 
					</svg>
 | 
				
			||||||
| 
		 After Width: | Height: | Size: 14 KiB  | 
							
								
								
									
										306
									
								
								static/styles/swagger.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										306
									
								
								static/styles/swagger.css
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							@@ -4,13 +4,21 @@
 | 
				
			|||||||
    "target": "es5",
 | 
					    "target": "es5",
 | 
				
			||||||
    "outDir": "dist",
 | 
					    "outDir": "dist",
 | 
				
			||||||
    "sourceMap": true,
 | 
					    "sourceMap": true,
 | 
				
			||||||
    "esModuleInterop": true
 | 
					    "esModuleInterop": true,
 | 
				
			||||||
 | 
					    "resolveJsonModule": true,
 | 
				
			||||||
 | 
					    "incremental": true,
 | 
				
			||||||
 | 
					    "diagnostics": true,
 | 
				
			||||||
 | 
					    "typeRoots": [
 | 
				
			||||||
 | 
					      "src/customTypings",
 | 
				
			||||||
 | 
					      "node_modules/@types"
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  "files": [
 | 
					  "files": [
 | 
				
			||||||
    "./node_modules/@types/node/index.d.ts"
 | 
					    "./node_modules/@types/node/index.d.ts"
 | 
				
			||||||
  ],
 | 
					  ],
 | 
				
			||||||
  "include": [
 | 
					  "include": [
 | 
				
			||||||
    "src/**/*.ts"
 | 
					    "src/**/*.ts",
 | 
				
			||||||
 | 
					    "src/**/*.json"
 | 
				
			||||||
  ],
 | 
					  ],
 | 
				
			||||||
  "exclude": [
 | 
					  "exclude": [
 | 
				
			||||||
    "node_modules"
 | 
					    "node_modules"
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user