@igea/oac_backend 1.0.39 → 1.0.41

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@igea/oac_backend",
3
- "version": "1.0.39",
3
+ "version": "1.0.41",
4
4
  "description": "Backend service for the OAC project",
5
5
  "main": "src/index.js",
6
6
  "bin": {
@@ -116,6 +116,121 @@ router.post('/upload/vocabularies', upload.array('files'), (req, res) => {
116
116
 
117
117
  });
118
118
 
119
+ //---------------------------------------------------------------
120
+ router.get('/get-vocabolary-terms/:key', (req, res) => {
121
+ const key = req.params.key;
122
+ const rootIRI = `<http://diagnostica/vocabularies/${key}>`;
123
+
124
+ let _query = `PREFIX crm: <http://www.cidoc-crm.org/cidoc-crm/>
125
+ CONSTRUCT {
126
+ ?concept ?p ?o .
127
+ }
128
+ WHERE {
129
+ ?concept (crm:P127_has_broader_term*) ${rootIRI} .
130
+ ?concept ?p ?o .
131
+ }`;
132
+
133
+ let query = `PREFIX crm: <http://www.cidoc-crm.org/cidoc-crm/>
134
+ PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
135
+ PREFIX skos: <http://www.w3.org/2004/02/skos/core#>
136
+ PREFIX owl: <http://www.w3.org/2002/07/owl#>
137
+
138
+ CONSTRUCT {
139
+
140
+ ?concept a owl:Class ;
141
+ rdfs:subClassOf ?parent ;
142
+ skos:prefLabel ?label ;
143
+ skos:closeMatch ?mappedConcept .
144
+
145
+ }
146
+ WHERE {
147
+
148
+ # Trovo tutti i concetti del vocabolario
149
+ ?concept (crm:P127_has_broader_term*) ${rootIRI} .
150
+
151
+ # Recupero l'etichetta
152
+ OPTIONAL { ?concept rdfs:label ?label . }
153
+
154
+ # Prelevo il parent da broader term
155
+ OPTIONAL {
156
+ ?concept crm:P127_has_broader_term ?parent .
157
+ }
158
+
159
+ # Genero un mapping verso un URI esterno
160
+ BIND(
161
+ IRI(CONCAT("${rootIRI}", REPLACE(STR(?concept), "^.*[/#]", "")))
162
+ AS ?mappedConcept
163
+ )
164
+
165
+ }
166
+ ORDER BY ?label`
167
+
168
+ axios.post(fusekiUrl, `query=${encodeURIComponent(query)}`,{
169
+ headers: {
170
+ 'Accept': `text/turtle`,
171
+ 'Content-Type': 'application/x-www-form-urlencoded'
172
+ },
173
+ responseType: 'stream'
174
+ }).then(response => {
175
+ res.setHeader('Content-Type', response.headers['content-type']);
176
+ response.data.pipe(res);
177
+ }).catch(err => {
178
+ res.status(500).json({
179
+ success: false,
180
+ data: null,
181
+ message: `Error: ${err}`
182
+ });
183
+ });
184
+ })
185
+ //---------------------------------------------------------------
186
+
187
+ /**
188
+ PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
189
+
190
+ SELECT ?obj
191
+ WHERE {
192
+ ?obj rdf:type <http://www.cidoc-crm.org/cidoc-crm/E55_Type> .
193
+ }
194
+ ORDER BY ?obj
195
+ LIMIT 10
196
+ OFFSET 50
197
+ */
198
+ //---------------------------------------------------------------
199
+ router.post('/search/by-prefix', (req, res) => {
200
+ const query = Fuseki.getQuerySearchByPrefix(
201
+ req.body.prefix || "",
202
+ parseInt(req.body.limit) || 50,
203
+ parseInt(req.body.offset) || 0
204
+ );
205
+
206
+ axios.post(fusekiUrl, `query=${encodeURIComponent(query)}`, {
207
+ headers: {
208
+ 'Content-Type': 'application/x-www-form-urlencoded',
209
+ 'Accept': 'application/sparql-results+json'
210
+ }
211
+ }).then(response => {
212
+ const bindings = response.data.results.bindings;
213
+ let results = []
214
+ bindings.forEach(result => {
215
+ results.push({
216
+ instance: result.instance.value,
217
+ label: result.label.value,
218
+ });
219
+ });
220
+ res.json({
221
+ success: true,
222
+ data: results,
223
+ message: null
224
+ });
225
+ }).catch(err => {
226
+ res.status(500).json({
227
+ success: false,
228
+ data: null,
229
+ message: `Error: ${err}`
230
+ });
231
+ });
232
+
233
+ });
119
234
  //---------------------------------------------------------------
120
235
  router.get('/count/entities', (req, res) => {
121
236
  const query = `
@@ -154,7 +269,6 @@ router.get('/count/entities', (req, res) => {
154
269
  message: `Error: ${err}`
155
270
  });
156
271
  });
157
-
158
272
  });
159
273
 
160
274
  router.get('/export/:format/:entity/:id', (req, res) => {
@@ -1,11 +1,11 @@
1
1
  const express = require('express');
2
2
  const router = express.Router();
3
3
  const path = require('path');
4
+ const fs = require('fs');
4
5
  const ONTO_FOLDER = path.join(__dirname, '..', 'ontology');
5
6
  const Converter = require('../models/converter');
6
7
  const tmp = require('tmp');
7
8
 
8
-
9
9
  router.get('/schema/:format', (req, res) => {
10
10
  console.log(`Requesting SHACL schema in format: ${req.params.format}`);
11
11
  let format = req.params.format || 'ttl';
@@ -35,7 +35,20 @@ router.get('/schema/:format', (req, res) => {
35
35
  });
36
36
  return;
37
37
  }
38
- res.sendFile(path.join(ONTO_FOLDER, filePath), (err) => {
38
+
39
+ let fileContent = fs.readFileSync(path.join(ONTO_FOLDER, filePath), 'utf8');
40
+ let protocol = process.env.OAC_EXPOSED_PROTOCOL || 'http';
41
+ let host = process.env.OAC_EXPOSED_HOST || '127.0.0.1';
42
+ if(host=="localhost") host="127.0.0.1";
43
+ let port = process.env.OAC_EXPOSED_PORT || '4000';
44
+ fileContent = fileContent.replace(/OAC_EXPOSED_PROTOCOL/g, protocol);
45
+ fileContent = fileContent.replace(/OAC_EXPOSED_HOST/g, host);
46
+ fileContent = fileContent.replace(/OAC_EXPOSED_PORT/g, port);
47
+
48
+ const tempFile = tmp.fileSync({ postfix: filePath });
49
+ fs.writeFileSync(tempFile.name, fileContent);
50
+
51
+ res.sendFile(tempFile.name, (err) => {
39
52
  if (err) {
40
53
  res.status(500).json({
41
54
  success: false,
@@ -97,6 +110,7 @@ router.get('/schema-temp', (req, res) => {
97
110
  });
98
111
 
99
112
  router.post('/convert/:from/:to', (req, res) => {
113
+ console.log(req.headers['content-type']);
100
114
  const from = req.params.from;
101
115
  const to = req.params.to;
102
116
  console.log(`Requesting conversion from ${from} to ${to}`);
@@ -105,6 +119,8 @@ router.post('/convert/:from/:to', (req, res) => {
105
119
  conversionFunction = Converter.turtle2RdfXml
106
120
  }else if(from === 'xml' && to === 'ttl'){
107
121
  conversionFunction = Converter.rdfXml2Turtle
122
+ }else if(from === to){
123
+ conversionFunction = Converter.same
108
124
  }else{
109
125
  res.status(400).json({
110
126
  success: false,
@@ -113,13 +129,12 @@ router.post('/convert/:from/:to', (req, res) => {
113
129
  });
114
130
  return;
115
131
  }
116
-
117
132
  const inputFile = tmp.fileSync({ postfix: `.${from}` });
118
133
  const outputFile = tmp.fileSync({ postfix: `.${to}` });
119
-
120
- const content = req.body.file
121
-
122
- fs.writeFileSync(inputFile, content);
134
+
135
+ let content = req.body.file
136
+
137
+ fs.writeFileSync(inputFile.name, content);
123
138
 
124
139
  const removeFiles = function(_files){
125
140
  for(let i=0; i<_files.length; i++){
@@ -131,9 +146,12 @@ router.post('/convert/:from/:to', (req, res) => {
131
146
  }
132
147
  }
133
148
  }
134
- let files = [inputFile];
135
- conversionFunction(inputFile, outputFile).then(() => {
136
- res.sendFile(outputFile, (err) => {
149
+ let files = [inputFile.name];
150
+ conversionFunction(inputFile.name, outputFile.name).then(() => {
151
+ let dt = new Date();
152
+ let filename = `investigation-${dt.toISOString()}.${to}`;
153
+ res.setHeader('Content-Disposition', `attachment; filename="${filename}"`);
154
+ res.sendFile(outputFile.name, (err) => {
137
155
  if (err) {
138
156
  res.status(500).json({
139
157
  success: false,
@@ -142,7 +160,7 @@ router.post('/convert/:from/:to', (req, res) => {
142
160
  });
143
161
  files = [inputFile]
144
162
  }
145
- files.push(outputFile)
163
+ files.push(outputFile.name)
146
164
  removeFiles(files)
147
165
  });
148
166
  }).catch(err => {
package/src/index.js CHANGED
@@ -23,6 +23,7 @@ const app = express();
23
23
  app.use(cookieParser());
24
24
  app.use(express.json());
25
25
  app.use(jwtLib.middleware);
26
+ app.use(express.urlencoded({ extended: true }))
26
27
 
27
28
  let newPort = null
28
29
 
@@ -5,6 +5,18 @@ const { exec } = require('child_process');
5
5
 
6
6
  class Converter {
7
7
 
8
+ static async same(inPath, outPath) {
9
+ return new Promise((resolve, reject) => {
10
+ fs.copyFile(inPath, outPath, (err) => {
11
+ if (err) {
12
+ console.error(`Error during copying file: ${err.message}`);
13
+ reject(err);
14
+ }else
15
+ resolve();
16
+ });
17
+ })
18
+ }
19
+
8
20
  static async turtle2RdfXml(inTurtlePath, outRdfXmlPath) {
9
21
  return new Promise((resolve, reject) => {
10
22
  const command = `rapper -i turtle -o rdfxml "${inTurtlePath}" > "${outRdfXmlPath}"`;
@@ -84,6 +84,28 @@ class Fuseki {
84
84
  }`;
85
85
  }
86
86
 
87
+ static getQuerySearchByPrefix(prefix, limit, offset){
88
+ limit = limit || 50;
89
+ offset = offset || 0;
90
+ if(limit < 1) limit = 50;
91
+ return `
92
+ PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
93
+ SELECT DISTINCT ?instance ?label
94
+ WHERE {
95
+ # tutte le istanze con qualsiasi proprietà
96
+ ?instance ?p ?o .
97
+ # filtro per IRI che inizia con il prefisso specifico
98
+ FILTER(STRSTARTS(STR(?instance), "${prefix}"))
99
+ # filtro per IRI che termina con UUID
100
+ #FILTER(REGEX(STR(?instance), "[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$"))
101
+ # label opzionale
102
+ OPTIONAL { ?instance rdfs:label ?label . }
103
+ }
104
+ ORDER BY ?label
105
+ LIMIT ${limit}
106
+ OFFSET ${offset}`
107
+ }
108
+
87
109
  }
88
110
 
89
111
  module.exports = Fuseki;
@@ -3,6 +3,8 @@
3
3
  @prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
4
4
  @prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
5
5
  @prefix crm: <http://www.cidoc-crm.org/cidoc-crm/> .
6
+ @prefix owl: <http://www.w3.org/2002/07/owl#> .
7
+ @prefix dcterms: <http://purl.org/dc/terms/> .
6
8
 
7
9
  ex:E7ActivityShape
8
10
  a sh:NodeShape ;
@@ -57,7 +59,8 @@ ex:E42IdentifierShape
57
59
  sh:path ex:P48_has_preferred_identifier ;
58
60
  sh:datatype xsd:string ;
59
61
  sh:name "ID" ;
60
- sh:defaultValue "$uuid$" ;
62
+ sh:nodeKind sh:IRI;
63
+ sh:description "http://diagnostica/indagine/$UUID$" ;
61
64
  sh:maxCount 1 ;
62
65
  sh:minCount 1 ;
63
66
  ] .
