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/routes/data.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import express from "express"
|
|
2
|
+
import { DataService } from "../services/data.js"
|
|
3
|
+
import { wrapAsync, supportDownloadFormats, returnJSON } from "../utils/middleware.js"
|
|
4
|
+
import { useAuth } from "../utils/auth.js"
|
|
5
|
+
|
|
6
|
+
export default config => {
|
|
7
|
+
const router = express.Router()
|
|
8
|
+
const dataService = new DataService(config)
|
|
9
|
+
|
|
10
|
+
router.get(
|
|
11
|
+
"/",
|
|
12
|
+
useAuth(false),
|
|
13
|
+
supportDownloadFormats([]),
|
|
14
|
+
wrapAsync(async req => dataService.getData(req)),
|
|
15
|
+
returnJSON,
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
return router
|
|
19
|
+
}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import express from "express"
|
|
2
|
+
import { MappingService } from "../services/mappings.js"
|
|
3
|
+
import * as utils from "../utils/middleware.js"
|
|
4
|
+
import { wrapAsync, wrapDownload } from "../utils/middleware.js"
|
|
5
|
+
import { useAuth } from "../utils/auth.js"
|
|
6
|
+
import { readRoute, createRoute } from "./common.js"
|
|
7
|
+
|
|
8
|
+
export default config => {
|
|
9
|
+
const router = express.Router()
|
|
10
|
+
const service = new MappingService(config)
|
|
11
|
+
|
|
12
|
+
// /mappings/suggest and /mappings/voc need to come before /mappings/:_id!
|
|
13
|
+
router.get(
|
|
14
|
+
"/suggest",
|
|
15
|
+
useAuth(config.concepts?.read?.auth),
|
|
16
|
+
wrapAsync(async (req) => {
|
|
17
|
+
return await service.getNotationSuggestions(req.query)
|
|
18
|
+
}),
|
|
19
|
+
utils.addPaginationHeaders,
|
|
20
|
+
utils.returnJSON,
|
|
21
|
+
)
|
|
22
|
+
router.get(
|
|
23
|
+
"/voc",
|
|
24
|
+
useAuth(config.schemes?.read?.auth),
|
|
25
|
+
wrapAsync(async (req) => {
|
|
26
|
+
return await service.getMappingSchemes(req.query)
|
|
27
|
+
}),
|
|
28
|
+
utils.addPaginationHeaders,
|
|
29
|
+
utils.adjust,
|
|
30
|
+
utils.returnJSON,
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
readRoute(router, "/", config.mappings.read, service, "mappings", ["json", "ndjson", "csv", "tsv"])
|
|
34
|
+
createRoute(router, "/", config.mappings.create, service)
|
|
35
|
+
|
|
36
|
+
if (config.mappings.read) {
|
|
37
|
+
router.get(
|
|
38
|
+
"/infer",
|
|
39
|
+
useAuth(config.mappings.read.auth),
|
|
40
|
+
wrapAsync(async req => service.inferMappings(req.query)),
|
|
41
|
+
utils.addPaginationHeaders,
|
|
42
|
+
utils.adjust,
|
|
43
|
+
utils.returnJSON,
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
router.get(
|
|
47
|
+
"/:_id",
|
|
48
|
+
useAuth(config.mappings.read.auth),
|
|
49
|
+
utils.supportDownloadFormats(["json", "ndjson", "csv", "tsv"]),
|
|
50
|
+
wrapAsync(async req => service.getMapping(req.params._id)),
|
|
51
|
+
wrapDownload(utils.adjust, false),
|
|
52
|
+
wrapDownload(utils.returnJSON, false),
|
|
53
|
+
wrapDownload(utils.handleDownload("mapping"), true),
|
|
54
|
+
)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (config.mappings.update) {
|
|
58
|
+
router.put(
|
|
59
|
+
"/:_id",
|
|
60
|
+
useAuth(config.mappings.update.auth),
|
|
61
|
+
utils.bodyParser,
|
|
62
|
+
wrapAsync(async (req) => {
|
|
63
|
+
return await service.putMapping({
|
|
64
|
+
_id: req.params._id,
|
|
65
|
+
body: req.body,
|
|
66
|
+
user: req.user,
|
|
67
|
+
existing: req.existing,
|
|
68
|
+
})
|
|
69
|
+
}),
|
|
70
|
+
utils.adjust,
|
|
71
|
+
utils.returnJSON,
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
router.patch(
|
|
75
|
+
"/:_id",
|
|
76
|
+
useAuth(config.mappings.update.auth),
|
|
77
|
+
utils.bodyParser,
|
|
78
|
+
wrapAsync(async (req) => {
|
|
79
|
+
return await service.patchMapping({
|
|
80
|
+
_id: req.params._id,
|
|
81
|
+
body: req.body,
|
|
82
|
+
user: req.user,
|
|
83
|
+
existing: req.existing,
|
|
84
|
+
})
|
|
85
|
+
}),
|
|
86
|
+
utils.adjust,
|
|
87
|
+
utils.returnJSON,
|
|
88
|
+
)
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if (config.mappings.delete) {
|
|
92
|
+
router.delete(
|
|
93
|
+
"/:_id",
|
|
94
|
+
useAuth(config.mappings.delete.auth),
|
|
95
|
+
utils.bodyParser,
|
|
96
|
+
wrapAsync(async (req) => {
|
|
97
|
+
return await service.deleteItem({
|
|
98
|
+
_id: req.params._id,
|
|
99
|
+
user: req.user,
|
|
100
|
+
existing: req.existing,
|
|
101
|
+
})
|
|
102
|
+
}),
|
|
103
|
+
(req, res) => res.sendStatus(204),
|
|
104
|
+
)
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
return router
|
|
108
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import express from "express"
|
|
2
|
+
import { RegistryService } from "../services/registries.js"
|
|
3
|
+
import { createRoute, readRoute, updateRoute, deleteRoute, suggestRoute } from "./common.js"
|
|
4
|
+
|
|
5
|
+
export default config => {
|
|
6
|
+
const router = express.Router()
|
|
7
|
+
const { registries } = config
|
|
8
|
+
if (!registries) {
|
|
9
|
+
return router
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const service = new RegistryService(config)
|
|
13
|
+
|
|
14
|
+
readRoute(router, "/", registries.read, service, "registries")
|
|
15
|
+
createRoute(router, "/", registries.create, service)
|
|
16
|
+
updateRoute(router, "/", registries.update, service)
|
|
17
|
+
deleteRoute(router, "/", registries.delete, service)
|
|
18
|
+
|
|
19
|
+
// TODO: patchRoute
|
|
20
|
+
|
|
21
|
+
suggestRoute(router, "/suggest", registries.read, service)
|
|
22
|
+
|
|
23
|
+
return router
|
|
24
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import express from "express"
|
|
2
|
+
import { SchemeService } from "../services/schemes.js"
|
|
3
|
+
import { ConceptService } from "../services/concepts.js"
|
|
4
|
+
import * as utils from "../utils/middleware.js"
|
|
5
|
+
import { wrapAsync, wrapDownload } from "../utils/middleware.js"
|
|
6
|
+
import { useAuth } from "../utils/auth.js"
|
|
7
|
+
import { MalformedRequestError } from "../errors/index.js"
|
|
8
|
+
import { readRoute, createRoute, updateRoute, deleteRoute, suggestRoute } from "./common.js"
|
|
9
|
+
|
|
10
|
+
export default config => {
|
|
11
|
+
const router = express.Router()
|
|
12
|
+
const service = new SchemeService(config)
|
|
13
|
+
const { schemes, concepts } = config
|
|
14
|
+
|
|
15
|
+
readRoute(router, "/", schemes.read, service, "schemes")
|
|
16
|
+
createRoute(router, "/", schemes.create, service)
|
|
17
|
+
updateRoute(router, "/", schemes.update, service)
|
|
18
|
+
deleteRoute(router, "/", schemes.delete, service)
|
|
19
|
+
|
|
20
|
+
suggestRoute(router, "/suggest", schemes.read, service)
|
|
21
|
+
|
|
22
|
+
if (concepts) {
|
|
23
|
+
const conceptService = new ConceptService(config)
|
|
24
|
+
|
|
25
|
+
router.get(
|
|
26
|
+
"/top",
|
|
27
|
+
useAuth(concepts.read.auth),
|
|
28
|
+
utils.supportDownloadFormats([]),
|
|
29
|
+
wrapAsync(async (req) => {
|
|
30
|
+
return await conceptService.getTop(req.query)
|
|
31
|
+
}),
|
|
32
|
+
utils.addPaginationHeaders,
|
|
33
|
+
utils.adjust,
|
|
34
|
+
utils.returnJSON,
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
router.get(
|
|
38
|
+
"/concepts",
|
|
39
|
+
useAuth(concepts.read.auth),
|
|
40
|
+
utils.supportDownloadFormats(["json", "ndjson"]),
|
|
41
|
+
wrapAsync(async (req) => {
|
|
42
|
+
if (!req.query.uri) {
|
|
43
|
+
throw new MalformedRequestError("Parameter `uri` (URI of a vocabulary) is required for endpoint /voc/concepts")
|
|
44
|
+
}
|
|
45
|
+
const query = { ...req.query, voc: req.query.uri }
|
|
46
|
+
delete query.uri
|
|
47
|
+
return await conceptService.queryItems(query)
|
|
48
|
+
}),
|
|
49
|
+
wrapDownload(utils.addPaginationHeaders, false),
|
|
50
|
+
wrapDownload(utils.adjust, false),
|
|
51
|
+
wrapDownload(utils.returnJSON, false),
|
|
52
|
+
wrapDownload(utils.handleDownload("concepts"), true),
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
if (concepts.delete) {
|
|
56
|
+
router.delete(
|
|
57
|
+
"/concepts",
|
|
58
|
+
useAuth(concepts.delete.auth),
|
|
59
|
+
utils.bodyParser,
|
|
60
|
+
wrapAsync(async (req) => {
|
|
61
|
+
return await conceptService.deleteConceptsFromScheme({
|
|
62
|
+
scheme: req.existing,
|
|
63
|
+
setApi: req.query.setApi,
|
|
64
|
+
})
|
|
65
|
+
}),
|
|
66
|
+
(req, res) => res.sendStatus(204),
|
|
67
|
+
)
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return router
|
|
72
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import express from "express"
|
|
2
|
+
import { ValidateService } from "../services/validate.js"
|
|
3
|
+
import { wrapAsync, returnJSON } from "../utils/middleware.js"
|
|
4
|
+
import axios from "axios"
|
|
5
|
+
import { MalformedRequestError } from "../errors/index.js"
|
|
6
|
+
|
|
7
|
+
export default config => {
|
|
8
|
+
const router = express.Router()
|
|
9
|
+
const service = new ValidateService(config)
|
|
10
|
+
|
|
11
|
+
router.get(
|
|
12
|
+
"/",
|
|
13
|
+
wrapAsync(async req => {
|
|
14
|
+
const url = req.query.url
|
|
15
|
+
if (!url) {
|
|
16
|
+
throw new MalformedRequestError("Please use HTTP POST or provide an URL to load data from!")
|
|
17
|
+
}
|
|
18
|
+
try {
|
|
19
|
+
const data = (await axios.get(url)).data
|
|
20
|
+
return await service.validate(data, req.query)
|
|
21
|
+
} catch (error) {
|
|
22
|
+
console.log(error)
|
|
23
|
+
throw new MalformedRequestError(`Error loading data from URL ${url}.`)
|
|
24
|
+
}
|
|
25
|
+
}),
|
|
26
|
+
returnJSON,
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
router.post(
|
|
30
|
+
"/",
|
|
31
|
+
express.json(),
|
|
32
|
+
wrapAsync(async req => service.validate(req.body, req.query)),
|
|
33
|
+
returnJSON,
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
return router
|
|
37
|
+
}
|
package/server.js
ADDED
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
import config from "./config/index.js"
|
|
2
|
+
import * as utils from "./utils/middleware.js"
|
|
3
|
+
import express from "express"
|
|
4
|
+
import * as db from "./utils/db.js"
|
|
5
|
+
import morgan from "morgan"
|
|
6
|
+
import nocache from "nocache"
|
|
7
|
+
|
|
8
|
+
import createAnnotationRouter from "./routes/annotations.js"
|
|
9
|
+
import createConceptRouter from "./routes/concepts.js"
|
|
10
|
+
import createConcordanceRouter from "./routes/concordances.js"
|
|
11
|
+
import createMappingRouter from "./routes/mappings.js"
|
|
12
|
+
import createSchemeRouter from "./routes/schemes.js"
|
|
13
|
+
import createRegistryRouter from "./routes/registries.js"
|
|
14
|
+
import createDataRouter from "./routes/data.js"
|
|
15
|
+
import createValidateRouter from "./routes/validate.js"
|
|
16
|
+
|
|
17
|
+
import { serverStatus } from "./utils/status.js"
|
|
18
|
+
|
|
19
|
+
import { ipcheck } from "./utils/ipcheck.js"
|
|
20
|
+
import { useAuth } from "./utils/auth.js"
|
|
21
|
+
import * as errors from "./errors/index.js"
|
|
22
|
+
import portfinder from "portfinder"
|
|
23
|
+
import expressWs from "express-ws"
|
|
24
|
+
import { setupChangesApi, isChangesApiAvailable } from "./utils/changes.js"
|
|
25
|
+
|
|
26
|
+
const __dirname = import.meta.dirname
|
|
27
|
+
const connection = db.connection
|
|
28
|
+
|
|
29
|
+
config.log(`Running in ${config.env} mode.`)
|
|
30
|
+
|
|
31
|
+
if (!config.baseUrl) {
|
|
32
|
+
config.warn("Warning: If you're using jskos-server behind a reverse proxy, it is necessary to add `baseUrl` to the configuration file!")
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Initialize express with settings
|
|
36
|
+
const app = express()
|
|
37
|
+
|
|
38
|
+
// Initialize WebSocket support
|
|
39
|
+
expressWs(app)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
app.set("json spaces", 2)
|
|
43
|
+
if (config.proxies && config.proxies.length) {
|
|
44
|
+
app.set("trust proxy", config.proxies)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Configure view engine to render EJS templates.
|
|
48
|
+
app.set("views", __dirname + "/views")
|
|
49
|
+
app.set("view engine", "ejs")
|
|
50
|
+
|
|
51
|
+
// Database connection
|
|
52
|
+
const connect = async () => {
|
|
53
|
+
try {
|
|
54
|
+
await db.connect(true)
|
|
55
|
+
// TODO: `indexExists` causes a deprecation warning. Find a different solution.
|
|
56
|
+
if (config.schemes && !(await connection.collection("terminologies").indexExists("text"))) {
|
|
57
|
+
config.warn("Text index on terminologies collection missing. /voc/search and /voc/suggest are disabled. Run `npm run import -- --indexes` or `npm run import -- -i schemes` to created indexes.")
|
|
58
|
+
config.status["voc-search"] = null
|
|
59
|
+
config.status["voc-suggest"] = null
|
|
60
|
+
}
|
|
61
|
+
if (config.concepts && !(await connection.collection("concepts").indexExists("text"))) {
|
|
62
|
+
config.warn("Text index on concepts collection missing. /concepts/search and /concepts/suggest are disabled. Run `npm run import -- --indexes` or `npm run import -- -i concepts` to created indexes.")
|
|
63
|
+
config.status.search = null
|
|
64
|
+
config.status.suggest = null
|
|
65
|
+
}
|
|
66
|
+
if (config.annotations?.mismatchTagVocabulary?.uri) {
|
|
67
|
+
const model = await import("./models/concepts.js")
|
|
68
|
+
const concepts = await model.Concept.find({ "inScheme.uri": config.annotations.mismatchTagVocabulary.uri })
|
|
69
|
+
if (concepts.length === 0) {
|
|
70
|
+
config.warn("annotations.mismatchTagVocabulary is configured, but no data for that vocabulary could be found in the database. Import the vocabulary data into this instance for the setting to work.")
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
} catch (error) {
|
|
74
|
+
config.warn("Error connecting to database, reconnect in a few seconds...")
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
// Connect immediately on startup
|
|
78
|
+
connect()
|
|
79
|
+
|
|
80
|
+
// Logging for access logs
|
|
81
|
+
if (config.verbosity === true || config.verbosity === "log") {
|
|
82
|
+
app.use(morgan(":date[iso] \":method :url HTTP/:http-version\" :status :res[content-length] \":referrer\" \":user-agent\""))
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Add default headers
|
|
86
|
+
app.use(utils.addDefaultHeaders)
|
|
87
|
+
|
|
88
|
+
// Disable client side caching
|
|
89
|
+
app.use(nocache())
|
|
90
|
+
|
|
91
|
+
// Disable ETags
|
|
92
|
+
app.set("etag", false)
|
|
93
|
+
app.use(express.urlencoded({ extended: false }))
|
|
94
|
+
|
|
95
|
+
// Set some properties on req that will be used by other middleware
|
|
96
|
+
app.use(utils.addMiddlewareProperties)
|
|
97
|
+
|
|
98
|
+
// Add routes
|
|
99
|
+
|
|
100
|
+
// Root path for static page
|
|
101
|
+
app.get("/", (req, res) => {
|
|
102
|
+
res.setHeader("Content-Type", "text/html")
|
|
103
|
+
res.render("base", {
|
|
104
|
+
config,
|
|
105
|
+
isChangesApiAvailable,
|
|
106
|
+
})
|
|
107
|
+
})
|
|
108
|
+
// JSON Schema for /status
|
|
109
|
+
app.use("/status.schema.json", express.static(__dirname + "/status.schema.json"))
|
|
110
|
+
|
|
111
|
+
// Status page /status
|
|
112
|
+
app.get("/status",
|
|
113
|
+
(req, res) => {
|
|
114
|
+
res.status(200).json(serverStatus(config, connection.readyState === 1))
|
|
115
|
+
})
|
|
116
|
+
|
|
117
|
+
// Database check middleware
|
|
118
|
+
app.use((req, res, next) => {
|
|
119
|
+
if (connection.readyState === 1) {
|
|
120
|
+
next()
|
|
121
|
+
} else {
|
|
122
|
+
// No connection to database, return error
|
|
123
|
+
next(new errors.DatabaseAccessError())
|
|
124
|
+
}
|
|
125
|
+
})
|
|
126
|
+
// IP check middleware
|
|
127
|
+
app.use(ipcheck(config))
|
|
128
|
+
|
|
129
|
+
// /checkAuth
|
|
130
|
+
app.get("/checkAuth", useAuth(true), (req, res) => {
|
|
131
|
+
res.sendStatus(204)
|
|
132
|
+
})
|
|
133
|
+
|
|
134
|
+
// Add conditional routes
|
|
135
|
+
if (config.schemes) {
|
|
136
|
+
app.use("/voc", createSchemeRouter(config))
|
|
137
|
+
}
|
|
138
|
+
if (config.mappings) {
|
|
139
|
+
app.use("/mappings", createMappingRouter(config))
|
|
140
|
+
}
|
|
141
|
+
if (config.concordances) {
|
|
142
|
+
app.use("/concordances", createConcordanceRouter(config))
|
|
143
|
+
}
|
|
144
|
+
if (config.annotations) {
|
|
145
|
+
app.use("/annotations", createAnnotationRouter(config))
|
|
146
|
+
}
|
|
147
|
+
if (config.concepts) {
|
|
148
|
+
app.use(createConceptRouter(config))
|
|
149
|
+
}
|
|
150
|
+
if (config.registries) {
|
|
151
|
+
app.use("/registries", createRegistryRouter(config))
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// These routes are always enabled
|
|
155
|
+
app.use("/data", createDataRouter(config))
|
|
156
|
+
app.use("/validate", createValidateRouter(config))
|
|
157
|
+
|
|
158
|
+
// Error handling
|
|
159
|
+
app.use((error, req, res, next) => {
|
|
160
|
+
// Check if error is defined in errors
|
|
161
|
+
if (Object.values(errors).includes(error.constructor)) {
|
|
162
|
+
res.status(error.statusCode).send({
|
|
163
|
+
error: error.constructor.name,
|
|
164
|
+
status: error.statusCode,
|
|
165
|
+
message: error.message,
|
|
166
|
+
})
|
|
167
|
+
} else {
|
|
168
|
+
next(error)
|
|
169
|
+
}
|
|
170
|
+
})
|
|
171
|
+
|
|
172
|
+
// Changes API
|
|
173
|
+
await setupChangesApi(app, config)
|
|
174
|
+
|
|
175
|
+
const start = async () => {
|
|
176
|
+
if (config.env == "test") {
|
|
177
|
+
portfinder.basePort = config.port
|
|
178
|
+
config.port = await portfinder.getPortPromise()
|
|
179
|
+
}
|
|
180
|
+
app.listen(config.port, () => {
|
|
181
|
+
config.log(`Now listening on port ${config.port}`)
|
|
182
|
+
})
|
|
183
|
+
}
|
|
184
|
+
// Start express server immediately even if database is not yet connected
|
|
185
|
+
start()
|
|
186
|
+
|
|
187
|
+
export {
|
|
188
|
+
app,
|
|
189
|
+
connection as db,
|
|
190
|
+
}
|