aiiinotate 0.2.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.
Files changed (88) hide show
  1. package/LICENSE +661 -0
  2. package/README.md +61 -0
  3. package/cli/import.js +142 -0
  4. package/cli/index.js +26 -0
  5. package/cli/io.js +105 -0
  6. package/cli/migrate.js +123 -0
  7. package/cli/mongoClient.js +11 -0
  8. package/docs/architecture.md +88 -0
  9. package/docs/db.md +38 -0
  10. package/docs/dev_iiif_compatibility.md +43 -0
  11. package/docs/endpoints.md +48 -0
  12. package/docs/progress.md +159 -0
  13. package/docs/specifications/0_w3c_open_annotations.md +332 -0
  14. package/docs/specifications/1_w3c_web_annotations.md +577 -0
  15. package/docs/specifications/2_iiif_apis.md +396 -0
  16. package/docs/specifications/3_iiif_annotations.md +103 -0
  17. package/docs/specifications/4_search_api.md +135 -0
  18. package/docs/specifications/5_sas.md +119 -0
  19. package/docs/specifications/6_mirador.md +119 -0
  20. package/docs/specifications/7_aikon.md +137 -0
  21. package/docs/specifications/include/presentation_2.0.webp +0 -0
  22. package/docs/specifications/include/presentation_2.0_white.png +0 -0
  23. package/docs/specifications/include/presentation_3.0.png +0 -0
  24. package/docs/specifications/include/presentation_3.0_resize.png +0 -0
  25. package/eslint.config.js +27 -0
  26. package/migrations/baseConfig.js +56 -0
  27. package/migrations/manageIndex.js +55 -0
  28. package/migrations/migrate-mongo-config-main.js +8 -0
  29. package/migrations/migrate-mongo-config-test.js +8 -0
  30. package/migrations/migrationScripts/20250825185706-collections.js +41 -0
  31. package/migrations/migrationScripts/20250826194832-annotations2-canvas-index.js +31 -0
  32. package/migrations/migrationScripts/20250904080710-annotations2-schema.js +42 -0
  33. package/migrations/migrationScripts/20251002141951-manifest2-schema.js +43 -0
  34. package/migrations/migrationScripts/20251006212110-manifest-unique-index.js +29 -0
  35. package/migrations/migrationScripts/20251028115614-annotations2-id-index.js +27 -0
  36. package/migrations/migrationTemplate.js +25 -0
  37. package/package.json +78 -0
  38. package/run.sh +70 -0
  39. package/scripts/_migrations.sh +79 -0
  40. package/scripts/_setup.js +31 -0
  41. package/scripts/setup_mongodb.sh +61 -0
  42. package/scripts/setup_mongodb_migrate.sh +17 -0
  43. package/scripts/setup_node.sh +15 -0
  44. package/scripts/utils.sh +192 -0
  45. package/setup.sh +20 -0
  46. package/src/app.js +113 -0
  47. package/src/config/.env.template +22 -0
  48. package/src/data/annotations/annotations2.js +419 -0
  49. package/src/data/annotations/annotations3.js +32 -0
  50. package/src/data/annotations/routes.js +271 -0
  51. package/src/data/annotations/routes.test.js +180 -0
  52. package/src/data/collectionAbstract.js +270 -0
  53. package/src/data/index.js +29 -0
  54. package/src/data/manifests/manifests2.js +305 -0
  55. package/src/data/manifests/manifests2.test.js +53 -0
  56. package/src/data/manifests/manifests3.js +23 -0
  57. package/src/data/manifests/routes.js +95 -0
  58. package/src/data/manifests/routes.test.js +69 -0
  59. package/src/data/routes.js +141 -0
  60. package/src/data/routes.test.js +117 -0
  61. package/src/data/utils/iiif2Utils.js +196 -0
  62. package/src/data/utils/iiif2Utils.test.js +98 -0
  63. package/src/data/utils/iiif3Utils.js +0 -0
  64. package/src/data/utils/iiifUtils.js +18 -0
  65. package/src/data/utils/routeUtils.js +109 -0
  66. package/src/data/utils/testUtils.js +253 -0
  67. package/src/data/utils/utils.js +231 -0
  68. package/src/db/index.js +48 -0
  69. package/src/fileServer/annotations.js +39 -0
  70. package/src/fileServer/data/annotationList_aikon_wit9_man11_anno165_all.jsonld +827 -0
  71. package/src/fileServer/data/annotationList_vhs_wit250_man250_anno250_all.jsonld +37514 -0
  72. package/src/fileServer/data/annotationList_vhs_wit253_man253_anno253_all.jsonld +20111 -0
  73. package/src/fileServer/data/annotations2Invalid.jsonld +39 -0
  74. package/src/fileServer/data/annotations2Valid.jsonld +39 -0
  75. package/src/fileServer/data/bnf_invalid_manifest.json +2806 -0
  76. package/src/fileServer/data/bnf_valid_manifest.json +2817 -0
  77. package/src/fileServer/data/vhs_wit253_man253_anno253_anno-24.json +1 -0
  78. package/src/fileServer/index.js +64 -0
  79. package/src/fileServer/manifests.js +14 -0
  80. package/src/fileServer/utils.js +35 -0
  81. package/src/schemas/index.js +20 -0
  82. package/src/schemas/schemasBase.js +47 -0
  83. package/src/schemas/schemasPresentation2.js +417 -0
  84. package/src/schemas/schemasPresentation3.js +57 -0
  85. package/src/schemas/schemasResolver.js +71 -0
  86. package/src/schemas/schemasRoutes.js +277 -0
  87. package/src/server.js +22 -0
  88. package/src/types.js +93 -0