@@ -66,24 +69,14 @@ ex:E55Type01Shape
66
69
  a sh:NodeShape ;
67
70
  sh:targetClass crm:E55_Type ;
68
71
  sh:property [
69
- sh:path ex:P2hastype1 ;
70
- #sh:class ex:E55Type01 ;
71
- #sh:in ( ex:TipoIndagineA ex:TipoIndagineB ) ;
72
- sh:in ( "Tipo indagine A" "Tipo indagine B" ) ;
73
- #owl:imports
72
+ sh:class owl:Class ;
73
+ sh:path crm:P127_has_broader_term ;
74
+ owl:imports <OAC_EXPOSED_PROTOCOL://OAC_EXPOSED_HOST:OAC_EXPOSED_PORT/backend/fuseki/get-vocabolary-terms/fase-di-analisi> ;
74
75
  sh:name "Tipo" ;
75
76
  sh:maxCount 1 ;
76
77
  sh:minCount 1 ;
77
78
  ] .
78
79
 
79
- # Vocabolario E55Type01 (Tipo indagine)
80
- #ex:TipoIndagineA
81
- # a crm:E55_Type ;
82
- # rdfs:label "Tipo indagine A" .
83
- #ex:TipoIndagineB
84
- # a crm:E55_Type ;
85
- # rdfs:label "Tipo indagine B" .
86
-
87
80
  ex:I12AdoptedBeliefShape
