summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorgebele <gebele@in-silico.ch>2018-06-11 12:46:06 +0200
committergebele <gebele@in-silico.ch>2018-06-11 12:46:06 +0200
commit3a11ba2918795821600b7113d0758415718d263a (patch)
tree2c03bdf1ed63582b8bb865c858ce225dee791a34
parent409c8a5a353235c91cbf965a885dd12da699d993 (diff)
combine gui with rest
-rw-r--r--api/api.json1098
-rw-r--r--application.rb21
-rw-r--r--lib/aa.rb82
-rw-r--r--lib/api.rb9
-rw-r--r--lib/compound.rb64
-rw-r--r--lib/dataset.rb46
-rw-r--r--lib/feature.rb29
-rw-r--r--lib/lazar-rest.rb69
-rw-r--r--lib/model.rb38
-rw-r--r--lib/nanoparticle.rb30
-rw-r--r--lib/report.rb208
-rw-r--r--lib/substance.rb30
-rw-r--r--lib/swagger.rb6
-rw-r--r--lib/validation.rb71
14 files changed, 1799 insertions, 2 deletions
diff --git a/api/api.json b/api/api.json
new file mode 100644
index 0000000..9976569
--- /dev/null
+++ b/api/api.json
@@ -0,0 +1,1098 @@
+{
+ "openapi": "3.0.0",
+ "x-orn-@id": "https://lazar.prod.openrisknet.org",
+ "x-orn-@type": "x-orn:Service",
+ "x-orn-@context": {
+ "@vocab": "http://openrisknet.org/schema#",
+ "x-orn": "http://openrisknet.org/schema#",
+ "x-orn-@id": "@id",
+ "x-orn-@type": "@type"
+ },
+ "servers": [
+ {
+ "url": "https://lazar.prod.openrisknet.org/"
+ }
+ ],
+ "info": {
+ "description": "REST API webservice for lazar and nano-lazar. \n\n*lazar* (lazy structure–activity relationships) is a modular framework for\npredictive toxicology. With activated Authentication & Authorization,\nsubjectid authorization token are obligatory for designated services.\n",
+ "version": "1.1.0",
+ "title": "Lazar & Nano-Lazar REST Service",
+ "contact": {
+ "name": "in silico toxicology gmbh",
+ "email": "info@in-silico.ch",
+ "url": "https://in-silico.ch"
+ },
+ "license": {
+ "name": "GNU GENERAL PUBLIC LICENSE",
+ "url": "https://github.com/opentox/lazar-rest/blob/master/LICENSE"
+ }
+ },
+ "externalDocs": {
+ "description": "See also *lazar-rest* documentation on Github\n",
+ "url": "https://github.com/opentox/lazar-rest"
+ },
+ "paths": {
+ "/model": {
+ "get": {
+ "x-orn-@type": "x-orn:Model",
+ "x-orn:path": "https://lazar.prod.openrisknet.org/model",
+ "x-orn:method": "Get",
+ "tags": [
+ "model"
+ ],
+ "description": "Get a list of all prediction models",
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/subjectid"
+ }
+ ],
+ "responses": {
+ "200": {
+ "$ref": "#/components/responses/200"
+ },
+ "400": {
+ "$ref": "#/components/responses/400"
+ },
+ "401": {
+ "$ref": "#/components/responses/401"
+ },
+ "404": {
+ "$ref": "#/components/responses/404"
+ },
+ "500": {
+ "$ref": "#/components/responses/500"
+ }
+ }
+ }
+ },
+ "/model/{id}": {
+ "get": {
+ "x-orn-@type": "x-orn:Model",
+ "x-orn:path": "https://lazar.prod.openrisknet.org/model",
+ "x-orn:method": "Get",
+ "tags": [
+ "model"
+ ],
+ "description": "Get model representation",
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/id"
+ },
+ {
+ "$ref": "#/components/parameters/subjectid"
+ }
+ ],
+ "responses": {
+ "200": {
+ "$ref": "#/components/responses/200"
+ },
+ "400": {
+ "$ref": "#/components/responses/400"
+ },
+ "401": {
+ "$ref": "#/components/responses/401"
+ },
+ "403": {
+ "$ref": "#/components/responses/403"
+ },
+ "404": {
+ "$ref": "#/components/responses/404"
+ }
+ }
+ },
+ "post": {
+ "x-orn-@type": "x-orn:Prediction",
+ "x-orn:path": "https://lazar.prod.openrisknet.org/model/{id}",
+ "x-orn:method": "Post",
+ "tags": [
+ "model"
+ ],
+ "description": "Predict a compound or a nanoparticle",
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/id"
+ },
+ {
+ "$ref": "#/components/parameters/subjectid"
+ }
+ ],
+ "responses": {
+ "200": {
+ "$ref": "#/components/responses/200"
+ },
+ "400": {
+ "$ref": "#/components/responses/400"
+ },
+ "401": {
+ "$ref": "#/components/responses/401"
+ },
+ "403": {
+ "$ref": "#/components/responses/403"
+ },
+ "404": {
+ "$ref": "#/components/responses/404"
+ }
+ },
+ "requestBody": {
+ "description": "SMILES identifier or Nanoparticle URI or comma separated\nlist of SMILES identifiers or Nanoparticle URI\n",
+ "required": true,
+ "content": {
+ "application/x-www-form-urlencoded": {
+ "x-orn:schema": "application/x-www-form-urlencoded",
+ "schema": {
+ "$ref": "#/components/schemas/postmodel"
+ }
+ }
+ }
+ }
+ }
+ },
+ "/report": {
+ "get": {
+ "x-orn-@type": "x-orn:Report",
+ "x-orn:path": "https://lazar.prod.openrisknet.org/report",
+ "x-orn:method": "Get",
+ "tags": [
+ "report"
+ ],
+ "description": "Get a list of QMRF reports",
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/subjectid"
+ }
+ ],
+ "responses": {
+ "200": {
+ "$ref": "#/components/responses/200"
+ },
+ "400": {
+ "$ref": "#/components/responses/400"
+ },
+ "401": {
+ "$ref": "#/components/responses/401"
+ },
+ "404": {
+ "$ref": "#/components/responses/404"
+ },
+ "500": {
+ "$ref": "#/components/responses/500"
+ }
+ }
+ }
+ },
+ "/report/{id}": {
+ "get": {
+ "x-orn-@type": "x-orn:Report",
+ "x-orn:path": "https://lazar.prod.openrisknet.org/report/{id}",
+ "x-orn:method": "Get",
+ "tags": [
+ "report"
+ ],
+ "description": "Get QMRF for prediction model",
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/id"
+ },
+ {
+ "$ref": "#/components/parameters/subjectid"
+ }
+ ],
+ "responses": {
+ "200": {
+ "$ref": "#/components/responses/200"
+ },
+ "400": {
+ "$ref": "#/components/responses/400"
+ },
+ "401": {
+ "$ref": "#/components/responses/401"
+ },
+ "403": {
+ "$ref": "#/components/responses/403"
+ },
+ "404": {
+ "$ref": "#/components/responses/404"
+ }
+ }
+ }
+ },
+ "/dataset": {
+ "get": {
+ "x-orn-@type": "x-orn:Dataset",
+ "x-orn:path": "https://lazar.prod.openrisknet.org/dataset",
+ "x-orn:method": "Get",
+ "tags": [
+ "dataset"
+ ],
+ "description": "Get a list of all datasets",
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/subjectid"
+ }
+ ],
+ "responses": {
+ "200": {
+ "$ref": "#/components/responses/200"
+ },
+ "400": {
+ "$ref": "#/components/responses/400"
+ },
+ "401": {
+ "$ref": "#/components/responses/401"
+ },
+ "404": {
+ "$ref": "#/components/responses/404"
+ },
+ "500": {
+ "$ref": "#/components/responses/500"
+ }
+ }
+ }
+ },
+ "/dataset/{id}": {
+ "get": {
+ "x-orn-@type": "x-orn:Dataset",
+ "x-orn:path": "https://lazar.prod.openrisknet.org/dataset/{id}",
+ "x-orn:method": "Get",
+ "tags": [
+ "dataset"
+ ],
+ "description": "Get dataset representation",
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/id"
+ },
+ {
+ "$ref": "#/components/parameters/subjectid"
+ }
+ ],
+ "responses": {
+ "200": {
+ "$ref": "#/components/responses/200"
+ },
+ "400": {
+ "$ref": "#/components/responses/400"
+ },
+ "401": {
+ "$ref": "#/components/responses/401"
+ },
+ "403": {
+ "$ref": "#/components/responses/403"
+ },
+ "404": {
+ "$ref": "#/components/responses/404"
+ },
+ "500": {
+ "$ref": "#/components/responses/500"
+ }
+ }
+ }
+ },
+ "/dataset/{id}/{attribute}": {
+ "get": {
+ "x-orn-@type": "x-orn:Dataset",
+ "x-orn:path": "https://lazar.prod.openrisknet.org/dataset/{id}/{attribute}",
+ "x-orn:method": "Get",
+ "tags": [
+ "dataset"
+ ],
+ "description": "Get dataset representation",
+ "parameters": [
+ {
+ "name": "attribute",
+ "in": "path",
+ "description": "requested attribute",
+ "required": true,
+ "schema": {
+ "type": "string",
+ "enum": [
+ "compounds",
+ "nanoparticles",
+ "substances",
+ "features"
+ ]
+ }
+ },
+ {
+ "$ref": "#/components/parameters/id"
+ },
+ {
+ "$ref": "#/components/parameters/subjectid"
+ }
+ ],
+ "responses": {
+ "200": {
+ "$ref": "#/components/responses/200"
+ },
+ "400": {
+ "$ref": "#/components/responses/400"
+ },
+ "401": {
+ "$ref": "#/components/responses/401"
+ },
+ "403": {
+ "$ref": "#/components/responses/403"
+ },
+ "404": {
+ "$ref": "#/components/responses/404"
+ },
+ "500": {
+ "$ref": "#/components/responses/500"
+ }
+ }
+ }
+ },
+ "/substance": {
+ "get": {
+ "x-orn-@type": "x-orn:Substance",
+ "x-orn:path": "https://lazar.prod.openrisknet.org/substance",
+ "x-orn:method": "Get",
+ "tags": [
+ "substance"
+ ],
+ "description": "Get a list of all substances",
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/subjectid"
+ }
+ ],
+ "responses": {
+ "200": {
+ "$ref": "#/components/responses/200"
+ },
+ "400": {
+ "$ref": "#/components/responses/400"
+ },
+ "401": {
+ "$ref": "#/components/responses/401"
+ },
+ "404": {
+ "$ref": "#/components/responses/404"
+ },
+ "500": {
+ "$ref": "#/components/responses/500"
+ }
+ }
+ }
+ },
+ "/substance/{id}": {
+ "get": {
+ "x-orn-@type": "x-orn:Substance",
+ "x-orn:path": "https://lazar.prod.openrisknet.org/substance/{id}",
+ "x-orn:method": "Get",
+ "tags": [
+ "substance"
+ ],
+ "description": "Get substance representation",
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/id"
+ },
+ {
+ "$ref": "#/components/parameters/subjectid"
+ }
+ ],
+ "responses": {
+ "200": {
+ "$ref": "#/components/responses/200"
+ },
+ "400": {
+ "$ref": "#/components/responses/400"
+ },
+ "401": {
+ "$ref": "#/components/responses/401"
+ },
+ "403": {
+ "$ref": "#/components/responses/403"
+ },
+ "404": {
+ "$ref": "#/components/responses/404"
+ },
+ "500": {
+ "$ref": "#/components/responses/500"
+ }
+ }
+ }
+ },
+ "/nanoparticle": {
+ "get": {
+ "x-orn-@type": "x-orn:Nanoparticle",
+ "x-orn:path": "https://lazar.prod.openrisknet.org/nanoparticle",
+ "x-orn:method": "Get",
+ "tags": [
+ "nanoparticle"
+ ],
+ "description": "Get a list of all nanoparticles",
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/subjectid"
+ }
+ ],
+ "responses": {
+ "200": {
+ "$ref": "#/components/responses/200"
+ },
+ "400": {
+ "$ref": "#/components/responses/400"
+ },
+ "401": {
+ "$ref": "#/components/responses/401"
+ },
+ "404": {
+ "$ref": "#/components/responses/404"
+ },
+ "500": {
+ "$ref": "#/components/responses/500"
+ }
+ }
+ }
+ },
+ "/nanoparticle/{id}": {
+ "get": {
+ "x-orn-@type": "x-orn:Nanoparticle",
+ "x-orn:path": "https://lazar.prod.openrisknet.org/nanoparticle/{id}",
+ "x-orn:method": "Get",
+ "tags": [
+ "nanoparticle"
+ ],
+ "description": "Get nanoparticle representation",
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/id"
+ },
+ {
+ "$ref": "#/components/parameters/subjectid"
+ }
+ ],
+ "responses": {
+ "200": {
+ "$ref": "#/components/responses/200"
+ },
+ "400": {
+ "$ref": "#/components/responses/400"
+ },
+ "401": {
+ "$ref": "#/components/responses/401"
+ },
+ "403": {
+ "$ref": "#/components/responses/403"
+ },
+ "404": {
+ "$ref": "#/components/responses/404"
+ },
+ "500": {
+ "$ref": "#/components/responses/500"
+ }
+ }
+ }
+ },
+ "/feature": {
+ "get": {
+ "x-orn-@type": "x-orn:Feature",
+ "x-orn:path": "https://lazar.prod.openrisknet.org/feature",
+ "x-orn:method": "Get",
+ "tags": [
+ "feature"
+ ],
+ "description": "Get a list of ids for all features",
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/subjectid"
+ }
+ ],
+ "responses": {
+ "200": {
+ "$ref": "#/components/responses/200"
+ },
+ "400": {
+ "$ref": "#/components/responses/400"
+ },
+ "401": {
+ "$ref": "#/components/responses/401"
+ },
+ "404": {
+ "$ref": "#/components/responses/404"
+ },
+ "500": {
+ "$ref": "#/components/responses/500"
+ }
+ }
+ }
+ },
+ "/feature/{id}": {
+ "get": {
+ "x-orn-@type": "x-orn:Feature",
+ "x-orn:path": "https://lazar.prod.openrisknet.org/feature/{id}",
+ "x-orn:method": "Get",
+ "tags": [
+ "feature"
+ ],
+ "description": "Get feature representation",
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/id"
+ },
+ {
+ "$ref": "#/components/parameters/subjectid"
+ }
+ ],
+ "responses": {
+ "200": {
+ "$ref": "#/components/responses/200"
+ },
+ "400": {
+ "$ref": "#/components/responses/400"
+ },
+ "401": {
+ "$ref": "#/components/responses/401"
+ },
+ "403": {
+ "$ref": "#/components/responses/403"
+ },
+ "404": {
+ "$ref": "#/components/responses/404"
+ },
+ "500": {
+ "$ref": "#/components/responses/500"
+ }
+ }
+ }
+ },
+ "/validation": {
+ "get": {
+ "x-orn-@type": "x-orn:Validation",
+ "x-orn:path": "https://lazar.prod.openrisknet.org/validation",
+ "x-orn:method": "Get",
+ "tags": [
+ "validation"
+ ],
+ "description": "Get a list of all validation types",
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/subjectid"
+ }
+ ],
+ "responses": {
+ "200": {
+ "$ref": "#/components/responses/200"
+ },
+ "400": {
+ "$ref": "#/components/responses/400"
+ },
+ "401": {
+ "$ref": "#/components/responses/401"
+ },
+ "404": {
+ "$ref": "#/components/responses/404"
+ },
+ "500": {
+ "$ref": "#/components/responses/500"
+ }
+ }
+ }
+ },
+ "/validation/{validationtype}": {
+ "get": {
+ "x-orn-@type": "x-orn:Validation",
+ "x-orn:path": "https://lazar.prod.openrisknet.org/validation/{validationtype}",
+ "x-orn:method": "Get",
+ "tags": [
+ "validation"
+ ],
+ "description": "Get all validations of a validation type",
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/valtype"
+ },
+ {
+ "$ref": "#/components/parameters/subjectid"
+ }
+ ],
+ "responses": {
+ "200": {
+ "$ref": "#/components/responses/200"
+ },
+ "400": {
+ "$ref": "#/components/responses/400"
+ },
+ "401": {
+ "$ref": "#/components/responses/401"
+ },
+ "403": {
+ "$ref": "#/components/responses/403"
+ },
+ "404": {
+ "$ref": "#/components/responses/404"
+ },
+ "500": {
+ "$ref": "#/components/responses/500"
+ }
+ }
+ }
+ },
+ "/validation/{validationtype}/{id}": {
+ "get": {
+ "x-orn-@type": "x-orn:Validation",
+ "x-orn:path": "https://lazar.prod.openrisknet.org/validation/{validationtype}/{id}",
+ "x-orn:method": "Get",
+ "tags": [
+ "validation"
+ ],
+ "description": "Get validation representation",
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/valtype"
+ },
+ {
+ "$ref": "#/components/parameters/id"
+ },
+ {
+ "$ref": "#/components/parameters/subjectid"
+ }
+ ],
+ "responses": {
+ "200": {
+ "$ref": "#/components/responses/200"
+ },
+ "400": {
+ "$ref": "#/components/responses/400"
+ },
+ "401": {
+ "$ref": "#/components/responses/401"
+ },
+ "403": {
+ "$ref": "#/components/responses/403"
+ },
+ "404": {
+ "$ref": "#/components/responses/404"
+ },
+ "500": {
+ "$ref": "#/components/responses/500"
+ }
+ }
+ }
+ },
+ "/compound/descriptor": {
+ "get": {
+ "x-orn-@type": "x-orn:Descriptor",
+ "x-orn:path": "https://lazar.prod.openrisknet.org/compound/descriptor",
+ "x-orn:method": "Get",
+ "tags": [
+ "compound",
+ "descriptor"
+ ],
+ "description": "Get a list of all descriptors",
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/subjectid"
+ }
+ ],
+ "responses": {
+ "200": {
+ "$ref": "#/components/responses/200"
+ },
+ "400": {
+ "$ref": "#/components/responses/400"
+ },
+ "401": {
+ "$ref": "#/components/responses/401"
+ },
+ "404": {
+ "$ref": "#/components/responses/404"
+ },
+ "500": {
+ "$ref": "#/components/responses/500"
+ }
+ }
+ },
+ "post": {
+ "x-orn-@type": "x-orn:Prediction",
+ "x-orn:path": "https://lazar.prod.openrisknet.org/compound/descriptor",
+ "x-orn:method": "Post",
+ "tags": [
+ "compound",
+ "descriptor"
+ ],
+ "summary": "Descriptor calculation",
+ "description": "Calculate descriptors for a single compound as SMILES string",
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/subjectid"
+ }
+ ],
+ "responses": {
+ "200": {
+ "$ref": "#/components/responses/200"
+ },
+ "400": {
+ "$ref": "#/components/responses/400"
+ },
+ "401": {
+ "$ref": "#/components/responses/401"
+ },
+ "404": {
+ "$ref": "#/components/responses/404"
+ },
+ "500": {
+ "$ref": "#/components/responses/500"
+ }
+ },
+ "requestBody": {
+ "description": "identifier and descriptor/s",
+ "required": true,
+ "content": {
+ "application/x-www-form-urlencoded": {
+ "x-orn:schema": "application/x-www-form-urlencoded",
+ "schema": {
+ "$ref": "#/components/schemas/postdescriptor"
+ }
+ }
+ }
+ }
+ }
+ },
+ "/compound/descriptor/{descriptor}": {
+ "get": {
+ "x-orn-@type": "x-orn:Descriptor",
+ "x-orn:path": "https://lazar.prod.openrisknet.org/compound/descriptor/{descriptor}",
+ "x-orn:method": "Get",
+ "tags": [
+ "compound",
+ "descriptor"
+ ],
+ "description": "Get informations about a single descriptor",
+ "parameters": [
+ {
+ "name": "descriptor",
+ "in": "path",
+ "description": "descriptor name or ID",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "$ref": "#/components/parameters/subjectid"
+ }
+ ],
+ "responses": {
+ "200": {
+ "$ref": "#/components/responses/200"
+ },
+ "400": {
+ "$ref": "#/components/responses/400"
+ },
+ "401": {
+ "$ref": "#/components/responses/401"
+ },
+ "404": {
+ "$ref": "#/components/responses/404"
+ },
+ "500": {
+ "$ref": "#/components/responses/500"
+ }
+ }
+ }
+ },
+ "/compound/{InChI}": {
+ "get": {
+ "x-orn-@type": "x-orn:Compound",
+ "x-orn:path": "https://lazar.prod.openrisknet.org/compound/{InChI}",
+ "x-orn:method": "Get",
+ "tags": [
+ "compound"
+ ],
+ "description": "Get compound representation",
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/InChI"
+ },
+ {
+ "$ref": "#/components/parameters/subjectid"
+ }
+ ],
+ "responses": {
+ "200": {
+ "$ref": "#/components/responses/200"
+ },
+ "400": {
+ "$ref": "#/components/responses/400"
+ }
+ }
+ }
+ },
+ "/api/api.json": {
+ "get": {
+ "tags": [
+ "api"
+ ],
+ "description": "Get swagger api in JSON",
+ "responses": {
+ "200": {
+ "$ref": "#/components/responses/200"
+ },
+ "400": {
+ "$ref": "#/components/responses/400"
+ },
+ "500": {
+ "$ref": "#/components/responses/500"
+ }
+ }
+ }
+ },
+ "/aa/authenticate": {
+ "post": {
+ "x-orn-@type": "x-orn:Authentication",
+ "x-orn:path": "https://lazar.prod.openrisknet.org/aa/authenticate",
+ "x-orn:method": "Post",
+ "tags": [
+ "authentication"
+ ],
+ "summary": "Get token",
+ "description": "Authentication against OpenSSO. Returns authentication token. Requires\nUsername and Password.\n",
+ "operationId": "login",
+ "responses": {
+ "200": {
+ "$ref": "#/components/responses/200"
+ },
+ "400": {
+ "$ref": "#/components/responses/400"
+ },
+ "401": {
+ "$ref": "#/components/responses/401"
+ },
+ "500": {
+ "$ref": "#/components/responses/500"
+ }
+ },
+ "requestBody": {
+ "description": "username and password",
+ "required": true,
+ "content": {
+ "application/x-www-form-urlencoded": {
+ "x-orn:schema": "application/x-www-form-urlencoded",
+ "schema": {
+ "$ref": "#/components/schemas/postauth"
+ }
+ }
+ }
+ }
+ }
+ },
+ "/aa/logout": {
+ "post": {
+ "x-orn-@type": "x-orn:Authentication",
+ "x-orn:path": "https://lazar.prod.openrisknet.org/aa/logout",
+ "x-orn:method": "Post",
+ "description": "Devalidates a token. Requires Subjectid.",
+ "summary": "Destroy token",
+ "operationId": "logout",
+ "tags": [
+ "authentication"
+ ],
+ "responses": {
+ "200": {
+ "$ref": "#/components/responses/200"
+ },
+ "400": {
+ "$ref": "#/components/responses/400"
+ },
+ "401": {
+ "$ref": "#/components/responses/401"
+ },
+ "500": {
+ "$ref": "#/components/responses/500"
+ }
+ },
+ "requestBody": {
+ "required": true,
+ "content": {
+ "application/x-www-form-urlencoded": {
+ "x-orn:schema": "application/x-www-form-urlencoded",
+ "schema": {
+ "$ref": "#/components/schemas/postlogout"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "tags": [
+ {
+ "name": "api",
+ "description": "Swagger API representation in JSON"
+ },
+ {
+ "name": "algorithm",
+ "description": "Algorithm"
+ },
+ {
+ "name": "authentication",
+ "description": "minimal Authentication service"
+ },
+ {
+ "name": "compound",
+ "description": "Compound"
+ },
+ {
+ "name": "dataset",
+ "description": "Dataset"
+ },
+ {
+ "name": "descriptor",
+ "description": "Descriptor"
+ },
+ {
+ "name": "feature",
+ "description": "Feature"
+ },
+ {
+ "name": "model",
+ "description": "Lazar Model Service"
+ },
+ {
+ "name": "nanoparticle",
+ "description": "Nanoparticle"
+ },
+ {
+ "name": "report",
+ "description": "QMRF Reporting"
+ },
+ {
+ "name": "substance",
+ "description": "Substance"
+ },
+ {
+ "name": "validation",
+ "description": "Validation"
+ }
+ ],
+ "components": {
+ "schemas": {
+ "postmodel": {
+ "type": "object",
+ "properties": {
+ "identifier": {
+ "x-orn:property": "identifier",
+ "type": "string",
+ "example": "O=C1NC(=O)NC=C1"
+ }
+ }
+ },
+ "postdescriptor": {
+ "type": "object",
+ "properties": {
+ "identifier": {
+ "x-orn:property": "identifier",
+ "type": "string",
+ "example": "O=C1NC(=O)NC=C1"
+ },
+ "descriptor": {
+ "x-orn:property": "descriptor",
+ "type": "string",
+ "example": "Openbabel.MW,Openbabel.atoms"
+ }
+ }
+ },
+ "postauth": {
+ "type": "object",
+ "properties": {
+ "username": {
+ "x-orn:property": "username",
+ "type": "string"
+ },
+ "password": {
+ "x-orn:property": "password",
+ "type": "string",
+ "format": "password"
+ }
+ }
+ },
+ "postlogout": {
+ "type": "object",
+ "properties": {
+ "subjectid": {
+ "x-orn:property": "subjectid",
+ "type": "string"
+ }
+ }
+ }
+ },
+ "parameters": {
+ "id": {
+ "name": "id",
+ "in": "path",
+ "description": "id",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ "InChI": {
+ "name": "InChI",
+ "in": "path",
+ "description": "InChI String",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ "valtype": {
+ "name": "validationtype",
+ "in": "path",
+ "description": "validation type",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ "subjectid": {
+ "in": "header",
+ "name": "subjectid",
+ "description": "authorization token",
+ "required": false,
+ "schema": {
+ "type": "string"
+ }
+ },
+ "subjectidRequired": {
+ "in": "header",
+ "name": "subjectid",
+ "description": "authorization token",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "OK",
+ "content": {
+ "application/json": {
+ "x-orn:returns": "application/json",
+ "schema": {
+ "type": "object"
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "Bad Request"
+ },
+ "401": {
+ "description": "Unauthorized"
+ },
+ "403": {
+ "description": "Forbidden"
+ },
+ "404": {
+ "description": "Resource Not Found"
+ },
+ "500": {
+ "description": "Server Error"
+ }
+ }
+ }
+}
diff --git a/application.rb b/application.rb
index 895b0c2..04e5352 100644
--- a/application.rb
+++ b/application.rb
@@ -26,10 +26,27 @@ error do
haml :error
end
-get '/?' do
- redirect to('/predict')
+# https://github.com/britg/sinatra-cross_origin#responding-to-options
+options "*" do
+ response.headers["Allow"] = "HEAD,GET,PUT,POST,DELETE,OPTIONS"
+ response.headers["Access-Control-Allow-Headers"] = "X-Requested-With, X-HTTP-Method-Override, Content-Type, Cache-Control, Accept"
+ 200
end
+[
+ "aa.rb",
+ "api.rb",
+ "compound.rb",
+ "dataset.rb",
+ "feature.rb",
+ "model.rb",
+ "nanoparticle.rb",
+ "report.rb",
+ "substance.rb",
+ "swagger.rb",
+ "validation.rb"
+].each{ |f| require_relative "./lib/#{f}" }
+
get '/predict/?' do
@models = OpenTox::Model::Validation.all
@models = @models.delete_if{|m| m.model.name =~ /\b(Net cell association)\b/}
diff --git a/lib/aa.rb b/lib/aa.rb
new file mode 100644
index 0000000..6dfec4b
--- /dev/null
+++ b/lib/aa.rb
@@ -0,0 +1,82 @@
+post "/aa/authenticate/?" do
+ mime_types = ["text/plain"]
+ bad_request_error "Mime type #{@accept} not supported here. Please request data as #{mime_types.join(', ')}." unless mime_types.include? @accept
+ bad_request_error "Please send formdata username." unless params[:username]
+ bad_request_error "Please send formdata password." unless params[:password]
+ case @accept
+ when "text/plain"
+ if OpenTox::Authorization.authenticate(params[:username], params[:password])
+ return OpenTox::RestClientWrapper.subjectid
+ else
+ return nil
+ end
+ else
+ bad_request_error "'#{@accept}' is not a supported content type."
+ end
+end
+
+post "/aa/logout/?" do
+ mime_types = ["text/plain"]
+ bad_request_error "Mime type #{@accept} not supported here. Please request data as #{mime_types.join(', ')}." unless mime_types.include? @accept
+ bad_request_error "Please send formdata subjectid." unless params[:subjectid]
+ case @accept
+ when "text/plain"
+ if OpenTox::Authorization.logout(params[:subjectid])
+ return "Successfully logged out. \n"
+ else
+ return "Logout failed.\n"
+ end
+ else
+ bad_request_error "'#{@accept}' is not a supported content type."
+ end
+end
+
+module OpenTox
+
+ AA = "https://opensso.in-silico.ch"
+
+ module Authorization
+ #Authentication against OpenSSO. Returns token. Requires Username and Password.
+ # @param user [String] Username
+ # @param pw [String] Password
+ # @return [Boolean] true if successful
+ def self.authenticate(user, pw)
+ begin
+ res = RestClientWrapper.post("#{AA}/auth/authenticate",{:username=>user, :password => pw},{:subjectid => ""}).sub("token.id=","").sub("\n","")
+ if is_token_valid(res)
+ RestClientWrapper.subjectid = res
+ return true
+ else
+ bad_request_error "Authentication failed #{res.inspect}"
+ end
+ rescue
+ bad_request_error "Authentication failed #{res.inspect}"
+ end
+ end
+
+ #Logout on opensso. Make token invalid. Requires token
+ # @param [String] subjectid the subjectid
+ # @return [Boolean] true if logout is OK
+ def self.logout(subjectid=RestClientWrapper.subjectid)
+ begin
+ out = RestClientWrapper.post("#{AA}/auth/logout", :subjectid => subjectid)
+ return true unless is_token_valid(subjectid)
+ rescue
+ return false
+ end
+ return false
+ end
+
+ #Checks if a token is a valid token
+ # @param [String]subjectid subjectid from openSSO session
+ # @return [Boolean] subjectid is valid or not.
+ def self.is_token_valid(subjectid=RestClientWrapper.subjectid)
+ begin
+ return true if RestClientWrapper.post("#{AA}/auth/isTokenValid",:tokenid => subjectid) == "boolean=true\n"
+ rescue #do rescue because openSSO throws 401
+ return false
+ end
+ return false
+ end
+ end
+end \ No newline at end of file
diff --git a/lib/api.rb b/lib/api.rb
new file mode 100644
index 0000000..28e33df
--- /dev/null
+++ b/lib/api.rb
@@ -0,0 +1,9 @@
+# route to swagger API file
+get "/api/api.json" do
+ response['Content-Type'] = "application/json"
+ api_file = File.join("api", "api.json")
+ bad_request_error "API Documentation in Swagger JSON is not implemented." unless File.exists?(api_file)
+ api_hash = JSON.parse(File.read(api_file))
+ api_hash["host"] = request.env['HTTP_HOST']
+ return api_hash.to_json
+end
diff --git a/lib/compound.rb b/lib/compound.rb
new file mode 100644
index 0000000..01ba036
--- /dev/null
+++ b/lib/compound.rb
@@ -0,0 +1,64 @@
+# Get a list of a single or all descriptors
+# @param [Header] Accept one of text/plain, application/json
+# @param [Path] Descriptor name or descriptor ID (e.G.: Openbabel.HBA1, 5755f8eb3cf99a00d8fedf2f)
+# @return [text/plain, application/json] list of all prediction models
+get "/compound/descriptor/?:descriptor?" do
+ case @accept
+ when "application/json"
+ return "#{JSON.pretty_generate PhysChem::DESCRIPTORS} " unless params[:descriptor]
+ return PhysChem.find_by(:name => params[:descriptor]).to_json if PhysChem::DESCRIPTORS.include?(params[:descriptor])
+ return PhysChem.find(params[:descriptor]).to_json if PhysChem.find(params[:descriptor])
+ else
+ return PhysChem::DESCRIPTORS.collect{|k, v| "#{k}: #{v}\n"} unless params[:descriptor]
+ return PhysChem::DESCRIPTORS[params[:descriptor]] if PhysChem::DESCRIPTORS.include?(params[:descriptor])
+ return "#{PhysChem.find(params[:descriptor]).name}: #{PhysChem.find(params[:descriptor]).description}" if PhysChem.find(params[:descriptor])
+ end
+end
+
+post "/compound/descriptor/?" do
+ bad_request_error "Missing Parameter " unless params[:identifier] && params[:descriptor]
+ descriptors = params['descriptor'].split(',')
+ compound = Compound.from_smiles params[:identifier]
+ physchem_descriptors = []
+ descriptors.each do |descriptor|
+ physchem_descriptors << PhysChem.find_by(:name => descriptor)
+ end
+ result = compound.calculate_properties physchem_descriptors
+ csv = (0..result.size-1).collect{|i| "\"#{physchem_descriptors[i].name}\",#{result[i]}"}.join("\n")
+ csv = "SMILES,\"#{params[:identifier]}\"\n#{csv}" if params[:identifier]
+ case @accept
+ when "text/csv","application/csv"
+ return csv
+ when "application/json"
+ result_hash = (0..result.size-1).collect{|i| {"#{physchem_descriptors[i].name}" => "#{result[i]}"}}
+ data = {"compound" => {"SMILES" => "#{params[:identifier]}"}}
+ data["compound"]["InChI"] = "#{compound.inchi}" if compound.inchi
+ data["compound"]["results"] = result_hash
+ return JSON.pretty_generate(data)
+ end
+end
+
+get %r{/compound/(.+)} do |inchi|
+ bad_request_error "Input parameter #{inchi} is not an InChI" unless inchi.match(/^InChI=/)
+ compound = Compound.from_inchi URI.unescape(inchi)
+ response['Content-Type'] = @accept
+ case @accept
+ when "application/json"
+ return JSON.pretty_generate JSON.parse(compound.to_json)
+ when "chemical/x-daylight-smiles"
+ return compound.smiles
+ when "chemical/x-inchi"
+ return compound.inchi
+ when "chemical/x-mdl-sdfile"
+ return compound.sdf
+ when "chemical/x-mdl-molfile"
+ when "image/png"
+ return compound.png
+ when "image/svg+xml"
+ return compound.svg
+ when "text/plain"
+ return "#{compound.names}\n"
+ else
+ return compound.inspect
+ end
+end \ No newline at end of file
diff --git a/lib/dataset.rb b/lib/dataset.rb
new file mode 100644
index 0000000..7c74f39
--- /dev/null
+++ b/lib/dataset.rb
@@ -0,0 +1,46 @@
+# Get all datasets
+get "/dataset/?" do
+ datasets = Dataset.all
+ case @accept
+ when "text/uri-list"
+ uri_list = datasets.collect{|dataset| uri("/dataset/#{dataset.id}")}
+ return uri_list.join("\n") + "\n"
+ when "application/json"
+ datasets = JSON.parse datasets.to_json
+ list = []
+ datasets.each{|d| list << uri("/dataset/#{d["_id"]["$oid"]}")}
+ return list.to_json
+ else
+ bad_request_error "Mime type #{@accept} is not supported."
+ end
+end
+
+# Get a dataset
+get "/dataset/:id/?" do
+ dataset = Dataset.find :id => params[:id]
+ not_found_error "Dataset with id: #{params[:id]} not found." unless dataset
+ case @accept
+ when "application/json"
+ dataset.data_entries.each do |k, v|
+ dataset.data_entries[k][:URI] = uri("/substance/#{k}")
+ end
+ dataset[:URI] = uri("/dataset/#{dataset.id}")
+ dataset[:substances] = uri("/dataset/#{dataset.id}/substances")
+ dataset[:features] = uri("/dataset/#{dataset.id}/features")
+ return dataset.to_json
+ when "text/csv", "application/csv"
+ return dataset.to_csv
+ else
+ bad_request_error "Mime type #{@accept} is not supported."
+ end
+end
+
+# Get a dataset attribute. One of compounds, nanoparticles, substances, features
+get "/dataset/:id/:attribute/?" do
+ dataset = Dataset.find :id => params[:id]
+ not_found_error "Dataset with id: #{params[:id]} not found." unless dataset
+ attribs = ["compounds", "nanoparticles", "substances", "features"]
+ return "Attribute '#{params[:attribute]}' is not available. Choose one of #{attribs.join(', ')}." unless attribs.include? params[:attribute]
+ out = dataset.send("#{params[:attribute]}")
+ return out.to_json
+end
diff --git a/lib/feature.rb b/lib/feature.rb
new file mode 100644
index 0000000..06a5b37
--- /dev/null
+++ b/lib/feature.rb
@@ -0,0 +1,29 @@
+# Get all Features
+get "/feature/?" do
+ features = Feature.all
+ case @accept
+ when "text/uri-list"
+ uri_list = features.collect{|feature| uri("/feature/#{feature.id}")}
+ return uri_list.join("\n") + "\n"
+ when "application/json"
+ features = JSON.parse features.to_json
+ list = []
+ features.each{|f| list << uri("/feature/#{f["_id"]["$oid"]}")}
+ return list.to_json
+ else
+ bad_request_error "Mime type #{@accept} is not supported."
+ end
+end
+
+# Get a feature
+get "/feature/:id/?" do
+ case @accept
+ when "application/json"
+ feature = Feature.find :id => params[:id]
+ not_found_error "Feature with id: #{params[:id]} not found." unless feature
+ feature[:URI] = uri("/feature/#{feature.id}")
+ return feature.to_json
+ else
+ bad_request_error "Mime type #{@accept} is not supported."
+ end
+end
diff --git a/lib/lazar-rest.rb b/lib/lazar-rest.rb
new file mode 100644
index 0000000..255c52f
--- /dev/null
+++ b/lib/lazar-rest.rb
@@ -0,0 +1,69 @@
+require "sinatra"
+require "sinatra/reloader"
+require 'sinatra/cross_origin'
+
+configure do
+ $logger = Logger.new(STDOUT)
+ enable :reloader #if development?
+ enable :cross_origin
+ disable :show_exceptions
+ disable :raise_errors
+end
+
+#set :protection, :except => :frame_options
+
+# Environment setup from unicorn -E param
+ENV["LAZAR_ENV"] = ENV["RACK_ENV"]
+require "../lazar/lib/lazar.rb"
+require "../qsar-report/lib/qsar-report.rb"
+=begin
+if ENV["LAZAR_ENV"] == "development"
+ require "../lazar/lib/lazar.rb"
+ require "../qsar-report/lib/qsar-report.rb"
+else
+ require "lazar"
+ require "qsar-report"
+end
+=end
+
+include OpenTox
+
+before do
+ @accept = request.env['HTTP_ACCEPT']
+ response['Content-Type'] = @accept
+end
+
+not_found do
+ 400
+ "Path '#{request.env["REQUEST_PATH"]}' not found.\n"
+end
+
+error do
+ response['Content-Type'] = "text/plain"
+ error = request.env['sinatra.error']
+ body = error.message+"\n"
+ error.respond_to?(:http_code) ? code = error.http_code : code = 500
+ halt code, body
+end
+
+# https://github.com/britg/sinatra-cross_origin#responding-to-options
+options "*" do
+ response.headers["Allow"] = "HEAD,GET,PUT,POST,DELETE,OPTIONS"
+ response.headers["Access-Control-Allow-Headers"] = "X-Requested-With, X-HTTP-Method-Override, Content-Type, Cache-Control, Accept"
+ 200
+end
+
+[
+ "aa.rb",
+ "api.rb",
+ "compound.rb",
+ "dataset.rb",
+ "feature.rb",
+ "model.rb",
+ "nanoparticle.rb",
+ "report.rb",
+ "substance.rb",
+ "swagger.rb",
+ "validation.rb"
+].each{ |f| require_relative f }
+
diff --git a/lib/model.rb b/lib/model.rb
new file mode 100644
index 0000000..9fbd90f
--- /dev/null
+++ b/lib/model.rb
@@ -0,0 +1,38 @@
+
+# Get a list of all prediction models
+# @param [Header] Accept one of text/uri-list,
+# @return [text/uri-list] list of all prediction models
+get "/model/?" do
+ models = Model::Validation.all
+ case @accept
+ when "text/uri-list"
+ uri_list = models.collect{|model| uri("/model/#{model.id}")}
+ return uri_list.join("\n") + "\n"
+ when "application/json"
+ models = JSON.parse models.to_json
+ list = []
+ models.each{|m| list << uri("/model/#{m["_id"]["$oid"]}")}
+ return list.to_json
+ else
+ bad_request_error "Mime type #{@accept} is not supported."
+ end
+end
+
+get "/model/:id/?" do
+ model = Model::Validation.find params[:id]
+ not_found_error "Model with id: #{params[:id]} not found." unless model
+ return model.to_json
+end
+
+
+post "/model/:id/?" do
+ identifier = params[:identifier].split(",")
+ compounds = identifier.collect{ |i| Compound.from_smiles i.strip }
+ model = Model::Validation.find params[:id]
+ batch = {}
+ compounds.each do |compound|
+ prediction = model.predict(compound)
+ batch[compound] = {:id => compound.id, :inchi => compound.inchi, :smiles => compound.smiles, :model => model, :prediction => prediction}
+ end
+ return batch.to_json
+end
diff --git a/lib/nanoparticle.rb b/lib/nanoparticle.rb
new file mode 100644
index 0000000..332493d
--- /dev/null
+++ b/lib/nanoparticle.rb
@@ -0,0 +1,30 @@
+# Get all Nanoparticles
+get "/nanoparticle/?" do
+ nanoparticles = Nanoparticle.all
+ case @accept
+ when "text/uri-list"
+ uri_list = nanoparticles.collect{|nanoparticle| uri("/nanoparticle/#{nanoparticle.id}")}
+ return uri_list.join("\n") + "\n"
+ when "application/json"
+ nanoparticles = JSON.parse nanoparticles.to_json
+ nanoparticles.each_index do |idx|
+ nanoparticles[idx][:URI] = uri("/nanoparticle/#{nanoparticles[idx]["_id"]["$oid"]}")
+ end
+ return nanoparticles.to_json
+ else
+ bad_request_error "Mime type #{@accept} is not supported."
+ end
+end
+
+# Get a nanoparticle
+get "/nanoparticle/:id/?" do
+ case @accept
+ when "application/json"
+ nanoparticle = Nanoparticle.find :id => params[:id]
+ not_found_error "Nanoparticle with id: #{params[:id]} not found." unless nanoparticle
+ nanoparticle[:URI] = uri("/nanoparticle/#{nanoparticle.id}")
+ return nanoparticle.to_json
+ else
+ bad_request_error "Mime type #{@accept} is not supported."
+ end
+end
diff --git a/lib/report.rb b/lib/report.rb
new file mode 100644
index 0000000..f576106
--- /dev/null
+++ b/lib/report.rb
@@ -0,0 +1,208 @@
+# Get a list of all possible reports to prediction models
+# @param [Header] Accept one of text/uri-list,
+# @return [text/uri-list] list of all prediction models
+get "/report/?" do
+ models = Model::Validation.all
+ case @accept
+ when "text/uri-list"
+ uri_list = models.collect{|model| uri("/report/#{model.model_id}")}
+ return uri_list.join("\n") + "\n"
+ when "application/json"
+ models = JSON.parse models.to_json
+ list = []
+ models.each{|m| list << uri("/report/#{m["model_id"]["$oid"]}")}
+ return list.to_json
+ else
+ bad_request_error "Mime type #{@accept} is not supported."
+ end
+end
+
+get "/report/:id/?" do
+ case @accept
+ when "application/xml"
+ model = Model::Lazar.find params[:id]
+ not_found_error "Model with id: #{params[:id]} not found." unless model
+ prediction_model = Model::Validation.find_by :model_id => params[:id]
+ validation_template = File.join(File.dirname(__FILE__),"../views/model_details.haml")
+
+ if File.directory?("#{File.dirname(__FILE__)}/../../lazar")
+ lazar_commit = `cd #{File.dirname(__FILE__)}/../../lazar; git rev-parse HEAD`.strip
+ lazar_commit = "https://github.com/opentox/lazar/tree/#{lazar_commit}"
+ else
+ lazar_commit = "https://github.com/opentox/lazar/releases/tag/v#{Gem.loaded_specs["lazar"].version}"
+ end
+
+ report = OpenTox::QMRFReport.new
+
+ # QSAR Identifier Title 1.1
+ report.value "QSAR_title", "Lazar model for #{prediction_model.species} #{prediction_model.endpoint}"
+
+ # Software coding the model 1.3
+ report.change_catalog :software_catalog, :firstsoftware, {:name => "lazar", :description => "lazar Lazy Structure- Activity Relationships", :number => "1", :url => "https://lazar.in-silico.ch", :contact => "info@in-silico.ch"}
+ report.ref_catalog :QSAR_software, :software_catalog, :firstsoftware
+
+ # Date of QMRF 2.1
+ report.value "qmrf_date", "#{Time.now.strftime('%d %B %Y')}"
+
+ # QMRF author(s) and contact details 2.1
+ report.change_catalog :authors_catalog, :firstauthor, {:name => "Christoph Helma", :affiliation => "in silico toxicology gmbh", :contact => "Rastatterstr. 41, CH-4057 Basel", :email => "info@in-silico.ch", :number => "1", :url => "www.in-silico.ch"}
+ report.ref_catalog :qmrf_authors, :authors_catalog, :firstauthor
+
+ # Model developer(s) and contact details 2.5
+ report.change_catalog :authors_catalog, :modelauthor, {:name => "Christoph Helma", :affiliation => "in silico toxicology gmbh", :contact => "Rastatterstr. 41, CH-4057 Basel", :email => "info@in-silico.ch", :number => "1", :url => "www.in-silico.ch"}
+ report.ref_catalog :model_authors, :authors_catalog, :modelauthor
+
+ # Date of model development and/or publication 2.6
+ report.value "model_date", "#{Time.parse(model.created_at.to_s).strftime('%Y')}"
+
+ # Reference(s) to main scientific papers and/or software package 2.7
+ report.change_catalog :publications_catalog, :publications_catalog_1, {:title => "Maunz, Guetlein, Rautenberg, Vorgrimmler, Gebele and Helma (2013), lazar: a modular predictive toxicology framework ", :url => "http://dx.doi.org/10.3389/fphar.2013.00038"}
+ report.ref_catalog :references, :publications_catalog, :publications_catalog_1
+
+ # Reference(s) to main scientific papers and/or software package 2.7
+ report.change_catalog :publications_catalog, :publications_catalog_2, {:title => "Maunz A and Helma C (2008) Prediction of chemical toxicity with local support vector regression and activity-specific kernels. SAR & QSAR in Environmental Research 19 (5-6), 413-431", :url => "http://dx.doi.org/10.1080/10629360802358430"}
+ report.ref_catalog :references, :publications_catalog, :publications_catalog_2
+
+ # Species 3.1
+ report.value "model_species", prediction_model.species
+
+ # Endpoint 3.2
+ report.change_catalog :endpoints_catalog, :endpoints_catalog_1, {:name => prediction_model.endpoint, :group => ""}
+ report.ref_catalog :model_endpoint, :endpoints_catalog, :endpoints_catalog_1
+
+ # Endpoint Units 3.4
+ report.value "endpoint_units", "#{prediction_model.unit}"
+
+ model_type = model.class.to_s.gsub('OpenTox::Model::Lazar','')
+
+ # Type of model 4.1
+ report.value "algorithm_type", "#{model_type}"
+
+ # Explicit algorithm 4.2
+ report.change_catalog :algorithms_catalog, :algorithms_catalog_1, {:definition => "see Helma 2016 and lazar.in-silico.ch, submitted version: #{lazar_commit}", :description => "Neighbor algorithm: #{model.algorithms["similarity"]["method"].gsub('_',' ').titleize}#{(model.algorithms["similarity"][:min] ? ' with similarity > ' + model.algorithms["similarity"][:min].to_s : '')}"}
+ report.ref_catalog :algorithm_explicit, :algorithms_catalog, :algorithms_catalog_1
+ report.change_catalog :algorithms_catalog, :algorithms_catalog_3, {:definition => "see Helma 2016 and lazar.in-silico.ch, submitted version: #{lazar_commit}", :description => "modified k-nearest neighbor #{model_type}"}
+ report.ref_catalog :algorithm_explicit, :algorithms_catalog, :algorithms_catalog_3
+ if model.algorithms["prediction"]
+ pred_algorithm_params = (model.algorithms["prediction"][:method] == "rf" ? "random forest" : model.algorithms["prediction"][:method])
+ end
+ report.change_catalog :algorithms_catalog, :algorithms_catalog_2, {:definition => "see Helma 2016 and lazar.in-silico.ch, submitted version: #{lazar_commit}", :description => "Prediction algorithm: #{model.algorithms["prediction"].to_s.gsub('OpenTox::Algorithm::','').gsub('_',' ').gsub('.', ' with ')} #{(pred_algorithm_params ? pred_algorithm_params : '')}"}
+ report.ref_catalog :algorithm_explicit, :algorithms_catalog, :algorithms_catalog_2
+
+ # Descriptors in the model 4.3
+ if model.algorithms["descriptors"][:type]
+ report.change_catalog :descriptors_catalog, :descriptors_catalog_1, {:description => "", :name => "#{model.algorithms["descriptors"][:type]}", :publication_ref => "", :units => ""}
+ report.ref_catalog :algorithms_descriptors, :descriptors_catalog, :descriptors_catalog_1
+ end
+
+ # Descriptor selection 4.4
+ report.value "descriptors_selection", "#{model.algorithms["feature_selection"].gsub('_',' ')} #{model.algorithms["feature_selection"].collect{|k,v| k.to_s + ': ' + v.to_s}.join(', ')}" if model.algorithms["feature_selection"]
+
+ # Algorithm and descriptor generation 4.5
+ report.value "descriptors_generation", "exhaustive breadth first search for paths in chemical graphs (simplified MolFea algorithm)"
+
+ # Software name and version for descriptor generation 4.6
+ report.change_catalog :software_catalog, :software_catalog_2, {:name => "lazar, submitted version: #{lazar_commit}", :description => "simplified MolFea algorithm", :number => "2", :url => "https://lazar.in-silico.ch", :contact => "info@in-silico.ch"}
+ report.ref_catalog :descriptors_generation_software, :software_catalog, :software_catalog_2
+
+ # Chemicals/Descriptors ratio 4.7
+ report.value "descriptors_chemicals_ratio", "not applicable (classification based on activities of neighbors, descriptors are used for similarity calculation)"
+
+ # Description of the applicability domain of the model 5.1
+ report.value "app_domain_description", "<html><head></head><body>
+ <p>
+ The applicability domain (AD) of the training set is characterized by
+ the confidence index of a prediction (high confidence index: close to
+ the applicability domain of the training set/reliable prediction, low
+ confidence: far from the applicability domain of the
+ trainingset/unreliable prediction). The confidence index considers (i)
+ the similarity and number of neighbors and (ii) contradictory examples
+ within the neighbors. A formal definition can be found in Helma 2006.
+ </p>
+ <p>
+ The reliability of predictions decreases gradually with increasing
+ distance from the applicability domain (i.e. decreasing confidence index)
+ </p>
+ </body>
+ </html>"
+
+ # Method used to assess the applicability domain 5.2
+ report.value "app_domain_method", "see Helma 2006 and Maunz 2008"
+
+ # Software name and version for applicability domain assessment 5.3
+ report.change_catalog :software_catalog, :software_catalog_3, {:name => "lazar, submitted version: #{lazar_commit}", :description => "integrated into main lazar algorithm", :number => "3", :url => "https://lazar.in-silico.ch", :contact => "info@in-silico.ch"}
+ report.ref_catalog :app_domain_software, :software_catalog, :software_catalog_3
+
+ # Limits of applicability 5.4
+ report.value "applicability_limits", "Predictions with low confidence index, unknown substructures and neighbors that might act by different mechanisms"
+
+ # Availability of the training set 6.1
+ report.change_attributes "training_set_availability", {:answer => "Yes"}
+
+ # Available information for the training set 6.2
+ report.change_attributes "training_set_data", {:cas => "Yes", :chemname => "Yes", :formula => "Yes", :inchi => "Yes", :mol => "Yes", :smiles => "Yes"}
+
+ # Data for each descriptor variable for the training set 6.3
+ report.change_attributes "training_set_descriptors", {:answer => "No"}
+
+ # Data for the dependent variable for the training set 6.4
+ report.change_attributes "dependent_var_availability", {:answer => "All"}
+
+ # Other information about the training set 6.5
+ report.value "other_info", "#{prediction_model.source}"
+
+ # Pre-processing of data before modelling 6.6
+ report.value "preprocessing", (model.class == OpenTox::Model::LazarRegression ? "-log10 transformation" : "none")
+
+ # Robustness - Statistics obtained by leave-many-out cross-validation 6.9
+ if prediction_model.repeated_crossvalidation
+ crossvalidations = prediction_model.crossvalidations
+ out = haml File.read(validation_template), :layout=> false, :locals => {:model => prediction_model}
+ report.value "lmo", out
+ end
+
+ # Mechanistic basis of the model 8.1
+ report.value "mechanistic_basis","<html><head></head><body>
+ <p>
+ Compounds with similar structures (neighbors) are assumed to have
+ similar activities as the query compound. For the determination of
+ activity specific similarities only statistically relevant subtructures
+ (paths) are used. For this reason there is a priori no bias towards
+ specific mechanistic hypothesis.
+ </p>
+ </body>
+ </html>"
+
+ # A priori or a posteriori mechanistic interpretation 8.2
+ report.value "mechanistic_basis_comments","a posteriori for individual predictions"
+
+ # Other information about the mechanistic interpretation 8.3
+ report.value "mechanistic_basis_info","<html><head></head><body><p>Hypothesis about biochemical mechanisms can be derived from individual
+ predictions by inspecting neighbors and relevant fragments.</p>
+ <p>Neighbors are compounds that are similar in respect to a certain
+ endpoint and it is likely that compounds with high similarity act by
+ similar mechanisms as the query compound. Links at the webinterface
+ prove an easy access to additional experimental data and literature
+ citations for the neighbors and the query structure.</p>
+ <p>Activating and deactivating parts of the query compound are highlighted
+ in red and green on the webinterface. Fragments that are unknown (or too
+ infrequent for statistical evaluation are marked in yellow and
+ additional statistical information about the individual fragments can be
+ retrieved. Please note that lazar predictions are based on neighbors and
+ not on fragments. Fragments and their statistical significance are used
+ for the calculation of activity specific similarities.</p>"
+
+ # Bibliography 9.2
+ report.ref_catalog :bibliography, :publications_catalog, :publications_catalog_1
+ report.ref_catalog :bibliography, :publications_catalog, :publications_catalog_2
+ report.change_catalog :publications_catalog, :publications_catalog_3, {:title => "Helma (2006), Lazy structure-activity relationships (lazar) for the prediction of rodent carcinogenicity and Salmonella mutagenicity.", :url => "http://dx.doi.org/10.1007/s11030-005-9001-5"}
+ report.ref_catalog :bibliography, :publications_catalog, :publications_catalog_3
+
+ # output
+ response['Content-Type'] = "application/xml"
+ return report.to_xml
+ else
+ bad_request_error "Mime type #{@accept} is not supported."
+ end
+
+end
diff --git a/lib/substance.rb b/lib/substance.rb
new file mode 100644
index 0000000..fef1b7e
--- /dev/null
+++ b/lib/substance.rb
@@ -0,0 +1,30 @@
+# Get all substances
+get "/substance/?" do
+ substances = Substance.all
+ case @accept
+ when "text/uri-list"
+ uri_list = substances.collect{|substance| uri("/substance/#{substance.id}")}
+ return uri_list.join("\n") + "\n"
+ when "application/json"
+ substances = JSON.parse substances.to_json
+ substances.each_index do |idx|
+ substances[idx][:URI] = uri("/substance/#{substances[idx]["_id"]["$oid"]}")
+ end
+ return substances.to_json
+ else
+ bad_request_error "Mime type #{@accept} is not supported."
+ end
+end
+
+# Get a substance
+get "/substance/:id/?" do
+ case @accept
+ when "application/json"
+ substance = Substance.find :id => params[:id]
+ not_found_error "Substance with id: #{params[:id]} not found." unless substance
+ substance[:URI] = uri("/substance/#{substance.id}")
+ return substance.to_json
+ else
+ bad_request_error "Mime type #{@accept} is not supported."
+ end
+end
diff --git a/lib/swagger.rb b/lib/swagger.rb
new file mode 100644
index 0000000..efe1c9d
--- /dev/null
+++ b/lib/swagger.rb
@@ -0,0 +1,6 @@
+get "/" do
+ response['Content-Type'] = "text/html"
+ index_file = File.join(ENV['HOME'],"swagger-ui/dist/index.html")
+ bad_request_error "API Documentation in Swagger JSON is not implemented." unless File.exists?(index_file)
+ File.read(index_file)
+end
diff --git a/lib/validation.rb b/lib/validation.rb
new file mode 100644
index 0000000..fad8a44
--- /dev/null
+++ b/lib/validation.rb
@@ -0,0 +1,71 @@
+# All available validation types
+VALIDATION_TYPES = ["repeatedcrossvalidation", "leaveoneout", "crossvalidation", "regressioncrossvalidation"]
+
+# Get a list of ayll possible validation types
+# @param [Header] Accept one of text/uri-list, application/json
+# @return [text/uri-list] URI list of all validation types
+get "/validation/?" do
+ uri_list = VALIDATION_TYPES.collect{|validationtype| uri("/validation/#{validationtype}")}
+ case @accept
+ when "text/uri-list"
+ return uri_list.join("\n") + "\n"
+ when "application/json"
+ return uri_list.to_json
+ else
+ bad_request_error "Mime type #{@accept} is not supported."
+ end
+end
+
+# Get a list of all validations
+# @param [Header] Accept one of text/uri-list, application/json
+# @param [Path] Validationtype One of "repeatedcrossvalidation", "leaveoneout", "crossvalidation", "regressioncrossvalidation"
+# @return [text/uri-list] list of all validations of a validation type
+get "/validation/:validationtype/?" do
+ bad_request_error "There is no such validation type as: #{params[:validationtype]}" unless VALIDATION_TYPES.include? params[:validationtype]
+ case params[:validationtype]
+ when "repeatedcrossvalidation"
+ validations = Validation::RepeatedCrossValidation.all
+ when "leaveoneout"
+ validations = Validation::LeaveOneOut.all
+ when "crossvalidation"
+ validations = Validation::CrossValidation.all
+ when "regressioncrossvalidation"
+ validations = Validation::RegressionCrossValidation.all
+ end
+
+ case @accept
+ when "text/uri-list"
+ uri_list = validations.collect{|validation| uri("/validation/#{params[:validationtype]}/#{validation.id}")}
+ return uri_list.join("\n") + "\n"
+ when "application/json"
+ validations = JSON.parse validations.to_json
+ validations.each_index do |idx|
+ validations[idx][:URI] = uri("/validation/#{params[:validationtype]}/#{validations[idx]["_id"]["$oid"]}")
+ end
+ return validations.to_json
+ else
+ bad_request_error "Mime type #{@accept} is not supported."
+ end
+end
+
+# Get validation representation
+get "/validation/:validationtype/:id/?" do
+ bad_request_error "There is no such validation type as: #{params[:validationtype]}" unless VALIDATION_TYPES.include? params[:validationtype]
+ case params[:validationtype]
+ when "repeatedcrossvalidation"
+ validation = Validation::RepeatedCrossValidation.find params[:id]
+ when "leaveoneout"
+ validation = Validation::LeaveOneOut.find params[:id]
+ when "crossvalidation"
+ validation = Validation::CrossValidation.find params[:id]
+ when "regressioncrossvalidation"
+ validation = Validation::RegressionCrossValidation.find params[:id]
+ end
+
+ not_found_error "#{params[:validationtype]} with id: #{params[:id]} not found." unless validation
+ #model[:URI] = uri("/model/#{model.id}")
+ #model[:neighbor_algorithm_parameters][:feature_dataset_uri] = uri("/dataset/#{model[:neighbor_algorithm_parameters][:feature_dataset_id]}") if model[:neighbor_algorithm_parameters][:feature_dataset_id]
+ #model[:training_dataset_uri] = uri("/dataset/#{model.training_dataset_id}") if model.training_dataset_id
+ #model[:prediction_feature_uri] = uri("/dataset/#{model.prediction_feature_id}") if model.prediction_feature_id
+ return validation.to_json
+end