@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 +1 -1
- package/src/controllers/fuseki.js +115 -1
- package/src/controllers/ontology.js +29 -11
- package/src/index.js +1 -0
- package/src/models/converter.js +12 -0
- package/src/models/fuseki.js +22 -0
- package/src/ontology/schema_v2.shacl.ttl +24 -50
package/package.json
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
package/src/models/converter.js
CHANGED
|
@@ -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}"`;
|
package/src/models/fuseki.js
CHANGED
|
@@ -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
|
-
|
|
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:
|
|
70
|
-
|
|
71
|
-
|
|
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
|
-
|
|
135
|
-
sh:
|
|
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
|
-
# ] .
|