88
81
  a sh:NodeShape ;
89
82
  sh:targetClass crm:I12_Adopted_Belief ;
@@ -99,13 +92,18 @@ ex:E55Type02Shape
99
92
  a sh:NodeShape ;
100
93
  sh:targetClass crm:E55_Type ;
101
94
  sh:property [
102
- sh:path ex:P2hastype2 ;
103
- #sh:class ex:E55Type02 ;
104
- #sh:in ( ex:TipoQuesitoDiagnostico1 ex:TipoQuesitoDiagnostico2 ex:TipoQuesitoDiagnostico3 ) ;
105
- sh:in ( "Tipo quesito diagnistico 1" "Tipo quesito diagnistico 2" "Tipo quesito diagnistico 3" ) ;
106
95
  sh:name "Tipo" ;
107
96
  sh:maxCount 1 ;
108
97
  sh:minCount 1 ;
98
+ #sh:class crm:E55_Type ;
99
+ sh:class owl:Class ;
100
+ sh:path crm:P127_has_broader_term ;
101
+ owl:imports <OAC_EXPOSED_PROTOCOL://OAC_EXPOSED_HOST:OAC_EXPOSED_PORT/backend/fuseki/get-vocabolary-terms/quesito-diagnostico> ;
102
+
103
+ #sh:class owl:Class ;
104
+ #sh:path dcterms:subject ;
105
+ #owl:imports <https://raw.githubusercontent.com/tibonto/DFG-Fachsystematik-Ontology/refs/heads/main/dfgfo.ttl> ;
106
+
109
107
  ] ;
