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
package/bin/reset.js
ADDED
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import * as db from "../utils/db.js"
|
|
4
|
+
import yesno from "yesno"
|
|
5
|
+
import jskos from "jskos-tools"
|
|
6
|
+
import _ from "lodash"
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
import meow from "meow"
|
|
10
|
+
const cli = meow(`
|
|
11
|
+
Usage
|
|
12
|
+
$ npm run reset -- [options] [URIs]
|
|
13
|
+
|
|
14
|
+
type is required unless you want to reset the whole database.
|
|
15
|
+
|
|
16
|
+
Options
|
|
17
|
+
GNU long option Option Meaning
|
|
18
|
+
--type -t Object type to be deleted. If omitted, type will be "concepts" if -s is given, "mappings" if -c is given, all types otherwise.
|
|
19
|
+
--scheme -s Only for concepts. Deletes only concepts from a certain scheme (inScheme). (Not applicable when URIs are specified.)
|
|
20
|
+
--concordance -c Only for mappings. Deletes only mappings from a certain concordance (partOf). (Not applicable when URIs are specified.)
|
|
21
|
+
--set-api EXPERIMENTAL. Onlt for concepts. Will update the scheme's \`API\` property after deleting concepts.
|
|
22
|
+
|
|
23
|
+
Examples
|
|
24
|
+
$ npm run reset -- -t concepts -s http://uri.gbv.de/terminology/rvk/
|
|
25
|
+
`, {
|
|
26
|
+
importMeta: import.meta,
|
|
27
|
+
flags: {
|
|
28
|
+
type: {
|
|
29
|
+
type: "string",
|
|
30
|
+
shortFlag: "t",
|
|
31
|
+
default: "",
|
|
32
|
+
},
|
|
33
|
+
scheme: {
|
|
34
|
+
type: "string",
|
|
35
|
+
shortFlag: "s",
|
|
36
|
+
default: "",
|
|
37
|
+
},
|
|
38
|
+
setApi: {
|
|
39
|
+
type: "boolean",
|
|
40
|
+
default: false,
|
|
41
|
+
},
|
|
42
|
+
concordance: {
|
|
43
|
+
type: "string",
|
|
44
|
+
shortFlag: "c",
|
|
45
|
+
default: "",
|
|
46
|
+
},
|
|
47
|
+
help: {
|
|
48
|
+
type: "boolean",
|
|
49
|
+
shortFlag: "h",
|
|
50
|
+
default: false,
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
if (cli.flags.help) {
|
|
56
|
+
cli.showHelp()
|
|
57
|
+
process.exit(0)
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const log = (...args) => {
|
|
61
|
+
console.log(...args)
|
|
62
|
+
}
|
|
63
|
+
const logError = ({ message, showHelp = false, exit = false }) => {
|
|
64
|
+
console.error(` Error: ${message}`)
|
|
65
|
+
if (showHelp) {
|
|
66
|
+
cli.showHelp()
|
|
67
|
+
}
|
|
68
|
+
if (exit) {
|
|
69
|
+
db.disconnect()
|
|
70
|
+
process.exit(1)
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const uris = cli.input
|
|
75
|
+
|
|
76
|
+
// Parse type
|
|
77
|
+
let type = jskos.guessObjectType(cli.flags.type, true)
|
|
78
|
+
let typeInferred = false
|
|
79
|
+
if (cli.flags.type && !type) {
|
|
80
|
+
logError({
|
|
81
|
+
message: `Invalid <type> argument: ${cli.flags.type || ""}`,
|
|
82
|
+
showHelp: true,
|
|
83
|
+
exit: true,
|
|
84
|
+
})
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Consistentcy checks and inferrence of parameters
|
|
88
|
+
if (cli.flags.scheme && cli.flags.concordance) {
|
|
89
|
+
logError({
|
|
90
|
+
message: "Options -s and -c are not compatible with each other.",
|
|
91
|
+
showHelp: true,
|
|
92
|
+
exit: true,
|
|
93
|
+
})
|
|
94
|
+
} else if ((cli.flags.scheme || cli.flags.concordance) && uris.length) {
|
|
95
|
+
logError({
|
|
96
|
+
message: "Options -s/-c can't be used when URIs are specified.",
|
|
97
|
+
showHelp: true,
|
|
98
|
+
exit: true,
|
|
99
|
+
})
|
|
100
|
+
} else if (cli.flags.scheme && !type) {
|
|
101
|
+
type = "concept"
|
|
102
|
+
typeInferred = true
|
|
103
|
+
} else if (cli.flags.concordance && !type) {
|
|
104
|
+
type = "mapping"
|
|
105
|
+
typeInferred = true
|
|
106
|
+
} else if (cli.flags.scheme && type != "concept") {
|
|
107
|
+
logError({
|
|
108
|
+
message: `Option -s is not compatible with type ${type}.`,
|
|
109
|
+
showHelp: true,
|
|
110
|
+
exit: true,
|
|
111
|
+
})
|
|
112
|
+
} else if (cli.flags.setApi && type != "concept") {
|
|
113
|
+
logError({
|
|
114
|
+
message: `Option --set-api is not compatible with type ${type}.`,
|
|
115
|
+
showHelp: true,
|
|
116
|
+
exit: true,
|
|
117
|
+
})
|
|
118
|
+
} else if (cli.flags.concordance && type != "mapping") {
|
|
119
|
+
logError({
|
|
120
|
+
message: `Option -c is not compatible with type ${type}.`,
|
|
121
|
+
showHelp: true,
|
|
122
|
+
exit: true,
|
|
123
|
+
})
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
import config from "../config/index.js"
|
|
127
|
+
import { createServices } from "../services/index.js"
|
|
128
|
+
const services = createServices(config)
|
|
129
|
+
import { models } from "../models/index.js"
|
|
130
|
+
|
|
131
|
+
;
|
|
132
|
+
(async () => {
|
|
133
|
+
// 1. Connect to database.
|
|
134
|
+
try {
|
|
135
|
+
await db.connect()
|
|
136
|
+
} catch (error) {
|
|
137
|
+
logError({
|
|
138
|
+
message: error,
|
|
139
|
+
exit: true,
|
|
140
|
+
})
|
|
141
|
+
}
|
|
142
|
+
log("Connection to database established.")
|
|
143
|
+
log()
|
|
144
|
+
|
|
145
|
+
// 2. Figure out what will get deleted (default: all types).
|
|
146
|
+
const types = type ? [type] : Object.keys(models)
|
|
147
|
+
// Prepare scheme/concordance URIs
|
|
148
|
+
let filterUris
|
|
149
|
+
if (cli.flags.scheme) {
|
|
150
|
+
const scheme = await services.scheme.getScheme(cli.flags.scheme)
|
|
151
|
+
if (scheme) {
|
|
152
|
+
filterUris = [scheme.uri].concat(scheme.identifier || [])
|
|
153
|
+
} else {
|
|
154
|
+
filterUris = [cli.flags.scheme]
|
|
155
|
+
}
|
|
156
|
+
} else if (cli.flags.concordance) {
|
|
157
|
+
const concordance = await services.concordance.getItem(cli.flags.concordance)
|
|
158
|
+
if (concordance) {
|
|
159
|
+
filterUris = [concordance.uri].concat(concordance.identifier || [])
|
|
160
|
+
} else {
|
|
161
|
+
filterUris = [cli.flags.concordance]
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
const toBeDeleted = {}
|
|
165
|
+
for (let type of types) {
|
|
166
|
+
const query = {}
|
|
167
|
+
if (!uris.length) {
|
|
168
|
+
// Get list of all URIs from database
|
|
169
|
+
// Apply filters if necessary
|
|
170
|
+
if (cli.flags.scheme) {
|
|
171
|
+
query["inScheme.uri"] = { $in: filterUris }
|
|
172
|
+
} else if (cli.flags.concordance) {
|
|
173
|
+
query["partOf.uri"] = { $in: filterUris }
|
|
174
|
+
}
|
|
175
|
+
} else {
|
|
176
|
+
query[type === "annotation" ? "id" : "uri"] = { $in: uris }
|
|
177
|
+
}
|
|
178
|
+
toBeDeleted[type] = (await models[type].find(query, { _id: 1 }).lean()).map(r => r._id)
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
let question = `Deleting ${uris.length ? "" : "all "}${type ? `${type}s` : "data"}${typeInferred ? " (inferred)" : ""}`
|
|
182
|
+
if (uris.length) {
|
|
183
|
+
question += " with URIs " + uris.join(", ")
|
|
184
|
+
}
|
|
185
|
+
if (cli.flags.scheme) {
|
|
186
|
+
question += ` from scheme ${cli.flags.scheme}`
|
|
187
|
+
} else if (cli.flags.concordance) {
|
|
188
|
+
question += ` from concordance ${cli.flags.concordance}`
|
|
189
|
+
}
|
|
190
|
+
question += " from database.\n"
|
|
191
|
+
let totalCount = 0
|
|
192
|
+
for (let type of types) {
|
|
193
|
+
const count = toBeDeleted[type] && toBeDeleted[type].length
|
|
194
|
+
if (count) {
|
|
195
|
+
question += `- ${count} ${type}s will be deleted.\n`
|
|
196
|
+
}
|
|
197
|
+
totalCount += count
|
|
198
|
+
}
|
|
199
|
+
if (totalCount == 0) {
|
|
200
|
+
logError({
|
|
201
|
+
message: "Did not find any entities to be deleted, aborting...",
|
|
202
|
+
exit: true,
|
|
203
|
+
})
|
|
204
|
+
}
|
|
205
|
+
if (totalCount > 50000) {
|
|
206
|
+
question += "This will take a while.\n"
|
|
207
|
+
}
|
|
208
|
+
question += "Is that okay?"
|
|
209
|
+
const ok = await yesno({
|
|
210
|
+
question,
|
|
211
|
+
defaultValue: false,
|
|
212
|
+
})
|
|
213
|
+
if (!ok) {
|
|
214
|
+
logError({
|
|
215
|
+
message: "Aborting...",
|
|
216
|
+
exit: true,
|
|
217
|
+
})
|
|
218
|
+
}
|
|
219
|
+
log()
|
|
220
|
+
|
|
221
|
+
for (let type of types) {
|
|
222
|
+
if (!toBeDeleted[type] || !toBeDeleted[type].length) {
|
|
223
|
+
continue
|
|
224
|
+
}
|
|
225
|
+
log(`Dealing with ${type}s...`)
|
|
226
|
+
for (let chunk of _.chunk(toBeDeleted[type], 50000)) {
|
|
227
|
+
const query = { _id: { $in: chunk } }
|
|
228
|
+
// For concepts, get all schemes to be adjusted later
|
|
229
|
+
let schemeUrisToAdjust = []
|
|
230
|
+
if (type == "concept") {
|
|
231
|
+
schemeUrisToAdjust = await models.concept.distinct("inScheme.uri", query).lean()
|
|
232
|
+
}
|
|
233
|
+
// For mappings, get all concordances to be adjusted later
|
|
234
|
+
let concordanceUrisToAdjust = []
|
|
235
|
+
if (type == "mapping") {
|
|
236
|
+
concordanceUrisToAdjust = await models.mapping.distinct("partOf.uri", query).lean()
|
|
237
|
+
}
|
|
238
|
+
// Delete entities...
|
|
239
|
+
const result = await models[type].deleteMany(query)
|
|
240
|
+
log(`- ${result.deletedCount} ${type}s deleted.`)
|
|
241
|
+
// Adjust schemes
|
|
242
|
+
if (schemeUrisToAdjust.length) {
|
|
243
|
+
log(`- adjusting ${schemeUrisToAdjust.length} schemes...`)
|
|
244
|
+
await services.scheme.postAdjustmentsForItems(schemeUrisToAdjust.map(uri => ({ uri })), { setApi: cli.flags.setApi })
|
|
245
|
+
}
|
|
246
|
+
// Adjust concordances
|
|
247
|
+
if (concordanceUrisToAdjust.length) {
|
|
248
|
+
log(`- adjusting extent for ${concordanceUrisToAdjust.length} concordances...`)
|
|
249
|
+
await Promise.all(concordanceUrisToAdjust.map(uri => services.concordance.postAdjustmentForConcordance(uri)))
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
log()
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
db.disconnect()
|
|
256
|
+
log(`End of import script: ${new Date()}`)
|
|
257
|
+
})()
|
package/bin/upgrade.js
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { Upgrader } from "../utils/version.js"
|
|
4
|
+
import config from "../config/index.js"
|
|
5
|
+
|
|
6
|
+
const upgrader = new Upgrader(config)
|
|
7
|
+
|
|
8
|
+
import * as db from "../utils/db.js"
|
|
9
|
+
import { Meta } from "../models/meta.js"
|
|
10
|
+
|
|
11
|
+
;(async () => {
|
|
12
|
+
await db.connect()
|
|
13
|
+
const meta = await Meta.findOne()
|
|
14
|
+
const list = upgrader.getUpgrades(meta.version, { forceLatest: process.argv.includes("-f") || process.argv.includes("--force-latest") })
|
|
15
|
+
console.log()
|
|
16
|
+
for (const version of list) {
|
|
17
|
+
console.log(`Performing necessary upgrades for version ${version}...`)
|
|
18
|
+
try {
|
|
19
|
+
await upgrader[version]()
|
|
20
|
+
meta.version = version
|
|
21
|
+
await meta.save()
|
|
22
|
+
console.log(`... upgrades for version ${version} done.`)
|
|
23
|
+
} catch (error) {
|
|
24
|
+
console.error("Error:", error)
|
|
25
|
+
console.error("aborting...")
|
|
26
|
+
break
|
|
27
|
+
}
|
|
28
|
+
console.log()
|
|
29
|
+
}
|
|
30
|
+
if (!list.length) {
|
|
31
|
+
console.log("No upgrades necessary.")
|
|
32
|
+
}
|
|
33
|
+
db.disconnect()
|
|
34
|
+
})()
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
{
|
|
2
|
+
"verbosity": "warn",
|
|
3
|
+
"baseUrl": null,
|
|
4
|
+
"title": "JSKOS Server",
|
|
5
|
+
"version": null,
|
|
6
|
+
"closedWorldAssumption": true,
|
|
7
|
+
"port": 3000,
|
|
8
|
+
"proxies": [],
|
|
9
|
+
"mongo": {
|
|
10
|
+
"user": "",
|
|
11
|
+
"pass": "",
|
|
12
|
+
"host": "127.0.0.1",
|
|
13
|
+
"port": 27017,
|
|
14
|
+
"db": "jskos-server",
|
|
15
|
+
"options": {
|
|
16
|
+
"connectTimeoutMS": 360000,
|
|
17
|
+
"socketTimeoutMS": 360000,
|
|
18
|
+
"heartbeatFrequencyMS": 10000
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"auth": {
|
|
22
|
+
"algorithm": "RS256",
|
|
23
|
+
"key": null
|
|
24
|
+
},
|
|
25
|
+
"schemes": true,
|
|
26
|
+
"concepts": true,
|
|
27
|
+
"mappings": {
|
|
28
|
+
"read": {
|
|
29
|
+
"auth": false
|
|
30
|
+
},
|
|
31
|
+
"create": {
|
|
32
|
+
"auth": true
|
|
33
|
+
},
|
|
34
|
+
"update": {
|
|
35
|
+
"auth": true,
|
|
36
|
+
"crossUser": false
|
|
37
|
+
},
|
|
38
|
+
"delete": {
|
|
39
|
+
"auth": true,
|
|
40
|
+
"crossUser": false
|
|
41
|
+
},
|
|
42
|
+
"fromSchemeWhitelist": null,
|
|
43
|
+
"toSchemeWhitelist": null,
|
|
44
|
+
"cardinality": "1-to-n"
|
|
45
|
+
},
|
|
46
|
+
"concordances": true,
|
|
47
|
+
"annotations": {
|
|
48
|
+
"read": {
|
|
49
|
+
"auth": false
|
|
50
|
+
},
|
|
51
|
+
"create": {
|
|
52
|
+
"auth": true
|
|
53
|
+
},
|
|
54
|
+
"update": {
|
|
55
|
+
"auth": true,
|
|
56
|
+
"crossUser": false
|
|
57
|
+
},
|
|
58
|
+
"delete": {
|
|
59
|
+
"auth": true,
|
|
60
|
+
"crossUser": false
|
|
61
|
+
},
|
|
62
|
+
"moderatingIdentities": [],
|
|
63
|
+
"mismatchTagVocabulary": null
|
|
64
|
+
},
|
|
65
|
+
"registries": {
|
|
66
|
+
"read": {
|
|
67
|
+
"auth": false
|
|
68
|
+
},
|
|
69
|
+
"create": {
|
|
70
|
+
"auth": true
|
|
71
|
+
},
|
|
72
|
+
"update": {
|
|
73
|
+
"auth": true,
|
|
74
|
+
"crossUser": false
|
|
75
|
+
},
|
|
76
|
+
"delete": {
|
|
77
|
+
"auth": true,
|
|
78
|
+
"crossUser": false
|
|
79
|
+
},
|
|
80
|
+
"mixedTypes": false
|
|
81
|
+
},
|
|
82
|
+
"changes": false,
|
|
83
|
+
"anonymous": false,
|
|
84
|
+
"identityProviders": null,
|
|
85
|
+
"identityGroups": {},
|
|
86
|
+
"identities": null,
|
|
87
|
+
"ips": null
|
|
88
|
+
}
|