jskos-server 2.4.0
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/.dockerignore +20 -0
- package/.editorconfig +9 -0
- package/.github/workflows/docker.yml +59 -0
- package/.github/workflows/gh-pages.yml +23 -0
- package/.github/workflows/gh-release.yml +19 -0
- package/.github/workflows/test.yml +39 -0
- package/.husky/pre-commit +1 -0
- package/CHANGELOG.md +18 -0
- package/LICENSE +21 -0
- package/README.md +2710 -0
- package/bin/extra.js +81 -0
- package/bin/import.js +438 -0
- package/bin/mongodb.js +21 -0
- package/bin/reset.js +257 -0
- package/bin/upgrade.js +34 -0
- package/config/config.default.json +88 -0
- package/config/config.schema.json +877 -0
- package/config/config.test.json +107 -0
- package/config/index.js +77 -0
- package/config/setup.js +212 -0
- package/depdendencies.png +0 -0
- package/docker/.env +1 -0
- package/docker/Dockerfile +20 -0
- package/docker/README.md +175 -0
- package/docker/docker-compose.yml +29 -0
- package/docker/docker-entrypoint.sh +8 -0
- package/docker/mongo-initdb.d/mongo_setup.sh +22 -0
- package/ecosystem.example.json +7 -0
- package/errors/index.js +94 -0
- package/eslint.config.js +17 -0
- package/index.js +10 -0
- package/models/annotations.js +13 -0
- package/models/concepts.js +12 -0
- package/models/concordances.js +12 -0
- package/models/index.js +33 -0
- package/models/mappings.js +20 -0
- package/models/meta.js +21 -0
- package/models/registries.js +12 -0
- package/models/schemes.js +12 -0
- package/package.json +91 -0
- package/routes/annotations.js +83 -0
- package/routes/common.js +86 -0
- package/routes/concepts.js +64 -0
- package/routes/concordances.js +86 -0
- package/routes/data.js +19 -0
- package/routes/mappings.js +108 -0
- package/routes/registries.js +24 -0
- package/routes/schemes.js +72 -0
- package/routes/validate.js +37 -0
- package/server.js +190 -0
- package/services/abstract.js +328 -0
- package/services/annotations.js +237 -0
- package/services/concepts.js +459 -0
- package/services/concordances.js +264 -0
- package/services/data.js +30 -0
- package/services/index.js +34 -0
- package/services/mappings.js +978 -0
- package/services/registries.js +319 -0
- package/services/schemes.js +318 -0
- package/services/validate.js +39 -0
- package/status.schema.json +145 -0
- package/test/abstract-service.js +36 -0
- package/test/annotations/annotation.json +13 -0
- package/test/api.js +2481 -0
- package/test/chai.js +14 -0
- package/test/changes.js +179 -0
- package/test/concepts/conceptNoFileEnding +4 -0
- package/test/concepts/concepts-ddc-6-60-61-62.json +123 -0
- package/test/concordances/concordances.ndjson +2 -0
- package/test/config.js +26 -0
- package/test/configs/complex-config.json +90 -0
- package/test/configs/empty-object.json +1 -0
- package/test/configs/fail-array.json +1 -0
- package/test/configs/fail-empty.json +0 -0
- package/test/configs/fail-mapping-only-props1.json +5 -0
- package/test/configs/fail-mapping-only-props2.json +5 -0
- package/test/configs/fail-mapping-only-props3.json +5 -0
- package/test/configs/fail-mapping-only-props4.json +5 -0
- package/test/configs/fail-nonexisting-prop.json +3 -0
- package/test/configs/fail-port-string.json +3 -0
- package/test/configs/fail-registry-types.json +16 -0
- package/test/configs/registry-types.json +16 -0
- package/test/data-write.js +784 -0
- package/test/eslint.js +22 -0
- package/test/import-reset.js +287 -0
- package/test/infer-mappings.js +340 -0
- package/test/ipcheck.js +287 -0
- package/test/mappings/README.md +1 -0
- package/test/mappings/ddc-gnd-1.mapping.json +33 -0
- package/test/mappings/ddc-gnd-2.mapping.json +67 -0
- package/test/mappings/mapping-ddc-gnd-noScheme.json +145 -0
- package/test/mappings/mapping-ddc-gnd.json +175 -0
- package/test/mappings/mappings-ddc.json +214 -0
- package/test/registries/registries.ndjson +2 -0
- package/test/services.js +557 -0
- package/test/terminologies/terminologies.json +94 -0
- package/test/test-utils.js +182 -0
- package/test/utils.js +425 -0
- package/test/validate.js +226 -0
- package/utils/adjust.js +206 -0
- package/utils/auth.js +154 -0
- package/utils/changes.js +88 -0
- package/utils/db.js +106 -0
- package/utils/ipcheck.js +76 -0
- package/utils/middleware.js +636 -0
- package/utils/searchHelper.js +153 -0
- package/utils/status.js +77 -0
- package/utils/users.js +7 -0
- package/utils/utils.js +114 -0
- package/utils/uuid.js +6 -0
- package/utils/version.js +324 -0
- package/views/base.ejs +172 -0
|
@@ -0,0 +1,784 @@
|
|
|
1
|
+
import chai from "./chai.js"
|
|
2
|
+
|
|
3
|
+
import * as server from "../server.js"
|
|
4
|
+
import assert from "node:assert"
|
|
5
|
+
import { assertMongoDB, setupInMemoryMongo, createCollectionsAndIndexes, teardownInMemoryMongo } from "./test-utils.js"
|
|
6
|
+
|
|
7
|
+
const schemes = [
|
|
8
|
+
{
|
|
9
|
+
uri: "urn:test:scheme1",
|
|
10
|
+
notation: ["scheme1"],
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
uri: "urn:test:scheme2",
|
|
14
|
+
prefLabel: {
|
|
15
|
+
fr: "somelabel",
|
|
16
|
+
},
|
|
17
|
+
altLabel: {
|
|
18
|
+
de: [
|
|
19
|
+
"an altLabel",
|
|
20
|
+
],
|
|
21
|
+
},
|
|
22
|
+
notation: ["scheme2"],
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
uri: "urn:test:scheme3",
|
|
26
|
+
definition: {
|
|
27
|
+
en: [
|
|
28
|
+
"this contains somelabel but shouldn't be found when leaving off the some",
|
|
29
|
+
],
|
|
30
|
+
},
|
|
31
|
+
notation: ["scheme3"],
|
|
32
|
+
},
|
|
33
|
+
]
|
|
34
|
+
|
|
35
|
+
describe("Data Writing features", () => {
|
|
36
|
+
before(async () => {
|
|
37
|
+
const mongoUri = await setupInMemoryMongo({ replSet: false })
|
|
38
|
+
process.env.MONGO_URI = mongoUri
|
|
39
|
+
await createCollectionsAndIndexes()
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
after(async () => {
|
|
43
|
+
// close server if you started one
|
|
44
|
+
await teardownInMemoryMongo()
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
// 🔌 Sanity‐check that mongoose really is connected
|
|
48
|
+
assertMongoDB()
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
describe("/voc write access", () => {
|
|
52
|
+
|
|
53
|
+
it("should POST a single scheme", done => {
|
|
54
|
+
chai.request.execute(server.app)
|
|
55
|
+
.post("/voc")
|
|
56
|
+
.send(schemes[0])
|
|
57
|
+
.end((error, res) => {
|
|
58
|
+
assert.equal(error, null)
|
|
59
|
+
res.should.have.status(201)
|
|
60
|
+
res.body.should.be.an("object")
|
|
61
|
+
assert.equal(res.body.uri, schemes[0].uri)
|
|
62
|
+
// Should have no concepts or top concepts
|
|
63
|
+
assert.deepEqual(res.body.concepts, [])
|
|
64
|
+
assert.deepEqual(res.body.topConcepts, [])
|
|
65
|
+
// Should have created and modified properties
|
|
66
|
+
assert.ok(!!res.body.created)
|
|
67
|
+
assert.ok(!!res.body.modified)
|
|
68
|
+
done()
|
|
69
|
+
})
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
it("should POST multiple schemes", done => {
|
|
73
|
+
chai.request.execute(server.app)
|
|
74
|
+
.post("/voc")
|
|
75
|
+
.send(schemes.slice(1))
|
|
76
|
+
.end((error, res) => {
|
|
77
|
+
assert.equal(error, null)
|
|
78
|
+
res.should.have.status(201)
|
|
79
|
+
res.body.should.be.an("array")
|
|
80
|
+
assert.deepEqual(res.body.map(c => c.uri), schemes.slice(1).map(c => c.uri))
|
|
81
|
+
for (let scheme of res.body) {
|
|
82
|
+
// Should have no concepts or top concepts
|
|
83
|
+
assert.deepEqual(scheme.concepts, [])
|
|
84
|
+
assert.deepEqual(scheme.topConcepts, [])
|
|
85
|
+
}
|
|
86
|
+
done()
|
|
87
|
+
})
|
|
88
|
+
})
|
|
89
|
+
|
|
90
|
+
// TODO: Maybe move somewhere else?
|
|
91
|
+
it("should GET correct results for notation", done => {
|
|
92
|
+
chai.request.execute(server.app)
|
|
93
|
+
.get("/voc/suggest")
|
|
94
|
+
.query({
|
|
95
|
+
search: "sche",
|
|
96
|
+
})
|
|
97
|
+
.end((err, res) => {
|
|
98
|
+
res.should.have.status(200)
|
|
99
|
+
res.should.have.header("Link")
|
|
100
|
+
res.should.have.header("X-Total-Count")
|
|
101
|
+
res.body.should.be.a("array")
|
|
102
|
+
res.body.length.should.be.eql(4) // OpenSearch Suggest Format
|
|
103
|
+
res.body[0].should.be.a("string")
|
|
104
|
+
res.body[1].should.be.a("array")
|
|
105
|
+
res.body[1].length.should.be.eql(schemes.length)
|
|
106
|
+
res.body[1][0].should.be.eql("scheme1")
|
|
107
|
+
res.body[3].should.be.a("array")
|
|
108
|
+
res.body[3].length.should.be.eql(schemes.length)
|
|
109
|
+
res.body[3][0].should.be.eql("urn:test:scheme1")
|
|
110
|
+
done()
|
|
111
|
+
})
|
|
112
|
+
})
|
|
113
|
+
|
|
114
|
+
// TODO: Maybe move somewhere else?
|
|
115
|
+
it("should GET correct results for term (1)", done => {
|
|
116
|
+
chai.request.execute(server.app)
|
|
117
|
+
.get("/voc/suggest")
|
|
118
|
+
.query({
|
|
119
|
+
search: "label",
|
|
120
|
+
})
|
|
121
|
+
.end((err, res) => {
|
|
122
|
+
res.should.have.status(200)
|
|
123
|
+
res.should.have.header("Link")
|
|
124
|
+
res.should.have.header("X-Total-Count")
|
|
125
|
+
res.body.should.be.a("array")
|
|
126
|
+
res.body.length.should.be.eql(4) // OpenSearch Suggest Format
|
|
127
|
+
res.body[0].should.be.a("string")
|
|
128
|
+
res.body[1].should.be.a("array")
|
|
129
|
+
res.body[1].length.should.be.eql(1)
|
|
130
|
+
res.body[3].should.be.a("array")
|
|
131
|
+
res.body[3].length.should.be.eql(1)
|
|
132
|
+
res.body[3][0].should.be.eql("urn:test:scheme2")
|
|
133
|
+
done()
|
|
134
|
+
})
|
|
135
|
+
})
|
|
136
|
+
|
|
137
|
+
/*
|
|
138
|
+
// TODO: Maybe move somewhere else?
|
|
139
|
+
it("should GET correct results for term (2)", done => {
|
|
140
|
+
chai.request.execute(server.app)
|
|
141
|
+
.get("/voc/suggest")
|
|
142
|
+
.query({
|
|
143
|
+
search: "somelabel",
|
|
144
|
+
})
|
|
145
|
+
.end((err, res) => {
|
|
146
|
+
res.should.have.status(200)
|
|
147
|
+
res.should.have.header("Link")
|
|
148
|
+
res.should.have.header("X-Total-Count")
|
|
149
|
+
res.body.should.be.a("array")
|
|
150
|
+
res.body.length.should.be.eql(4) // OpenSearch Suggest Format
|
|
151
|
+
res.body[0].should.be.a("string")
|
|
152
|
+
res.body[1].should.be.a("array")
|
|
153
|
+
res.body[1].length.should.be.eql(2)
|
|
154
|
+
res.body[3].should.be.a("array")
|
|
155
|
+
res.body[3].length.should.be.eql(2)
|
|
156
|
+
res.body[3][0].should.be.eql("urn:test:scheme2")
|
|
157
|
+
res.body[3][1].should.be.eql("urn:test:scheme3")
|
|
158
|
+
done()
|
|
159
|
+
})
|
|
160
|
+
})
|
|
161
|
+
|
|
162
|
+
it("should not POST an invalid scheme (1 - invalid prefLabel)", done => {
|
|
163
|
+
chai.request.execute(server.app)
|
|
164
|
+
.post("/voc")
|
|
165
|
+
.send({
|
|
166
|
+
uri: "uri:test",
|
|
167
|
+
prefLabel: "test",
|
|
168
|
+
})
|
|
169
|
+
.end((error, res) => {
|
|
170
|
+
assert.equal(error, null)
|
|
171
|
+
res.should.have.status(422)
|
|
172
|
+
res.body.should.be.an("object")
|
|
173
|
+
assert.equal(res.body.error, "InvalidBodyError")
|
|
174
|
+
done()
|
|
175
|
+
})
|
|
176
|
+
})
|
|
177
|
+
|
|
178
|
+
it("should not POST an invalid scheme (2 - missing URI)", done => {
|
|
179
|
+
chai.request.execute(server.app)
|
|
180
|
+
.post("/voc")
|
|
181
|
+
.send({
|
|
182
|
+
prefLabel: { en: "test" },
|
|
183
|
+
})
|
|
184
|
+
.end((error, res) => {
|
|
185
|
+
assert.equal(error, null)
|
|
186
|
+
res.should.have.status(422)
|
|
187
|
+
res.body.should.be.an("object")
|
|
188
|
+
assert.equal(res.body.error, "InvalidBodyError")
|
|
189
|
+
done()
|
|
190
|
+
})
|
|
191
|
+
})
|
|
192
|
+
|
|
193
|
+
it("should not POST a scheme that already exists", done => {
|
|
194
|
+
chai.request.execute(server.app)
|
|
195
|
+
.post("/voc")
|
|
196
|
+
.send(schemes[0])
|
|
197
|
+
.end((error, res) => {
|
|
198
|
+
assert.equal(error, null)
|
|
199
|
+
res.should.have.status(422)
|
|
200
|
+
res.body.should.be.an("object")
|
|
201
|
+
assert.equal(res.body.error, "DuplicateEntityError")
|
|
202
|
+
done()
|
|
203
|
+
})
|
|
204
|
+
})
|
|
205
|
+
|
|
206
|
+
it("should bulk POST schemes and ignore errors", done => {
|
|
207
|
+
const bulkSchemes = [
|
|
208
|
+
{
|
|
209
|
+
uri: "urn:test:scheme-bulk1",
|
|
210
|
+
},
|
|
211
|
+
{
|
|
212
|
+
uri: "urn:test:scheme-bulk2",
|
|
213
|
+
},
|
|
214
|
+
{
|
|
215
|
+
uri: "test-scheme-bulk-invalid",
|
|
216
|
+
},
|
|
217
|
+
{
|
|
218
|
+
uri: schemes[0].uri,
|
|
219
|
+
prefLabel: { en: "Bulk updated scheme" },
|
|
220
|
+
},
|
|
221
|
+
]
|
|
222
|
+
chai.request.execute(server.app)
|
|
223
|
+
.post("/voc")
|
|
224
|
+
.query({
|
|
225
|
+
bulk: true,
|
|
226
|
+
})
|
|
227
|
+
.send(bulkSchemes)
|
|
228
|
+
.end((error, res) => {
|
|
229
|
+
assert.equal(error, null)
|
|
230
|
+
res.should.have.status(201)
|
|
231
|
+
res.body.should.be.an("array")
|
|
232
|
+
assert.equal(res.body.length, 3) // one invalid scheme removed
|
|
233
|
+
// Check updated scheme
|
|
234
|
+
chai.request.execute(server.app).get("/voc").query({ uri: schemes[0].uri }).end((error, res) => {
|
|
235
|
+
assert.equal(error, null)
|
|
236
|
+
res.should.have.status(200)
|
|
237
|
+
res.body.should.be.an("array")
|
|
238
|
+
assert.equal(res.body.length, 1)
|
|
239
|
+
assert.equal(res.body[0].uri, schemes[0].uri)
|
|
240
|
+
assert.deepEqual(res.body[0].prefLabel, bulkSchemes.find(s => s.uri == schemes[0].uri).prefLabel)
|
|
241
|
+
res.body[0].concepts.should.be.an("array")
|
|
242
|
+
res.body[0].topConcepts.should.be.an("array")
|
|
243
|
+
done()
|
|
244
|
+
})
|
|
245
|
+
})
|
|
246
|
+
})
|
|
247
|
+
*/
|
|
248
|
+
/*
|
|
249
|
+
it("should PUT a scheme (created should be removed, modified should be updated)", async () => {
|
|
250
|
+
const patch = {
|
|
251
|
+
notation: ["A"],
|
|
252
|
+
created: "2012",
|
|
253
|
+
}
|
|
254
|
+
let scheme = schemes[0], res
|
|
255
|
+
// 1. Get current scheme from database
|
|
256
|
+
res = await chai.request.execute(server.app)
|
|
257
|
+
.get("/voc")
|
|
258
|
+
.query({
|
|
259
|
+
uri: scheme.uri,
|
|
260
|
+
})
|
|
261
|
+
assert.strictEqual(res.status, 200)
|
|
262
|
+
scheme = res.body[0]
|
|
263
|
+
assert.ok(!!scheme)
|
|
264
|
+
// 2. Make PUT request
|
|
265
|
+
res = await chai.request.execute(server.app)
|
|
266
|
+
.put("/voc")
|
|
267
|
+
.send(Object.assign({}, scheme, patch))
|
|
268
|
+
res.should.have.status(200)
|
|
269
|
+
res.body.should.be.an("object")
|
|
270
|
+
assert.deepStrictEqual(res.body.notation, patch.notation)
|
|
271
|
+
// Make sure created was NOT updated even though it was set on patch
|
|
272
|
+
assert.strictEqual(res.body.created, scheme.created)
|
|
273
|
+
assert.notStrictEqual(res.body.created, patch.created)
|
|
274
|
+
// Make sure modified was updated
|
|
275
|
+
assert.notStrictEqual(res.body.modified, scheme.modified)
|
|
276
|
+
})
|
|
277
|
+
|
|
278
|
+
it("should not PUT an invalid scheme", done => {
|
|
279
|
+
const patch = {
|
|
280
|
+
notation: "A",
|
|
281
|
+
}
|
|
282
|
+
chai.request.execute(server.app)
|
|
283
|
+
.put("/voc")
|
|
284
|
+
.send(Object.assign({}, schemes[0], patch))
|
|
285
|
+
.end((error, res) => {
|
|
286
|
+
assert.equal(error, null)
|
|
287
|
+
res.should.have.status(422)
|
|
288
|
+
res.body.should.be.an("object")
|
|
289
|
+
assert.equal(res.body.error, "InvalidBodyError")
|
|
290
|
+
done()
|
|
291
|
+
})
|
|
292
|
+
})
|
|
293
|
+
|
|
294
|
+
it("should not PUT a scheme that doesn't exist", done => {
|
|
295
|
+
chai.request.execute(server.app)
|
|
296
|
+
.put("/voc")
|
|
297
|
+
.send({
|
|
298
|
+
uri: "urn:test:scheme-that-does-not-exist",
|
|
299
|
+
notation: ["A"],
|
|
300
|
+
})
|
|
301
|
+
.end((error, res) => {
|
|
302
|
+
assert.equal(error, null)
|
|
303
|
+
res.should.have.status(404)
|
|
304
|
+
res.body.should.be.an("object")
|
|
305
|
+
assert.equal(res.body.error, "EntityNotFoundError")
|
|
306
|
+
done()
|
|
307
|
+
})
|
|
308
|
+
})
|
|
309
|
+
|
|
310
|
+
it("should DELETE a scheme", done => {
|
|
311
|
+
chai.request.execute(server.app)
|
|
312
|
+
.delete("/voc")
|
|
313
|
+
.query({
|
|
314
|
+
uri: schemes[2].uri,
|
|
315
|
+
})
|
|
316
|
+
.end((error, res) => {
|
|
317
|
+
assert.equal(error, null)
|
|
318
|
+
res.should.have.status(204)
|
|
319
|
+
done()
|
|
320
|
+
})
|
|
321
|
+
})
|
|
322
|
+
|
|
323
|
+
it("should not DELETE a scheme that doesn't exist", done => {
|
|
324
|
+
chai.request.execute(server.app)
|
|
325
|
+
.delete("/voc")
|
|
326
|
+
.query({
|
|
327
|
+
uri: "urn:test:scheme-that-does-not-exist",
|
|
328
|
+
})
|
|
329
|
+
.end((error, res) => {
|
|
330
|
+
assert.equal(error, null)
|
|
331
|
+
res.should.have.status(404)
|
|
332
|
+
res.body.should.be.an("object")
|
|
333
|
+
assert.equal(res.body.error, "EntityNotFoundError")
|
|
334
|
+
done()
|
|
335
|
+
})
|
|
336
|
+
})
|
|
337
|
+
|
|
338
|
+
})
|
|
339
|
+
|
|
340
|
+
describe("/concepts write access", () => {
|
|
341
|
+
|
|
342
|
+
const concept = {
|
|
343
|
+
uri: "urn:test:concept",
|
|
344
|
+
inScheme: [schemes[0]],
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
const concepts = [
|
|
348
|
+
{
|
|
349
|
+
uri: "urn:test:concept2",
|
|
350
|
+
topConceptOf: [schemes[1]],
|
|
351
|
+
},
|
|
352
|
+
{
|
|
353
|
+
uri: "urn:test:concept3",
|
|
354
|
+
inScheme: [schemes[0]],
|
|
355
|
+
broader: [concept],
|
|
356
|
+
},
|
|
357
|
+
]
|
|
358
|
+
|
|
359
|
+
it("should POST a concept", done => {
|
|
360
|
+
chai.request.execute(server.app)
|
|
361
|
+
.post("/concepts")
|
|
362
|
+
.send(concept)
|
|
363
|
+
.end((error, res) => {
|
|
364
|
+
res.should.have.status(201)
|
|
365
|
+
res.body.should.be.a("object")
|
|
366
|
+
assert.equal(res.body.uri, concept.uri)
|
|
367
|
+
done()
|
|
368
|
+
})
|
|
369
|
+
})
|
|
370
|
+
|
|
371
|
+
it("should have refreshed the `concepts` property of the scheme after POSTing a concept", done => {
|
|
372
|
+
chai.request.execute(server.app)
|
|
373
|
+
.get("/voc")
|
|
374
|
+
.query({
|
|
375
|
+
uri: concept.inScheme[0].uri,
|
|
376
|
+
})
|
|
377
|
+
.end((error, res) => {
|
|
378
|
+
res.should.have.status(200)
|
|
379
|
+
res.body.should.be.a("array")
|
|
380
|
+
res.body[0].should.be.a("object")
|
|
381
|
+
assert.equal(res.body[0].uri, concept.inScheme[0].uri)
|
|
382
|
+
assert.deepEqual(res.body[0].concepts, [null])
|
|
383
|
+
done()
|
|
384
|
+
})
|
|
385
|
+
})
|
|
386
|
+
|
|
387
|
+
it("should not DELETE a scheme when it currently has concepts", done => {
|
|
388
|
+
chai.request.execute(server.app)
|
|
389
|
+
.delete("/voc")
|
|
390
|
+
.query({
|
|
391
|
+
uri: concept.inScheme[0].uri,
|
|
392
|
+
})
|
|
393
|
+
.end((error, res) => {
|
|
394
|
+
assert.equal(error, null)
|
|
395
|
+
res.should.have.status(400)
|
|
396
|
+
res.body.should.be.a("object")
|
|
397
|
+
assert.equal(res.body.error, "MalformedRequestError")
|
|
398
|
+
done()
|
|
399
|
+
})
|
|
400
|
+
})
|
|
401
|
+
|
|
402
|
+
it("should POST multiple concepts", done => {
|
|
403
|
+
chai.request.execute(server.app)
|
|
404
|
+
.post("/concepts")
|
|
405
|
+
.send(concepts)
|
|
406
|
+
.end((error, res) => {
|
|
407
|
+
res.should.have.status(201)
|
|
408
|
+
res.body.should.be.an("array")
|
|
409
|
+
assert.deepEqual(res.body.map(c => c.uri), concepts.map(c => c.uri))
|
|
410
|
+
done()
|
|
411
|
+
})
|
|
412
|
+
})
|
|
413
|
+
|
|
414
|
+
it("should have refreshed the `topConcepts` property of the scheme after POSTing a top concept", done => {
|
|
415
|
+
chai.request.execute(server.app)
|
|
416
|
+
.get("/voc")
|
|
417
|
+
.query({
|
|
418
|
+
uri: concepts[0].topConceptOf[0].uri,
|
|
419
|
+
})
|
|
420
|
+
.end((error, res) => {
|
|
421
|
+
res.should.have.status(200)
|
|
422
|
+
res.body.should.be.a("array")
|
|
423
|
+
res.body[0].should.be.a("object")
|
|
424
|
+
assert.equal(res.body[0].uri, concepts[0].topConceptOf[0].uri)
|
|
425
|
+
assert.deepEqual(res.body[0].topConcepts, [null])
|
|
426
|
+
done()
|
|
427
|
+
})
|
|
428
|
+
})
|
|
429
|
+
|
|
430
|
+
it("should not POST a concept without scheme", done => {
|
|
431
|
+
chai.request.execute(server.app)
|
|
432
|
+
.post("/concepts")
|
|
433
|
+
.send({
|
|
434
|
+
uri: "urn:test:concept-without-scheme",
|
|
435
|
+
})
|
|
436
|
+
.end((error, res) => {
|
|
437
|
+
res.should.have.status(400)
|
|
438
|
+
res.body.should.be.a("object")
|
|
439
|
+
assert.equal(res.body.error, "MalformedRequestError")
|
|
440
|
+
done()
|
|
441
|
+
})
|
|
442
|
+
})
|
|
443
|
+
|
|
444
|
+
it("should POST a concept without scheme when scheme param is given, then delete it", async () => {
|
|
445
|
+
const scheme = schemes[0]
|
|
446
|
+
const concept = {
|
|
447
|
+
uri: "urn:test:concept-without-scheme",
|
|
448
|
+
}
|
|
449
|
+
let res
|
|
450
|
+
// POST concept
|
|
451
|
+
res = await chai.request.execute(server.app)
|
|
452
|
+
.post("/concepts")
|
|
453
|
+
.query({
|
|
454
|
+
scheme: scheme.uri,
|
|
455
|
+
})
|
|
456
|
+
.send(concept)
|
|
457
|
+
res.should.have.status(201)
|
|
458
|
+
res.body.should.be.a("object")
|
|
459
|
+
assert.strictEqual(res.body.uri, concept.uri)
|
|
460
|
+
assert.strictEqual(res.body.inScheme[0].uri, scheme.uri)
|
|
461
|
+
// DELETE concept
|
|
462
|
+
res = await chai.request.execute(server.app)
|
|
463
|
+
.delete("/concepts")
|
|
464
|
+
.query(concept)
|
|
465
|
+
res.should.have.status(204)
|
|
466
|
+
})
|
|
467
|
+
|
|
468
|
+
it("should not POST a concept with invalid URI", done => {
|
|
469
|
+
chai.request.execute(server.app)
|
|
470
|
+
.post("/concepts")
|
|
471
|
+
.send({
|
|
472
|
+
uri: "concept-invalid-uri",
|
|
473
|
+
inScheme: [schemes[1]],
|
|
474
|
+
})
|
|
475
|
+
.end((error, res) => {
|
|
476
|
+
res.should.have.status(422)
|
|
477
|
+
res.body.should.be.a("object")
|
|
478
|
+
assert.equal(res.body.error, "InvalidBodyError")
|
|
479
|
+
done()
|
|
480
|
+
})
|
|
481
|
+
})
|
|
482
|
+
|
|
483
|
+
it("should not POST a concept with missing URI", done => {
|
|
484
|
+
chai.request.execute(server.app)
|
|
485
|
+
.post("/concepts")
|
|
486
|
+
.send({
|
|
487
|
+
inScheme: [schemes[1]],
|
|
488
|
+
})
|
|
489
|
+
.end((error, res) => {
|
|
490
|
+
res.should.have.status(422)
|
|
491
|
+
res.body.should.be.a("object")
|
|
492
|
+
assert.equal(res.body.error, "InvalidBodyError")
|
|
493
|
+
done()
|
|
494
|
+
})
|
|
495
|
+
})
|
|
496
|
+
|
|
497
|
+
it("should not POST a concept that already exists", done => {
|
|
498
|
+
chai.request.execute(server.app)
|
|
499
|
+
.post("/concepts")
|
|
500
|
+
.send(concept)
|
|
501
|
+
.end((error, res) => {
|
|
502
|
+
assert.equal(error, null)
|
|
503
|
+
res.should.have.status(422)
|
|
504
|
+
res.body.should.be.an("object")
|
|
505
|
+
assert.equal(res.body.error, "DuplicateEntityError")
|
|
506
|
+
done()
|
|
507
|
+
})
|
|
508
|
+
})
|
|
509
|
+
|
|
510
|
+
it("should POST a single concept that already exists if bulk is set", done => {
|
|
511
|
+
chai.request.execute(server.app)
|
|
512
|
+
.post("/concepts")
|
|
513
|
+
.query({
|
|
514
|
+
bulk: true,
|
|
515
|
+
})
|
|
516
|
+
.send(concept)
|
|
517
|
+
.end((error, res) => {
|
|
518
|
+
assert.equal(error, null)
|
|
519
|
+
res.should.have.status(201)
|
|
520
|
+
res.body.should.be.an("object")
|
|
521
|
+
done()
|
|
522
|
+
})
|
|
523
|
+
})
|
|
524
|
+
|
|
525
|
+
it("should POST upsert multiple concepts", done => {
|
|
526
|
+
chai.request.execute(server.app)
|
|
527
|
+
.post("/concepts")
|
|
528
|
+
.query({
|
|
529
|
+
bulk: true,
|
|
530
|
+
})
|
|
531
|
+
.send(concepts)
|
|
532
|
+
.end((error, res) => {
|
|
533
|
+
res.should.have.status(201)
|
|
534
|
+
res.body.should.be.an("array")
|
|
535
|
+
assert.deepEqual(res.body.map(c => c.uri), concepts.map(c => c.uri))
|
|
536
|
+
assert.deepEqual(Object.keys(res.body[0]), ["uri"])
|
|
537
|
+
done()
|
|
538
|
+
})
|
|
539
|
+
})
|
|
540
|
+
|
|
541
|
+
it("should ignore POST errors when bulk is set", done => {
|
|
542
|
+
chai.request.execute(server.app)
|
|
543
|
+
.post("/concepts")
|
|
544
|
+
.query({
|
|
545
|
+
bulk: true,
|
|
546
|
+
})
|
|
547
|
+
.send([{
|
|
548
|
+
uri: "concept-invalid-uri",
|
|
549
|
+
inScheme: [schemes[1]],
|
|
550
|
+
}])
|
|
551
|
+
.end((error, res) => {
|
|
552
|
+
res.should.have.status(201)
|
|
553
|
+
res.body.should.be.an("array")
|
|
554
|
+
assert.equal(res.body.length, 0)
|
|
555
|
+
done()
|
|
556
|
+
})
|
|
557
|
+
})
|
|
558
|
+
|
|
559
|
+
it("should not POST a concept with scheme that is not in database", done => {
|
|
560
|
+
chai.request.execute(server.app)
|
|
561
|
+
.post("/concepts")
|
|
562
|
+
.send({
|
|
563
|
+
uri: "urn:test:concept-with-missing-scheme",
|
|
564
|
+
inScheme: [
|
|
565
|
+
{
|
|
566
|
+
uri: "urn:test:scheme-that-does-not-exist",
|
|
567
|
+
},
|
|
568
|
+
],
|
|
569
|
+
})
|
|
570
|
+
.end((error, res) => {
|
|
571
|
+
res.should.have.status(400)
|
|
572
|
+
res.body.should.be.a("object")
|
|
573
|
+
assert.equal(res.body.error, "MalformedRequestError")
|
|
574
|
+
done()
|
|
575
|
+
})
|
|
576
|
+
})
|
|
577
|
+
|
|
578
|
+
it("should PUT a concept", done => {
|
|
579
|
+
const patch = {
|
|
580
|
+
notation: ["A"],
|
|
581
|
+
}
|
|
582
|
+
chai.request.execute(server.app)
|
|
583
|
+
.put("/concepts")
|
|
584
|
+
.send(Object.assign({}, concept, patch))
|
|
585
|
+
.end((error, res) => {
|
|
586
|
+
assert.equal(error, null)
|
|
587
|
+
res.should.have.status(200)
|
|
588
|
+
res.body.should.be.an("object")
|
|
589
|
+
assert.deepEqual(res.body.notation, patch.notation)
|
|
590
|
+
done()
|
|
591
|
+
})
|
|
592
|
+
})
|
|
593
|
+
|
|
594
|
+
it("should not PUT an invalid concept", done => {
|
|
595
|
+
chai.request.execute(server.app)
|
|
596
|
+
.put("/concepts")
|
|
597
|
+
.send({
|
|
598
|
+
uri: "urn:test:concept2",
|
|
599
|
+
inScheme: [schemes[1]],
|
|
600
|
+
prefLabel: "should be an object",
|
|
601
|
+
})
|
|
602
|
+
.end((error, res) => {
|
|
603
|
+
res.should.have.status(422)
|
|
604
|
+
res.body.should.be.a("object")
|
|
605
|
+
assert.equal(res.body.error, "InvalidBodyError")
|
|
606
|
+
done()
|
|
607
|
+
})
|
|
608
|
+
})
|
|
609
|
+
|
|
610
|
+
it("should not PUT a concept that doesn't exist", done => {
|
|
611
|
+
chai.request.execute(server.app)
|
|
612
|
+
.put("/concepts")
|
|
613
|
+
.send({
|
|
614
|
+
uri: "urn:test:concept-that-does-not-exist",
|
|
615
|
+
inScheme: [schemes[1]],
|
|
616
|
+
prefLabel: { en: "should be an object" },
|
|
617
|
+
})
|
|
618
|
+
.end((error, res) => {
|
|
619
|
+
res.should.have.status(404)
|
|
620
|
+
res.body.should.be.a("object")
|
|
621
|
+
assert.equal(res.body.error, "EntityNotFoundError")
|
|
622
|
+
done()
|
|
623
|
+
})
|
|
624
|
+
})
|
|
625
|
+
|
|
626
|
+
it("should DELETE posted concepts", done => {
|
|
627
|
+
concepts.push(concept)
|
|
628
|
+
let count = 0
|
|
629
|
+
const maybeDone = () => {
|
|
630
|
+
count += 1
|
|
631
|
+
if (count == concepts.length) {
|
|
632
|
+
done()
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
for (let concept of concepts) {
|
|
636
|
+
chai.request.execute(server.app)
|
|
637
|
+
.delete("/concepts")
|
|
638
|
+
.query({
|
|
639
|
+
uri: concept.uri,
|
|
640
|
+
})
|
|
641
|
+
.end((err, res) => {
|
|
642
|
+
res.should.have.status(204)
|
|
643
|
+
maybeDone()
|
|
644
|
+
})
|
|
645
|
+
}
|
|
646
|
+
})
|
|
647
|
+
|
|
648
|
+
it("should have refreshed the `concepts` property of the scheme after DELETEing a concept", done => {
|
|
649
|
+
chai.request.execute(server.app)
|
|
650
|
+
.get("/voc")
|
|
651
|
+
.query({
|
|
652
|
+
uri: concept.inScheme[0].uri,
|
|
653
|
+
})
|
|
654
|
+
.end((error, res) => {
|
|
655
|
+
res.should.have.status(200)
|
|
656
|
+
res.body.should.be.a("array")
|
|
657
|
+
res.body[0].should.be.a("object")
|
|
658
|
+
assert.equal(res.body[0].uri, concept.inScheme[0].uri)
|
|
659
|
+
assert.deepEqual(res.body[0].concepts, [])
|
|
660
|
+
done()
|
|
661
|
+
})
|
|
662
|
+
})
|
|
663
|
+
|
|
664
|
+
it("should DELETE a scheme after its last concept was removed", done => {
|
|
665
|
+
chai.request.execute(server.app)
|
|
666
|
+
.delete("/voc")
|
|
667
|
+
.query({
|
|
668
|
+
uri: concept.inScheme[0].uri,
|
|
669
|
+
})
|
|
670
|
+
.end((error, res) => {
|
|
671
|
+
assert.equal(error, null)
|
|
672
|
+
res.should.have.status(204)
|
|
673
|
+
done()
|
|
674
|
+
})
|
|
675
|
+
})
|
|
676
|
+
|
|
677
|
+
it("should have refreshed the `topConcepts` property of the scheme after DELETEing a top concept", done => {
|
|
678
|
+
chai.request.execute(server.app)
|
|
679
|
+
.get("/voc")
|
|
680
|
+
.query({
|
|
681
|
+
uri: concepts[0].topConceptOf[0].uri,
|
|
682
|
+
})
|
|
683
|
+
.end((error, res) => {
|
|
684
|
+
res.should.have.status(200)
|
|
685
|
+
res.body.should.be.a("array")
|
|
686
|
+
res.body[0].should.be.a("object")
|
|
687
|
+
assert.equal(res.body[0].uri, concepts[0].topConceptOf[0].uri)
|
|
688
|
+
assert.deepEqual(res.body[0].topConcepts, [])
|
|
689
|
+
done()
|
|
690
|
+
})
|
|
691
|
+
})
|
|
692
|
+
|
|
693
|
+
it("should DELETE all concepts of a scheme", async () => {
|
|
694
|
+
const uri = concepts[0].topConceptOf[0].uri
|
|
695
|
+
let res
|
|
696
|
+
// Post concept
|
|
697
|
+
res = await chai.request.execute(server.app)
|
|
698
|
+
.post("/concepts")
|
|
699
|
+
.send(concepts[0])
|
|
700
|
+
res.should.have.status(201)
|
|
701
|
+
res.body.should.be.an("object")
|
|
702
|
+
res.body.uri.should.be.eql(concepts[0].uri)
|
|
703
|
+
// Delete from scheme
|
|
704
|
+
res = await chai.request.execute(server.app)
|
|
705
|
+
.delete("/voc/concepts")
|
|
706
|
+
.query({
|
|
707
|
+
uri,
|
|
708
|
+
})
|
|
709
|
+
res.should.have.status(204)
|
|
710
|
+
// Get from scheme
|
|
711
|
+
res = await chai.request.execute(server.app)
|
|
712
|
+
.get("/voc/concepts")
|
|
713
|
+
.query({ uri })
|
|
714
|
+
res.should.have.status(200)
|
|
715
|
+
res.body.should.be.a("array")
|
|
716
|
+
res.body.length.should.be.eql(0)
|
|
717
|
+
})
|
|
718
|
+
|
|
719
|
+
it("should not DELETE a concept that doesn't exist", done => {
|
|
720
|
+
chai.request.execute(server.app)
|
|
721
|
+
.delete("/concepts")
|
|
722
|
+
.query({
|
|
723
|
+
uri: "urn:test:concept-that-does-not-exist",
|
|
724
|
+
})
|
|
725
|
+
.end((error, res) => {
|
|
726
|
+
res.should.have.status(404)
|
|
727
|
+
res.body.should.be.a("object")
|
|
728
|
+
assert.equal(res.body.error, "EntityNotFoundError")
|
|
729
|
+
done()
|
|
730
|
+
})
|
|
731
|
+
})
|
|
732
|
+
|
|
733
|
+
it("should POST a concept, update its scheme's properties, then DELETE the concept", async () => {
|
|
734
|
+
const uri = concepts[0].topConceptOf[0].uri
|
|
735
|
+
const concept = {
|
|
736
|
+
uri: "urn:test:concept",
|
|
737
|
+
topConceptOf: [{ uri }],
|
|
738
|
+
}
|
|
739
|
+
const getScheme = async () => {
|
|
740
|
+
const res = await chai.request.execute(server.app)
|
|
741
|
+
.get("/voc")
|
|
742
|
+
.query({
|
|
743
|
+
uri,
|
|
744
|
+
})
|
|
745
|
+
assert.strictEqual(res.status, 200)
|
|
746
|
+
assert.strictEqual(res.body.length, 1)
|
|
747
|
+
return res
|
|
748
|
+
}
|
|
749
|
+
let res, scheme
|
|
750
|
+
// Get scheme before POSTing
|
|
751
|
+
res = await getScheme()
|
|
752
|
+
scheme = res.body[0]
|
|
753
|
+
assert.strictEqual(scheme.uri, uri)
|
|
754
|
+
// POST concept
|
|
755
|
+
res = await chai.request.execute(server.app)
|
|
756
|
+
.post("/concepts")
|
|
757
|
+
.send(concept)
|
|
758
|
+
assert.strictEqual(res.status, 201)
|
|
759
|
+
// Check scheme after POSTing
|
|
760
|
+
res = await getScheme()
|
|
761
|
+
// Check concepts, topConcepts, and modified properties
|
|
762
|
+
assert.notDeepStrictEqual(res.body.concepts, scheme.concepts)
|
|
763
|
+
assert.notDeepStrictEqual(res.body.topConcepts, scheme.topConcepts)
|
|
764
|
+
assert.notStrictEqual(res.body.modified, scheme.modified)
|
|
765
|
+
scheme = res.body[0]
|
|
766
|
+
// DELETE concept
|
|
767
|
+
res = await chai.request.execute(server.app)
|
|
768
|
+
.delete("/concepts")
|
|
769
|
+
.query({
|
|
770
|
+
uri: concept.uri,
|
|
771
|
+
})
|
|
772
|
+
assert.strictEqual(res.status, 204)
|
|
773
|
+
// Check scheme after DELETE
|
|
774
|
+
res = await getScheme()
|
|
775
|
+
// Check concepts, topConcepts, and modified properties
|
|
776
|
+
assert.notDeepStrictEqual(res.body.concepts, scheme.concepts)
|
|
777
|
+
assert.notDeepStrictEqual(res.body.topConcepts, scheme.topConcepts)
|
|
778
|
+
assert.notStrictEqual(res.body.modified, scheme.modified)
|
|
779
|
+
})
|
|
780
|
+
*/
|
|
781
|
+
|
|
782
|
+
})
|
|
783
|
+
|
|
784
|
+
})
|