@@ -0,0 +1,43 @@
1
+ /**
2
+ * define the validation schema for collection `manifests2`.
3
+ */
4
+
5
+ import build from "#src/app.js"
6
+
7
+ /**
8
+ * @param db {import('mongodb').Db}
9
+ * @param client {import('mongodb').MongoClient}
10
+ * @returns {Promise<void>}
11
+ */
12
+ export const up = async (db, client) => {
13
+ const
14
+ fastify = await build(),
15
+ fastifySchema = fastify.schemasPresentation2.getSchema("manifestMongo"),
16
+ schema = fastify.schemasResolver(fastifySchema),
17
+ commandDoc = {
18
+ collMod: "manifests2",
19
+ validator: { $jsonSchema: schema },
20
+ },
21
+ r = await db.command(commandDoc);
22
+
23
+
24
+ if ( r.ok !== 1 ) {
25
+ throw new Error(`command failed with error: ${r}`);
26
+ }
27
+ };
28
+
29
+ /**
30
+ * @param db {import('mongodb').Db}
31
+ * @param client {import('mongodb').MongoClient}
32
+ * @returns {Promise<void>}
33
+ */
34
+ export const down = async (db, client) => {
35
+ const r = await db.command({
36
+ collMod: "manifests2",
37
+ validator: {}
38
+ });
39
+ if ( r.ok !== 1 ) {
40
+ throw new Error(`command failed with error: ${r}`);
41
+ }
42
+ };
43
+
@@ -0,0 +1,29 @@
1
+ /** create a unique index on `manifests2.@id` */
2
+
3
+ const
4
+ colName = "manifests2",
5
+ indexSpec = { "@id": 1 },
6
+ indexOptions = { name: "manifestIdIndex", unique: true };
7
+
8
+ /**
9
+ * @param {import('mongodb').Db} db
10
+ * @param {import('mongodb').MongoClient} client
11
+ * @returns {Promise<void>}
12
+ */
13
+ export const up = async (db, client) => {
14
+ const collection = db.collection(colName);
15
+ const result = await collection.createIndex(indexSpec, indexOptions);
16
+ console.log("created index:", result);
17
+ };
18
+
19
+ /**
20
+ * @param {import('mongodb').Db} db
21
+ * @param {import('mongodb').MongoClient} client
22
+ * @returns {Promise<void>}
23
+ */
24
+ export const down = async (db, client) => {
25
+ const collection = db.collection(colName);
26
+ const result = await collection.dropIndex(indexOptions.name);
27
+ console.log("dropped index:", result);
28
+ };
29
+
@@ -0,0 +1,27 @@
1
+ // template migration file generated by migrate-mongo
2
+
3
+ import {createIndex, removeIndex} from "../manageIndex.js";
4
+
5
+ const
6
+ colName = "annotations2",
7
+ indexSpec = { "@id": 1 },
8
+ indexOptions = { name: "annotationIdIndex" };
9
+
10
+ /**
11
+ * @param {import('mongodb').Db} db
12
+ * @param {import('mongodb').MongoClient} client
13
+ * @returns {Promise<void>}
14
+ */
15
+ export const up = async (db, client) => {
16
+ await createIndex(db, colName, indexSpec, indexOptions);
17
+ };
18
+
19
+ /**
20
+ * @param {import('mongodb').Db} db
21
+ * @param {import('mongodb').MongoClient} client
22
+ * @returns {Promise<void>}
23
+ */
24
+ export const down = async (db, client) => {
25
+ await removeIndex(db, colName, indexOptions);
26
+ };
27
+
@@ -0,0 +1,25 @@
1
+ // template migration file generated by migrate-mongo
2
+
3
+ /**
4
+ * @param {import('mongodb').Db} db
5
+ * @param {import('mongodb').MongoClient} client
6
+ * @returns {Promise<void>}
7
+ */
8
+ export const up = async (db, client) => {
9
+ // TODO write your migration here.
10
+ // See https://github.com/seppevs/migrate-mongo/#creating-a-new-migration-script
11
+ // Example:
12
+ // await db.collection('albums').updateOne({artist: 'The Beatles'}, {$set: {blacklisted: true}});
13
+ };
14
+
15
+ /**
16
+ * @param {import('mongodb').Db} db
17
+ * @param {import('mongodb').MongoClient} client
18
+ * @returns {Promise<void>}
19
+ */
20
+ export const down = async (db, client) => {
21
+ // TODO write the statements to rollback your migration (if possible)
22
+ // Example:
23
+ // await db.collection('albums').updateOne({artist: 'The Beatles'}, {$set: {blacklisted: false}});
24
+ };
25
+
package/package.json ADDED
@@ -0,0 +1,78 @@
1
+ {
2
+ "name": "aiiinotate",
3
+ "version": "0.2.0",
4
+ "description": "a fast IIIF-compliant annotation server",
5
+ "main": "index.js",
6
+ "type": "module",
7
+ "directories": {
8
+ "doc": "docs"
9
+ },
10
+ "scripts": {
11
+ "setup": "bash run.sh -s",
12
+ "start": "bash run.sh -d",
13
+ "prod": "bash run.sh -p",
14
+ "test": "bash run.sh -t",
15
+ "cli": "dotenvx run -f ./src/config/.env -- node ./cli/index.js",
16
+ "lint": "npx eslint --fix",
17
+ "migrate-make": "npm run cli -- migrate make",
18
+ "migrate-apply": "npm run cli migrate apply",
19
+ "migrate-revert": "npm run cli migrate revert",
20
+ "migrate-revert-all": "npm run cli migrate revert-all"
21
+ },
22
+ "pre-commit": [
23
+ "lint"
24
+ ],
25
+ "repository": {
26
+ "type": "git",
27
+ "url": "git+https://github.com/Aikon-platform/aiiinotate.git"
28
+ },
29
+ "keywords": [
30
+ "annotation-server",
31
+ "iiif",
32
+ "annotation",
33
+ "international-image-interoperability-framework"
34
+ ],
35
+ "author": "Aikon",
36
+ "license": "MIT",
37
+ "bugs": {
38
+ "url": "https://github.com/Aikon-platform/aiiinotate/issues"
39
+ },
40
+ "homepage": "https://github.com/Aikon-platform/aiiinotate#readme",
41
+ "imports": {
42
+ "#types": "./src/types.js",
43
+ "#cli/*.js": "./cli/*.js",
44
+ "#src/*.js": "./src/*.js",
45
+ "#migrations/*.js": "./migrations/*.js",
46
+ "#db/*.js": "./src/db/*.js",
47
+ "#schemas/*.js": "./src/schemas/*.js",
48
+ "#config/*.js": "./src/config/*.js",
49
+ "#data/*.js": "./src/data/*.js",
50
+ "#utils/*.js": "./src/data/utils/*.js",
51
+ "#fileServer/*.js": "./src/fileServer/*.js",
52
+ "#fileServer/*.json": "./src/fileServer/*.json",
53
+ "#manifests/*.js": "./src/data/manifests/*.js",
54
+ "#annotations/*.js": "./src/data/annotations/*.js"
55
+ },
56
+ "dependencies": {
57
+ "@dotenvx/dotenvx": "^1.49.0",
58
+ "@fastify/ajv-compiler": "^4.0.2",
59
+ "@fastify/cors": "^11.1.0",
60
+ "@fastify/mongodb": "^9.0.2",
61
+ "@fastify/swagger": "^9.5.2",
62
+ "commander": "^14.0.0",
63
+ "fastify": "^5.5.0",
64
+ "migrate-mongo": "^12.1.3",
65
+ "mongodb": "^6.18.0",
66
+ "swagger-markdown": "^3.0.0",
67
+ "uuid": "^11.1.0"
68
+ },
69
+ "devDependencies": {
70
+ "@eslint/css": "^0.10.0",
71
+ "@eslint/js": "^9.33.0",
72
+ "@eslint/json": "^0.13.1",
73
+ "@stylistic/eslint-plugin": "^5.2.3",
74
+ "eslint": "^9.33.0",
75
+ "globals": "^16.3.0",
76
+ "pre-commit": "^1.2.2"
77
+ }
78
+ }
package/run.sh ADDED
@@ -0,0 +1,70 @@
1
+ #!/bin/env bash
2
+
3
+ source "./scripts/utils.sh";
4
+
5
+ SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
6
+ ENV_FILE="$SCRIPT_DIR/src/config/.env";
7
+
8
+ print_usage() {
9
+ cat<<EOF
10
+
11
+ USAGE bash run.sh [-s, -d, -p, -t, -c, -h]
12
+
13
+ (use from the scripts defined in 'package.json': 'npm start')
14
+
15
+ -s: setup the app
16
+ -t: test the app
17
+ -d: run the app in dev mode
18
+ -p: run the app in prod mode
19
+ -c: run the command line interface
20
+ -h: print help and exit
21
+
22
+ EOF
23
+ }
24
+
25
+ start () {
26
+ local mode="$1"
27
+
28
+ if [ ! -f "$ENV_FILE" ];
29
+ then echo -e "\nERROR: .env file not found at '$ENV_FILE'. exiting..." && exit 1;
30
+ fi;
31
+
32
+ start_mongod
33
+
34
+ if [ "$mode" = "setup" ]; then
35
+ dotenvx run -f "$ENV_FILE" -- \
36
+ node "$SCRIPT_DIR/scripts/setup.js";
37
+ elif [ "$mode" = "dev" ]; then
38
+ dotenvx run -f "$ENV_FILE" -- \
39
+ node --watch "$SCRIPT_DIR/src/server.js";
40
+ elif [ "$mode" = "test" ]; then
41
+ dotenvx run -f "$ENV_FILE" -- \
42
+ node --test --test-isolation=none;
43
+ elif [ "$mode" = "cli" ] ; then
44
+ dotenvx run -f "$ENV_FILE" -- \
45
+ node "$SCRIPT_DIR/cli/index.js";
46
+ else echo -e "\nERROR: mode not implemented: '$mode'\n"; print_usage; exit 1;
47
+ fi;
48
+ }
49
+
50
+ while getopts 'hdptcs' mode_flag; do
51
+ case "${mode_flag}" in
52
+ s) MODE="setup"
53
+ break;;
54
+ d) MODE="dev"
55
+ break;;
56
+ p) MODE="prod"
57
+ break;;
58
+ t) MODE="test"
59
+ break;;
60
+ c) MODE="cli"
61
+ break;;
62
+ h) print_usage
63
+ exit 0;;
64
+ *) print_usage
65
+ exit 1;;
66
+ esac
67
+ done
68
+
69
+ start "$MODE";
70
+
@@ -0,0 +1,79 @@
1
+ #!/bin/env bash
2
+
3
+ # use through package.json scripts.
4
+
5
+ # these sripts are used to manage all migrations in parallel
6
+ # on both the main database and the test database.
7
+ #NOTE migrate-init is not implemented.
8
+
9
+ SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
10
+
11
+ source "$SCRIPT_DIR/utils.sh" || exit 1;
12
+
13
+ MIGRATIONS_CONFIG_MAIN="$MIGRATIONS_DIR/migrate-mongo-config-main.js";
14
+ MIGRATIONS_CONFIG_TEST="$MIGRATIONS_DIR/migrate-mongo-config-test.js";
15
+ MIGRATIONS_CONFIGS=("$MIGRATIONS_CONFIG_MAIN" "$MIGRATIONS_CONFIG_TEST");
16
+
17
+ ##################################################
18
+ # functions
19
+
20
+ # create a migration
21
+ # NOTE `migrate-mongo create` generates a timestamped file and, since this script is run twice
22
+ # (once per config file), 2 migration files are created. so what we do is mimic migrate-make by
23
+ # copying a blank template file to the `migrationScripts` directory.
24
+ migrate_make() {
25
+ config_fp=$1; # path to config file
26
+ migration_name="$2"; # name of migration to create
27
+
28
+ if [ -z "$migration_name" ];
29
+ then echo "ERROR. a migration name must be given."; exit 1;
30
+ fi;
31
+
32
+ cp "$MIGRATIONS_DIR/migrationTemplate.js" "$MIGRATIONS_DIR/migrationScripts/$(date +'%Y%m%d%H%M%S')-$migration_name.js";
33
+ }
34
+
35
+ # apply migrations
36
+ migrate_apply() {
37
+ config_fp=$1; # path to config file
38
+ dotenvx run -f "$ENV_FILE" -- npx migrate-mongo up -f "$config_fp";
39
+ }
40
+
41
+ # rvert the last migration
42
+ migrate_revert() {
43
+ config_fp=$1; # path to config file
44
+ dotenvx run -f "$ENV_FILE" -- npx migrate-mongo down -f "$config_fp";
45
+ }
46
+
47
+ # undo all migrations
48
+ migrate_revert_all() {
49
+ config_fp=$1; # path to config file
50
+
51
+ for _ in "$MIGRATIONS_DIR"/migrationScripts/*;
52
+ do dotenvx run -f "$ENV_FILE" -- npx migrate-mongo down -f "$config_fp";
53
+ done;
54
+ }
55
+
56
+
57
+ ##################################################
58
+ # cli
59
+
60
+ OP=$1
61
+ MIGRATION_NAME=$2 # only used by `migrate_make`
62
+
63
+ case "$OP" in
64
+ make) FUNC=migrate_make;;
65
+ apply) FUNC=migrate_apply;;
66
+ revert) FUNC=migrate_revert;;
67
+ revertAll) FUNC=migrate_revert_all;;
68
+ esac;
69
+
70
+ if [ -z "$FUNC" ];
71
+ then echo "ERROR: unrecognized keyword '$OP'. please use one of 'make', 'apply', 'revert', 'revertAll'. exiting..."; exit 1;
72
+ fi;
73
+
74
+ start_mongod
75
+
76
+ for config_fp in "${MIGRATIONS_CONFIGS[@]}"; do
77
+ $FUNC "$config_fp" "$MIGRATION_NAME";
78
+ done
79
+
@@ -0,0 +1,31 @@
1
+ #!usr/bin/env node
2
+ import path from "node:path";
3
+ import { execSync } from "node:child_process";
4
+ import { fileURLToPath } from "node:url";
5
+
6
+ import { MongoClient } from "mongodb";
7
+
8
+ const
9
+ // path to dirctory of curent file
10
+ dirScripts = path.dirname(fileURLToPath(import.meta.url)),
11
+ dirRoot = path.resolve(dirScripts, ".."),
12
+ dirMigrations = path.resolve(dirRoot, "migrations");
13
+
14
+ const connString = process.env.MONGODB_CONNSTRING;
15
+
16
+ (async () => {
17
+ let client;
18
+ try {
19
+ client = new MongoClient(connString);
20
+ await client.connect();
21
+ console.log("CONNECTED !")
22
+ console.log(dirScripts);
23
+ console.log(dirRoot);
24
+ console.log(dirMigrations);
25
+ } finally {
26
+ if ( client != null ) {
27
+ client.close()
28
+ }
29
+ }
30
+ }
31
+ )();
@@ -0,0 +1,61 @@
1
+ #!/bin/env bash
2
+
3
+ # mongo install guide: https://www.mongodb.com/docs/manual/tutorial/install-mongodb-on-ubuntu/#std-label-install-mdb-community-ubuntu
4
+
5
+ #NOTE only the mongodb installation is done here. for database creation, see `setup_mongodb_populate.sh`
6
+
7
+ SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
8
+ source "$SCRIPT_DIR/utils.sh";
9
+
10
+ install_mongodb_ubuntu () {
11
+
12
+ sudo apt-get install gnupg curl
13
+
14
+ curl -fsSL https://www.mongodb.org/static/pgp/server-8.0.asc | \
15
+ sudo gpg -o /usr/share/keyrings/mongodb-server-8.0.gpg \
16
+ --dearmor
17
+
18
+ # assert we have an 86 64 architecture
19
+ if [ "$(arch)" != "x86_64" ];
20
+ then echo "MongoDB only supports x86_64 architectures (yours is $(arch)). exiting..."; exit 1
21
+ fi;
22
+
23
+ # fetch the release name. Mongo only supports LTS versions, so if the user's Ubuntu version is not LTS, we get the name of the last LTS released before the user's version.
24
+ source "/etc/lsb-release"
25
+ if float_comparison "$DISTRIB_RELEASE >= 24.04";
26
+ then DISTRIB="noble";
27
+ elif float_comparison "$DISTRIB_RELEASE >= 22.04";
28
+ then DISTRIB="jammy";
29
+ elif float_comparison "$DISTRIB_RELEASE >= 20.04";
30
+ then DISTRIB="focal";
31
+ else echo "Your Ubuntu version ($DISTRIB_RELEASE) is not supported by MongoDB 8.0"; exit 1;
32
+ fi;
33
+
34
+ # create list file
35
+ echo "deb [ arch=amd64,arm64 signed-by=/usr/share/keyrings/mongodb-server-8.0.gpg ] https://repo.mongodb.org/apt/ubuntu $DISTRIB/mongodb-org/8.0 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-8.0.list
36
+
37
+ sudo apt-get update
38
+
39
+ sudo apt-get install -y mongodb-org
40
+ }
41
+
42
+ install_mongodb_mac () {
43
+ xcode-select --install;
44
+ brew tap mongodb/brew;
45
+ brew update;
46
+ brew install mongodb-community@8.0;
47
+ }
48
+
49
+ if ! command -v mongod ; then
50
+ echo_title "INSTALL MONGODB"
51
+
52
+ if [ "$OS" = "Linux" ]; then
53
+ install_mongodb_ubuntu;
54
+ sudo systemctl start mongod;
55
+ elif [ "$OS" = "Mac" ]; then
56
+ install_mongodb_mac;
57
+ brew services start mongodb-community@8.0;
58
+ else echo "Unsupported OS: $OS"; exit 1;
59
+ fi;
60
+
61
+ fi;
@@ -0,0 +1,17 @@
1
+ #!/bin/env bash
2
+
3
+ #NOTE : this setup creates and populates our db WITHOUT users or authentication.
4
+ # it is possible to add users and auth to a mongodb instance, but
5
+ # - it is a bit convoluted in itself
6
+ # - it is difficult to automate: we would need to
7
+ # - create a root user + a user for the app
8
+ # - create this app user by generating mongosh scripts from the user's .env files (so use Python to write custom JS)
9
+ # - update the mongodb conf file so that the systemd mongodb service uses auth login, which would need to parse YAML, so to use python
10
+
11
+ SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
12
+ ROOT_DIR="$SCRIPT_DIR/../"
13
+
14
+ cd "$ROOT_DIR"
15
+
16
+ npm run migrate-apply
17
+
@@ -0,0 +1,15 @@
1
+ #!/bin/env bash
2
+
3
+ SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
4
+ source "$SCRIPT_DIR/utils.sh";
5
+
6
+ if ! command -v npm &> /dev/null; then
7
+ echo_title "INSTALL NVM & NODE";
8
+ curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.5/install.sh | bash
9
+ nvm install node
10
+ npm install -g webpack webpack-cli
11
+ fi
12
+
13
+ echo_title "SETUP FASTIFY APP";
14
+ cd "$ROOT_DIR";
15
+ npm i;
@@ -0,0 +1,192 @@
1
+ #!/bin/env bash
2
+
3
+ # directory of the current script
4
+ SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
5
+ # root of the app
6
+ ROOT_DIR=$( dirname "$SCRIPT_DIR" )
7
+ # src/ directory
8
+ SRC_DIR="$ROOT_DIR/src"
9
+ # migrations/ dir
10
+ MIGRATIONS_DIR="$ROOT_DIR/migrations";
11
+ # .env file
12
+ ENV_FILE="$SRC_DIR/config/.env"
13
+
14
+
15
+ color_echo() {
16
+ Color_Off="\033[0m"
17
+ Red="\033[1;91m" # Red
18
+ Green="\033[1;92m" # Green
19
+ Yellow="\033[1;93m" # Yellow
20
+ Blue="\033[1;94m" # Blue
21
+ Purple="\033[1;95m" # Purple
22
+ Cyan="\033[1;96m" # Cyan
23
+
24
+ case "$1" in
25
+ "green") echo -e "$Green$2$Color_Off";;
26
+ "red") echo -e "$Red$2$Color_Off";;
27
+ "blue") echo -e "$Blue$2$Color_Off";;
28
+ "yellow") echo -e "$Yellow$2$Color_Off";;
29
+ "purple") echo -e "$Purple$2$Color_Off";;
30
+ "cyan") echo -e "$Cyan$2$Color_Off";;
31
+ *) echo "$2";;
32
+ esac
33
+ }
34
+
35
+ echo_title(){
36
+ sep_line="========================================"
37
+ len_title=${#1}
38
+
39
+ if [ "$len_title" -gt 40 ]; then
40
+ sep_line=$(printf "%0.s=" $(seq 1 $len_title))
41
+ title="$1"
42
+ else
43
+ diff=$((38 - len_title))
44
+ half_diff=$((diff / 2))
45
+ sep=$(printf "%0.s=" $(seq 1 $half_diff))
46
+
47
+ if [ $((diff % 2)) -ne 0 ]; then
48
+ title="$sep $1 $sep="
49
+ else
50
+ title="$sep $1 $sep"
51
+ fi
52
+ fi
53
+
54
+ color_echo purple "\n\n$sep_line\n$title\n$sep_line"
55
+ }
56
+
57
+ get_os() {
58
+ unameOut="$(uname -s)"
59
+ case "${unameOut}" in
60
+ Linux*) os=Linux;;
61
+ Darwin*) os=Mac;;
62
+ CYGWIN*) os=Cygwin;;
63
+ MINGW*) os=MinGw;;
64
+ MSYS_NT*) os=Git;;
65
+ *) os="UNKNOWN:${unameOut}"
66
+ esac
67
+ echo "${os}"
68
+ }
69
+
70
+ export OS
71
+ OS=$(get_os)
72
+
73
+ # gets a password and validates it by running a dummy cmd.
74
+ # parent process must call the function with `get_password || exit` to exit the script if `SUDO_PSW` is invalid
75
+ get_password() {
76
+ if [ -z "$SUDO_PSW" ]; then
77
+ read -s -p "Enter your sudo password: " SUDO_PSW
78
+ echo
79
+ echo "$SUDO_PSW" | sudo -S whoami > /dev/null 2>&1
80
+ if [ $? -ne 0 ]; then
81
+ echo "Invalid sudo password. Exiting..."
82
+ return 1
83
+ fi
84
+ return 0
85
+ fi
86
+ }
87
+
88
+ # the sed at the end removes trailing non-alphanumeric chars.
89
+ generate_random_string() {
90
+ echo "$(openssl rand -base64 32 | tr -d '/\n' | sed -r -e "s/[^a-zA-Z0-9]+$//")"
91
+ }
92
+
93
+ get_env_value() {
94
+ param=$1
95
+ env_file=$2
96
+ value=$(awk -F= -v param="$param" '/^[^#]/ && $1 == param {gsub(/"/, "", $2); print $2}' "$env_file")
97
+ echo "$value"
98
+ }
99
+
100
+ get_env_desc() {
101
+ current_line="$1"
102
+ prev_line="$2"
103
+ desc=""
104
+ if [[ $prev_line =~ ^# ]]; then
105
+ desc=$(echo "$prev_line" | sed 's/^#\s*//')
106
+ fi
107
+ echo "$desc"
108
+ }
109
+
110
+ ask() {
111
+ options=("yes" "no")
112
+ color_echo blue "$1"
113
+ answer=$(printf "%s\n" "${options[@]}" | fzy)
114
+ echo ""
115
+ if [ "$answer" = "no" ]; then
116
+ exit 1
117
+ fi
118
+ }
119
+
120
+ # float arithmetic comparison is not supported by bash and we need to use `bc`
121
+ # usage: if float_comparison "a >= b"; then... ; fi
122
+ float_comparison () {
123
+ expr="$1"
124
+ (( $(echo "$expr" |bc -l) ));
125
+ }
126
+
127
+ # sed replacements in place
128
+ # `sed -i` can't be used in the same way with Linux and Mac: it's `sed -i` on Linux, `sed -i ""` on Mac
129
+ sed_repl_inplace() {
130
+ sed_expr="$1"
131
+ file="$2"
132
+
133
+ if [ "$OS" = "Linux" ]; then
134
+ sed -i -e "$sed_expr" "$file"
135
+ else
136
+ sed -i "" -e "$sed_expr" "$file"
137
+ fi
138
+ }
139
+
140
+ # sudo does not inherit from bash functions so this is a copy of "sed_repl_inplace" with sudo privileges (see: https://stackoverflow.com/a/9448969)
141
+ sudo_sed_repl_inplace() {
142
+ sed_expr="$1"
143
+ file="$2"
144
+
145
+ if [ "$OS" = "Linux" ]; then
146
+ [ -n "$SUDO_PSW" ] && echo "$SUDO_PSW" | sudo -S sed -i -e "$sed_expr" "$file" || sudo sed -i -e "$sed_expr" "$file"
147
+ else
148
+ [ -n "$SUDO_PSW" ] && echo "$SUDO_PSW" | sudo -S sed -i "" -e "$sed_expr" "$file" || sudo sed -i "" -e "$sed_expr" "$file"
149
+ fi
150
+ }
151
+
152
+ # ed replacements to a new file
153
+ sed_repl_newfile() {
154
+ sed_expr="$1"
155
+ infile="$2"
156
+ outfile="$3"
157
+
158
+ sed "$sed_expr" "$infile" | tee "$outfile" > /dev/null
159
+ }
160
+
161
+ sudo_sed_repl_newfile() {
162
+ sed_expr="$1"
163
+ infile="$2"
164
+ outfile="$3"
165
+
166
+ sudo sed "$sed_expr" "$infile" | sudo tee "$outfile" > /dev/null
167
+ }
168
+
169
+ run_script() {
170
+ local script_name="$1"
171
+ local description="$2"
172
+ local SCRIPT_DIR=${3:-${SCRIPT_DIR}}
173
+ options=("yes" "no")
174
+
175
+ color_echo blue "Do you want to run $description?"
176
+ answer=$(printf "%s\n" "${options[@]}" | fzy)
177
+ echo ""
178
+ if [ "$answer" = "yes" ]; then
179
+ bash "$SCRIPT_DIR/$script_name" \
180
+ && color_echo green "$description completed successfully" \
181
+ || color_echo red "$description failed with exit code. Continuing..."
182
+ else
183
+ color_echo cyan "Skipping $description"
184
+ fi
185
+ echo ""
186
+ }
187
+
188
+ start_mongod() {
189
+ if ! systemctl is-active --quiet mongod;
190
+ then sudo systemctl start mongod;
191
+ fi;
192
+ }