110
108
  sh:property [
111
109
  sh:path crm:P3_has_note ;
@@ -114,25 +112,20 @@ ex:E55Type02Shape
114
112
  sh:maxCount 1 ;
115
113
  ] .
116
114
 
117
- # Vocabolario E55Type02 (Tipo quesito diagnostico)
118
- #ex:TipoQuesitoDiagnostico1
119
- # a crm:E55_Type ;
120
- # rdfs:label "Tipo quesito diagnistico 1" .
121
- #ex:TipoQuesitoDiagnostico2
122
- # a crm:E55_Type ;
123
- # rdfs:label "Tipo quesito diagnistico 2" .
124
- #ex:TipoQuesitoDiagnostico3
125
- # a crm:E55_Type ;
126
- # rdfs:label "Tipo quesito diagnistico 3" .
127
-
128
115
  ex:E29ActorShape
129
116
  a sh:NodeShape ;
130
117
  sh:targetClass crm:E29_Actor ;
131
118
  sh:property [
132
119
  sh:path ex:ente_richiedente ;
133
120
  sh:datatype xsd:string ;
134
- sh:name "Ente richiedente" ;
135
- sh:maxCount 1 ;
121
+
122
+ #sh:name "Ente richiedente" ;
123
+ #sh:maxCount 1 ;
124
+
125
+ sh:name "ID" ;
126
+ sh:nodeKind sh:IRI;
127
+ sh:description "http://diagnostica/actor/$UUID$" ;
128
+
136
129
  ] ;
137
130
  sh:property [
138
131
  sh:path ex:schedatore ;
@@ -141,22 +134,3 @@ ex:E29ActorShape
141
134
  sh:maxCount 1 ;
142
135
  sh:minCount 1 ;
143
136
  ] .
144
-
145
- #Vocabolario E55Type03a (con unico termine "Ente_richiedente") ???
146
- #Vocabolario E55Type03b (con unico termine "Ente_schedatore") ???
147
- #ex:TipoAttore1
148
- # a crm:E55_Type ;
149
- # rdfs:label "Ente richiedente" .
150
- #ex:TipoAttore2
151
- # a crm:E55_Type ;
152
- # rdfs:label "Schedatore" .
153
-
154
- #ex:E55Type03Shape
155
- # a sh:NodeShape ;
156
- # sh:targetClass crm:E55_Type ;
157
- # sh:property [
158
- # sh:path crm:P1_is_defined_by ;
159
- # sh:node ex:E41AppellationShape ;
160
- # sh:name "Attore" ;
161
- # sh:maxCount 1 ;
162
- # ] .