does not make db tables
This commit is contained in:
parent
4c3ccaa7b4
commit
af6d37c7ca
|
|
@ -18,6 +18,8 @@
|
||||||
"@nestjs/typeorm": "^11.0.0",
|
"@nestjs/typeorm": "^11.0.0",
|
||||||
"class-transformer": "^0.5.1",
|
"class-transformer": "^0.5.1",
|
||||||
"class-validator": "^0.14.2",
|
"class-validator": "^0.14.2",
|
||||||
|
"glob": "^11.0.3",
|
||||||
|
"jsonwebtoken": "^9.0.2",
|
||||||
"libphonenumber-js": "^1.12.9",
|
"libphonenumber-js": "^1.12.9",
|
||||||
"mongodb": "^6.17.0",
|
"mongodb": "^6.17.0",
|
||||||
"mongoose": "^8.16.3",
|
"mongoose": "^8.16.3",
|
||||||
|
|
@ -38,6 +40,7 @@
|
||||||
"@swc/core": "^1.12.11",
|
"@swc/core": "^1.12.11",
|
||||||
"@types/express": "^5.0.3",
|
"@types/express": "^5.0.3",
|
||||||
"@types/jest": "^30.0.0",
|
"@types/jest": "^30.0.0",
|
||||||
|
"@types/jsonwebtoken": "^9.0.10",
|
||||||
"@types/node": "^24.0.13",
|
"@types/node": "^24.0.13",
|
||||||
"@types/supertest": "^6.0.3",
|
"@types/supertest": "^6.0.3",
|
||||||
"eslint": "^9.31.0",
|
"eslint": "^9.31.0",
|
||||||
|
|
@ -1381,7 +1384,6 @@
|
||||||
"version": "4.0.1",
|
"version": "4.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/@isaacs/balanced-match/-/balanced-match-4.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/@isaacs/balanced-match/-/balanced-match-4.0.1.tgz",
|
||||||
"integrity": "sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==",
|
"integrity": "sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==",
|
||||||
"dev": true,
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "20 || >=22"
|
"node": "20 || >=22"
|
||||||
}
|
}
|
||||||
|
|
@ -1390,7 +1392,6 @@
|
||||||
"version": "5.0.0",
|
"version": "5.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/@isaacs/brace-expansion/-/brace-expansion-5.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/@isaacs/brace-expansion/-/brace-expansion-5.0.0.tgz",
|
||||||
"integrity": "sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==",
|
"integrity": "sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==",
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@isaacs/balanced-match": "^4.0.1"
|
"@isaacs/balanced-match": "^4.0.1"
|
||||||
},
|
},
|
||||||
|
|
@ -2454,6 +2455,29 @@
|
||||||
"node": ">=4.0"
|
"node": ">=4.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@nestjs/cli/node_modules/glob": {
|
||||||
|
"version": "11.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/glob/-/glob-11.0.1.tgz",
|
||||||
|
"integrity": "sha512-zrQDm8XPnYEKawJScsnM0QzobJxlT/kHOOlRTio8IH/GrmxRE5fjllkzdaHclIuNjUQTJYH2xHNIGfdpJkDJUw==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"foreground-child": "^3.1.0",
|
||||||
|
"jackspeak": "^4.0.1",
|
||||||
|
"minimatch": "^10.0.0",
|
||||||
|
"minipass": "^7.1.2",
|
||||||
|
"package-json-from-dist": "^1.0.0",
|
||||||
|
"path-scurry": "^2.0.0"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"glob": "dist/esm/bin.mjs"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "20 || >=22"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/isaacs"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@nestjs/cli/node_modules/json-schema-traverse": {
|
"node_modules/@nestjs/cli/node_modules/json-schema-traverse": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
|
||||||
|
|
@ -2481,6 +2505,21 @@
|
||||||
"node": ">= 0.6"
|
"node": ">= 0.6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@nestjs/cli/node_modules/minimatch": {
|
||||||
|
"version": "10.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.0.3.tgz",
|
||||||
|
"integrity": "sha512-IPZ167aShDZZUMdRk66cyQAW3qr0WzbHkPdMYa8bzZhlHhO3jALbKdxcaak7W9FfT2rZNpQuUu4Od7ILEpXSaw==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@isaacs/brace-expansion": "^5.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "20 || >=22"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/isaacs"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@nestjs/cli/node_modules/schema-utils": {
|
"node_modules/@nestjs/cli/node_modules/schema-utils": {
|
||||||
"version": "4.3.2",
|
"version": "4.3.2",
|
||||||
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.2.tgz",
|
||||||
|
|
@ -3517,6 +3556,16 @@
|
||||||
"integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==",
|
"integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/jsonwebtoken": {
|
||||||
|
"version": "9.0.10",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.10.tgz",
|
||||||
|
"integrity": "sha512-asx5hIG9Qmf/1oStypjanR7iKTv0gXQ1Ov/jfrX6kS/EO0OFni8orbmGCn0672NHR3kXHwpAwR+B368ZGN/2rA==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@types/ms": "*",
|
||||||
|
"@types/node": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@types/methods": {
|
"node_modules/@types/methods": {
|
||||||
"version": "1.1.4",
|
"version": "1.1.4",
|
||||||
"resolved": "https://registry.npmjs.org/@types/methods/-/methods-1.1.4.tgz",
|
"resolved": "https://registry.npmjs.org/@types/methods/-/methods-1.1.4.tgz",
|
||||||
|
|
@ -3529,6 +3578,12 @@
|
||||||
"integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==",
|
"integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/ms": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"node_modules/@types/node": {
|
"node_modules/@types/node": {
|
||||||
"version": "24.0.13",
|
"version": "24.0.13",
|
||||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.0.13.tgz",
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.0.13.tgz",
|
||||||
|
|
@ -5435,6 +5490,11 @@
|
||||||
"node": "*"
|
"node": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/buffer-equal-constant-time": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA=="
|
||||||
|
},
|
||||||
"node_modules/buffer-from": {
|
"node_modules/buffer-from": {
|
||||||
"version": "1.1.2",
|
"version": "1.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
|
||||||
|
|
@ -6194,6 +6254,14 @@
|
||||||
"resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
|
||||||
"integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA=="
|
"integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA=="
|
||||||
},
|
},
|
||||||
|
"node_modules/ecdsa-sig-formatter": {
|
||||||
|
"version": "1.0.11",
|
||||||
|
"resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz",
|
||||||
|
"integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"safe-buffer": "^5.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/ee-first": {
|
"node_modules/ee-first": {
|
||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
|
||||||
|
|
@ -7372,14 +7440,13 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/glob": {
|
"node_modules/glob": {
|
||||||
"version": "11.0.1",
|
"version": "11.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/glob/-/glob-11.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/glob/-/glob-11.0.3.tgz",
|
||||||
"integrity": "sha512-zrQDm8XPnYEKawJScsnM0QzobJxlT/kHOOlRTio8IH/GrmxRE5fjllkzdaHclIuNjUQTJYH2xHNIGfdpJkDJUw==",
|
"integrity": "sha512-2Nim7dha1KVkaiF4q6Dj+ngPPMdfvLJEOpZk/jKiUAkqKebpGAWQXAq9z1xu9HKu5lWfqw/FASuccEjyznjPaA==",
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"foreground-child": "^3.1.0",
|
"foreground-child": "^3.3.1",
|
||||||
"jackspeak": "^4.0.1",
|
"jackspeak": "^4.1.1",
|
||||||
"minimatch": "^10.0.0",
|
"minimatch": "^10.0.3",
|
||||||
"minipass": "^7.1.2",
|
"minipass": "^7.1.2",
|
||||||
"package-json-from-dist": "^1.0.0",
|
"package-json-from-dist": "^1.0.0",
|
||||||
"path-scurry": "^2.0.0"
|
"path-scurry": "^2.0.0"
|
||||||
|
|
@ -7416,7 +7483,6 @@
|
||||||
"version": "10.0.3",
|
"version": "10.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.0.3.tgz",
|
||||||
"integrity": "sha512-IPZ167aShDZZUMdRk66cyQAW3qr0WzbHkPdMYa8bzZhlHhO3jALbKdxcaak7W9FfT2rZNpQuUu4Od7ILEpXSaw==",
|
"integrity": "sha512-IPZ167aShDZZUMdRk66cyQAW3qr0WzbHkPdMYa8bzZhlHhO3jALbKdxcaak7W9FfT2rZNpQuUu4Od7ILEpXSaw==",
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@isaacs/brace-expansion": "^5.0.0"
|
"@isaacs/brace-expansion": "^5.0.0"
|
||||||
},
|
},
|
||||||
|
|
@ -7942,7 +8008,6 @@
|
||||||
"version": "4.1.1",
|
"version": "4.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-4.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-4.1.1.tgz",
|
||||||
"integrity": "sha512-zptv57P3GpL+O0I7VdMJNBZCu+BPHVQUk55Ft8/QCJjTVxrnJHuVuX/0Bl2A6/+2oyR/ZMEuFKwmzqqZ/U5nPQ==",
|
"integrity": "sha512-zptv57P3GpL+O0I7VdMJNBZCu+BPHVQUk55Ft8/QCJjTVxrnJHuVuX/0Bl2A6/+2oyR/ZMEuFKwmzqqZ/U5nPQ==",
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@isaacs/cliui": "^8.0.2"
|
"@isaacs/cliui": "^8.0.2"
|
||||||
},
|
},
|
||||||
|
|
@ -8807,6 +8872,46 @@
|
||||||
"graceful-fs": "^4.1.6"
|
"graceful-fs": "^4.1.6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/jsonwebtoken": {
|
||||||
|
"version": "9.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz",
|
||||||
|
"integrity": "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"jws": "^3.2.2",
|
||||||
|
"lodash.includes": "^4.3.0",
|
||||||
|
"lodash.isboolean": "^3.0.3",
|
||||||
|
"lodash.isinteger": "^4.0.4",
|
||||||
|
"lodash.isnumber": "^3.0.3",
|
||||||
|
"lodash.isplainobject": "^4.0.6",
|
||||||
|
"lodash.isstring": "^4.0.1",
|
||||||
|
"lodash.once": "^4.0.0",
|
||||||
|
"ms": "^2.1.1",
|
||||||
|
"semver": "^7.5.4"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12",
|
||||||
|
"npm": ">=6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/jwa": {
|
||||||
|
"version": "1.4.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.2.tgz",
|
||||||
|
"integrity": "sha512-eeH5JO+21J78qMvTIDdBXidBd6nG2kZjg5Ohz/1fpa28Z4CcsWUzJ1ZZyFq/3z3N17aZy+ZuBoHljASbL1WfOw==",
|
||||||
|
"dependencies": {
|
||||||
|
"buffer-equal-constant-time": "^1.0.1",
|
||||||
|
"ecdsa-sig-formatter": "1.0.11",
|
||||||
|
"safe-buffer": "^5.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/jws": {
|
||||||
|
"version": "3.2.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz",
|
||||||
|
"integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==",
|
||||||
|
"dependencies": {
|
||||||
|
"jwa": "^1.4.1",
|
||||||
|
"safe-buffer": "^5.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/kareem": {
|
"node_modules/kareem": {
|
||||||
"version": "2.6.3",
|
"version": "2.6.3",
|
||||||
"resolved": "https://registry.npmjs.org/kareem/-/kareem-2.6.3.tgz",
|
"resolved": "https://registry.npmjs.org/kareem/-/kareem-2.6.3.tgz",
|
||||||
|
|
@ -8959,6 +9064,36 @@
|
||||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
||||||
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
|
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
|
||||||
},
|
},
|
||||||
|
"node_modules/lodash.includes": {
|
||||||
|
"version": "4.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz",
|
||||||
|
"integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w=="
|
||||||
|
},
|
||||||
|
"node_modules/lodash.isboolean": {
|
||||||
|
"version": "3.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz",
|
||||||
|
"integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg=="
|
||||||
|
},
|
||||||
|
"node_modules/lodash.isinteger": {
|
||||||
|
"version": "4.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz",
|
||||||
|
"integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA=="
|
||||||
|
},
|
||||||
|
"node_modules/lodash.isnumber": {
|
||||||
|
"version": "3.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz",
|
||||||
|
"integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw=="
|
||||||
|
},
|
||||||
|
"node_modules/lodash.isplainobject": {
|
||||||
|
"version": "4.0.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz",
|
||||||
|
"integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA=="
|
||||||
|
},
|
||||||
|
"node_modules/lodash.isstring": {
|
||||||
|
"version": "4.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz",
|
||||||
|
"integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw=="
|
||||||
|
},
|
||||||
"node_modules/lodash.memoize": {
|
"node_modules/lodash.memoize": {
|
||||||
"version": "4.1.2",
|
"version": "4.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz",
|
||||||
|
|
@ -8971,6 +9106,11 @@
|
||||||
"integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
|
"integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/lodash.once": {
|
||||||
|
"version": "4.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz",
|
||||||
|
"integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg=="
|
||||||
|
},
|
||||||
"node_modules/log-symbols": {
|
"node_modules/log-symbols": {
|
||||||
"version": "4.1.0",
|
"version": "4.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz",
|
||||||
|
|
@ -9791,7 +9931,6 @@
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.0.tgz",
|
||||||
"integrity": "sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg==",
|
"integrity": "sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg==",
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"lru-cache": "^11.0.0",
|
"lru-cache": "^11.0.0",
|
||||||
"minipass": "^7.1.2"
|
"minipass": "^7.1.2"
|
||||||
|
|
@ -9807,7 +9946,6 @@
|
||||||
"version": "11.1.0",
|
"version": "11.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.1.0.tgz",
|
||||||
"integrity": "sha512-QIXZUBJUx+2zHUdQujWejBkcD9+cs94tLn0+YL8UrCh+D5sCXZ4c7LaEH48pNwRY3MLDgqUFyhlCyjJPf1WP0A==",
|
"integrity": "sha512-QIXZUBJUx+2zHUdQujWejBkcD9+cs94tLn0+YL8UrCh+D5sCXZ4c7LaEH48pNwRY3MLDgqUFyhlCyjJPf1WP0A==",
|
||||||
"dev": true,
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "20 || >=22"
|
"node": "20 || >=22"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -27,14 +27,16 @@
|
||||||
"@nestjs/mongoose": "^11.0.3",
|
"@nestjs/mongoose": "^11.0.3",
|
||||||
"@nestjs/platform-express": "^11.1.3",
|
"@nestjs/platform-express": "^11.1.3",
|
||||||
"@nestjs/typeorm": "^11.0.0",
|
"@nestjs/typeorm": "^11.0.0",
|
||||||
"pg": "^8.11.3",
|
|
||||||
"class-transformer": "^0.5.1",
|
"class-transformer": "^0.5.1",
|
||||||
"class-validator": "^0.14.2",
|
"class-validator": "^0.14.2",
|
||||||
|
"glob": "^11.0.3",
|
||||||
|
"jsonwebtoken": "^9.0.2",
|
||||||
"libphonenumber-js": "^1.12.9",
|
"libphonenumber-js": "^1.12.9",
|
||||||
"mongodb": "^6.17.0",
|
"mongodb": "^6.17.0",
|
||||||
"mongoose": "^8.16.3",
|
"mongoose": "^8.16.3",
|
||||||
"mongoose-paginate-v2": "^1.9.1",
|
"mongoose-paginate-v2": "^1.9.1",
|
||||||
"nestjs-paginate": "^12.5.1",
|
"nestjs-paginate": "^12.5.1",
|
||||||
|
"pg": "^8.11.3",
|
||||||
"reflect-metadata": "^0.2.2",
|
"reflect-metadata": "^0.2.2",
|
||||||
"rxjs": "^7.8.2",
|
"rxjs": "^7.8.2",
|
||||||
"uuid": "^11.1.0"
|
"uuid": "^11.1.0"
|
||||||
|
|
@ -49,6 +51,7 @@
|
||||||
"@swc/core": "^1.12.11",
|
"@swc/core": "^1.12.11",
|
||||||
"@types/express": "^5.0.3",
|
"@types/express": "^5.0.3",
|
||||||
"@types/jest": "^30.0.0",
|
"@types/jest": "^30.0.0",
|
||||||
|
"@types/jsonwebtoken": "^9.0.10",
|
||||||
"@types/node": "^24.0.13",
|
"@types/node": "^24.0.13",
|
||||||
"@types/supertest": "^6.0.3",
|
"@types/supertest": "^6.0.3",
|
||||||
"eslint": "^9.31.0",
|
"eslint": "^9.31.0",
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ export abstract class BaseEntity {
|
||||||
updatedAt: Date;
|
updatedAt: Date;
|
||||||
|
|
||||||
@Column(() => Metadata)
|
@Column(() => Metadata)
|
||||||
metadata: Metadata;
|
metadata: Metadata = new Metadata();
|
||||||
|
|
||||||
@Column({
|
@Column({
|
||||||
type: 'enum',
|
type: 'enum',
|
||||||
|
|
|
||||||
|
|
@ -7,11 +7,11 @@ export class Metadata {
|
||||||
primary: true,
|
primary: true,
|
||||||
default: () => 'uuid_generate_v4()',
|
default: () => 'uuid_generate_v4()',
|
||||||
})
|
})
|
||||||
id: string;
|
id?: string;
|
||||||
|
|
||||||
@Column({
|
@Column({
|
||||||
type: 'jsonb',
|
type: 'jsonb',
|
||||||
default: () => "'[]'",
|
default: () => "'[]'",
|
||||||
})
|
})
|
||||||
entries: { key: string; value: string }[];
|
entries?: { key: string; value: string }[];
|
||||||
}
|
}
|
||||||
|
|
@ -1,12 +1,24 @@
|
||||||
import { Controller, Get } from '@nestjs/common';
|
import { Controller, Get } from '@nestjs/common';
|
||||||
import { AppService } from './app.service';
|
import { AppService } from './app.service';
|
||||||
|
import { InjectDataSource } from '@nestjs/typeorm';
|
||||||
|
import { DataSource } from 'typeorm';
|
||||||
@Controller()
|
@Controller()
|
||||||
export class AppController {
|
export class AppController {
|
||||||
constructor(private readonly appService: AppService) {}
|
constructor(private readonly appService: AppService,
|
||||||
|
@InjectDataSource() private readonly dataSource: DataSource) {}
|
||||||
@Get()
|
@Get()
|
||||||
getHello(): string {
|
getHello(): string {
|
||||||
return this.appService.getHello();
|
return this.appService.getHello();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Get('test-db')
|
||||||
|
async testDatabaseConnection() {
|
||||||
|
try {
|
||||||
|
await this.dataSource.query('SELECT 1');
|
||||||
|
return { message: 'Database connection successful' };
|
||||||
|
} catch (error) {
|
||||||
|
return { message: 'Database connection failed', error: error.message };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,39 @@
|
||||||
|
// src/config/database.config.ts
|
||||||
import { TypeOrmModuleOptions } from '@nestjs/typeorm';
|
import { TypeOrmModuleOptions } from '@nestjs/typeorm';
|
||||||
|
import { Participant } from '../participant/entity/participant.entity';
|
||||||
|
import { Metadata } from '../_core/entity/_metadata.entity';
|
||||||
|
import { Form } from '../form/entity/form.entity';
|
||||||
|
import { Realm } from '../realm/entity/realm.entity';
|
||||||
|
import { Question } from '../question/entity/question.entity';
|
||||||
|
import { Answer } from '../answer/entity/answer.entity';
|
||||||
|
import { Option } from '../option/entity/option.entity';
|
||||||
|
import { Attachment } from '../attachment/entity/attachment.entity';
|
||||||
|
import { FormSection } from '../formSection/entity/formSection.entity';
|
||||||
|
import { FormPage } from '../formPage/entity/formPage.entity';
|
||||||
|
import { FormResult } from '../formResult/entity/formResult.entity';
|
||||||
|
import { ParticipantGroup } from '../participantGroup/entity/participantGroup.entity';
|
||||||
|
|
||||||
export const typeOrmConfig: TypeOrmModuleOptions = {
|
export const typeOrmConfig: TypeOrmModuleOptions = {
|
||||||
type: 'postgres',
|
type: 'postgres',
|
||||||
host: 'localhost',
|
host: 'localhost',
|
||||||
port: 5432,
|
port: 5433,
|
||||||
username: 'your_username',
|
username: 'postgres',
|
||||||
password: 'your_password',
|
password: '1111',
|
||||||
database: 'your_database',
|
database: 'postgres',
|
||||||
entities: [__dirname + '/**/*.entity{.ts,.js}'],
|
entities: [
|
||||||
|
Participant,
|
||||||
|
Metadata,
|
||||||
|
Form,
|
||||||
|
Realm,
|
||||||
|
Question,
|
||||||
|
Answer,
|
||||||
|
Option,
|
||||||
|
Attachment,
|
||||||
|
FormSection,
|
||||||
|
FormPage,
|
||||||
|
FormResult,
|
||||||
|
ParticipantGroup,
|
||||||
|
],
|
||||||
synchronize: true,
|
synchronize: true,
|
||||||
extensions: ['uuid-ossp'],
|
logging: true,
|
||||||
};
|
};
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
import { Entity, Column, OneToMany } from 'typeorm';
|
import { Entity, Column, OneToMany, ManyToOne } from 'typeorm';
|
||||||
import { BaseEntity } from '../../_core/entity/_base.entity';
|
import { BaseEntity } from '../../_core/entity/_base.entity';
|
||||||
import { FormPage } from '../../formPage/entity/formPage.entity';
|
import { FormPage } from '../../formPage/entity/formPage.entity';
|
||||||
import { Participant } from '../../participant/entity/participant.entity'; // Assuming Participant entity exists
|
import { Participant } from '../../participant/entity/participant.entity';
|
||||||
|
import { Realm } from '../../realm/entity/realm.entity';
|
||||||
|
|
||||||
@Entity()
|
@Entity()
|
||||||
export class Form extends BaseEntity {
|
export class Form extends BaseEntity {
|
||||||
|
|
@ -19,6 +20,10 @@ export class Form extends BaseEntity {
|
||||||
@OneToMany(() => Participant, participant => participant.form, { cascade: true, eager: true })
|
@OneToMany(() => Participant, participant => participant.form, { cascade: true, eager: true })
|
||||||
participants: Participant[];
|
participants: Participant[];
|
||||||
|
|
||||||
|
// Many-to-One relationship with Realm (ADD THIS)
|
||||||
|
@ManyToOne(() => Realm, realm => realm.forms)
|
||||||
|
realm: Realm;
|
||||||
|
|
||||||
// Attachments are typically stored in a separate table and linked via a many-to-many or one-to-many
|
// Attachments are typically stored in a separate table and linked via a many-to-many or one-to-many
|
||||||
// For simplicity, if attachments are embedded, they would be handled like DisplayCondition in FormSection.
|
// For simplicity, if attachments are embedded, they would be handled like DisplayCondition in FormSection.
|
||||||
// If they are separate entities, they would need a relationship defined here.
|
// If they are separate entities, they would need a relationship defined here.
|
||||||
|
|
@ -28,8 +33,6 @@ export class Form extends BaseEntity {
|
||||||
// If you need attachments directly on Form, please provide the Attachment entity structure.
|
// If you need attachments directly on Form, please provide the Attachment entity structure.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// @Prop({
|
// @Prop({
|
||||||
// type: [AttachmentSchema],
|
// type: [AttachmentSchema],
|
||||||
// default: [],
|
// default: [],
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ import { IsNumber, IsString, IsOptional, IsUUID, ValidateNested, IsArray, IsDate
|
||||||
import { Type } from 'class-transformer';
|
import { Type } from 'class-transformer';
|
||||||
import { BaseDto } from '../../_core/dto/base.dto';
|
import { BaseDto } from '../../_core/dto/base.dto';
|
||||||
|
|
||||||
// DTO for Options
|
// DTO for Options (remains the same as it's validation-focused)
|
||||||
class CreateOptionsDto {
|
class CreateOptionsDto {
|
||||||
@IsString()
|
@IsString()
|
||||||
value: string;
|
value: string;
|
||||||
|
|
@ -11,7 +11,7 @@ class CreateOptionsDto {
|
||||||
count: number;
|
count: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
// DTO for Opinion
|
// DTO for Opinion (remains the same)
|
||||||
class CreateOpinionDto {
|
class CreateOpinionDto {
|
||||||
@ValidateNested()
|
@ValidateNested()
|
||||||
@Type(() => CreateOptionsDto)
|
@Type(() => CreateOptionsDto)
|
||||||
|
|
@ -21,7 +21,7 @@ class CreateOpinionDto {
|
||||||
questionId: string;
|
questionId: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Main DTO for creating a FormResult
|
// Main DTO for creating a FormResult (remains largely the same)
|
||||||
export class CreateFormResultDto extends BaseDto {
|
export class CreateFormResultDto extends BaseDto {
|
||||||
@IsNumber()
|
@IsNumber()
|
||||||
numParticipants: number;
|
numParticipants: number;
|
||||||
|
|
|
||||||
|
|
@ -1,98 +1,41 @@
|
||||||
import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
|
import { Entity, Column } from 'typeorm';
|
||||||
import { Document } from 'mongoose';
|
import { BaseEntity } from '../../_core/entity/_base.entity';
|
||||||
import { BaseEntity } from 'src/_core/entity/_base.entity';
|
|
||||||
import * as mongoosePaginate from 'mongoose-paginate-v2';
|
|
||||||
import { Attachment, AttachmentSchema } from '../../attachment/entity/attachment.entity';
|
|
||||||
import { Option, OptionSchema } from '../../option/entity/option.entity';
|
|
||||||
import { UUID } from 'mongodb';
|
|
||||||
|
|
||||||
// Sub-schema for Options
|
// Options class (embedded)
|
||||||
@Schema({ _id: false, id: false })
|
export class Options {
|
||||||
class Options {
|
@Column()
|
||||||
@Prop({
|
|
||||||
type: String,
|
|
||||||
required: true,
|
|
||||||
})
|
|
||||||
value: string;
|
value: string;
|
||||||
|
|
||||||
@Prop({
|
@Column({ type: 'int', default: 0 })
|
||||||
type: Number,
|
|
||||||
required: true,
|
|
||||||
min: 0,
|
|
||||||
default: 0
|
|
||||||
})
|
|
||||||
count: number;
|
count: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const OptionsSchema = SchemaFactory.createForClass(Options);
|
// Opinion class (embedded)
|
||||||
|
export class Opinion {
|
||||||
// Sub-schema for Opinion
|
@Column(() => Options)
|
||||||
@Schema({ _id: false, id: false })
|
|
||||||
class Opinion {
|
|
||||||
@Prop({
|
|
||||||
type: OptionsSchema,
|
|
||||||
required: true,
|
|
||||||
})
|
|
||||||
options: Options;
|
options: Options;
|
||||||
|
|
||||||
@Prop({
|
@Column({
|
||||||
type: UUID,
|
type: 'uuid',
|
||||||
required: true,
|
unique: true,
|
||||||
})
|
})
|
||||||
questionId: string;
|
questionId: string;
|
||||||
}
|
}
|
||||||
export const OpinionSchema = SchemaFactory.createForClass(Opinion);
|
|
||||||
|
|
||||||
|
@Entity()
|
||||||
@Schema({ _id: false, id: false }) // Disable _id and virtual id
|
|
||||||
export class FormResult extends BaseEntity {
|
export class FormResult extends BaseEntity {
|
||||||
@Prop({
|
@Column({ type: 'int', default: 0 })
|
||||||
type: Number,
|
numParticipants: number;
|
||||||
required: true,
|
|
||||||
min: 0,
|
|
||||||
default: 0,
|
|
||||||
})
|
|
||||||
numParticipants: string;
|
|
||||||
|
|
||||||
@Prop({
|
@Column({ type: 'int', default: 0 })
|
||||||
type: Number,
|
numQuestions: number;
|
||||||
required: true,
|
|
||||||
min: 0,
|
|
||||||
default: 0,
|
|
||||||
})
|
|
||||||
numQuestions: string;
|
|
||||||
|
|
||||||
@Prop({
|
@Column({ type: 'int', default: 0 })
|
||||||
type: Number,
|
numAnswers: number;
|
||||||
required: true,
|
|
||||||
min: 0,
|
|
||||||
default: 0,
|
|
||||||
})
|
|
||||||
numAnswers: string;
|
|
||||||
|
|
||||||
@Prop({
|
@Column({ type: 'int', default: 0 })
|
||||||
type: Number,
|
numComplete: number;
|
||||||
required: true,
|
|
||||||
min: 0,
|
|
||||||
default: 0,
|
|
||||||
})
|
|
||||||
numComplete: string; // number of people who completed this form
|
|
||||||
|
|
||||||
@Prop({
|
@Column(() => Opinion)
|
||||||
type: [OpinionSchema],
|
|
||||||
default: [],
|
|
||||||
})
|
|
||||||
opinions: Opinion[];
|
opinions: Opinion[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export type FormResultDocument = FormResult & Document;
|
|
||||||
export const FormResultSchema = SchemaFactory.createForClass(FormResult);
|
|
||||||
FormResultSchema.plugin(mongoosePaginate);
|
|
||||||
|
|
||||||
// Transform the output to remove the internal '_id'
|
|
||||||
FormResultSchema.set('toJSON', {
|
|
||||||
transform: (doc: FormResultDocument, ret: FormResult & { _id?: any }) => {
|
|
||||||
delete ret._id;
|
|
||||||
return ret;
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,6 @@ export class FormResultController {
|
||||||
@Query('page') page: string = '1',
|
@Query('page') page: string = '1',
|
||||||
@Query('limit') limit: string = '10',
|
@Query('limit') limit: string = '10',
|
||||||
) {
|
) {
|
||||||
// The service returns the full pagination object
|
|
||||||
return this.formResultService.findAll(parseInt(page, 10), parseInt(limit, 10));
|
return this.formResultService.findAll(parseInt(page, 10), parseInt(limit, 10));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,13 @@
|
||||||
import { Module } from '@nestjs/common';
|
import { Module } from '@nestjs/common';
|
||||||
import { MongooseModule } from '@nestjs/mongoose';
|
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||||
import { FormResultService } from './formResult.service';
|
import { FormResultService } from './formResult.service';
|
||||||
import { FormResultController } from './formResult.controller';
|
import { FormResultController } from './formResult.controller';
|
||||||
import { FormResult, FormResultSchema } from './entity/formResult.entity';
|
import { FormResult } from './entity/formResult.entity';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [
|
imports: [
|
||||||
MongooseModule.forFeature([
|
TypeOrmModule.forFeature([
|
||||||
{ name: FormResult.name, schema: FormResultSchema },
|
FormResult,
|
||||||
]),
|
]),
|
||||||
],
|
],
|
||||||
controllers: [FormResultController],
|
controllers: [FormResultController],
|
||||||
|
|
|
||||||
|
|
@ -1,25 +1,22 @@
|
||||||
import { Injectable, NotFoundException } from '@nestjs/common';
|
import { Injectable, NotFoundException } from '@nestjs/common';
|
||||||
import { InjectModel } from '@nestjs/mongoose';
|
import { InjectRepository } from '@nestjs/typeorm';
|
||||||
import { Model } from 'mongoose';
|
import { Repository } from 'typeorm';
|
||||||
import { FormResult, FormResultDocument } from './entity/formResult.entity';
|
import { FormResult } from './entity/formResult.entity';
|
||||||
import { CreateFormResultDto } from './dto/create-formResult.dto';
|
import { CreateFormResultDto } from './dto/create-formResult.dto';
|
||||||
import { UpdateFormResultDto } from './dto/update-formResult.dto';
|
import { UpdateFormResultDto } from './dto/update-formResult.dto';
|
||||||
import { PaginateModel } from '../participant/participant.service';
|
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class FormResultService {
|
export class FormResultService {
|
||||||
constructor(
|
constructor(
|
||||||
@InjectModel(FormResult.name)
|
@InjectRepository(FormResult)
|
||||||
private readonly formResultModel: PaginateModel<FormResultDocument>,
|
private readonly formResultRepo: Repository<FormResult>,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
async create(data: CreateFormResultDto): Promise<FormResult> {
|
async create(data: CreateFormResultDto): Promise<FormResult> {
|
||||||
const formResult = new this.formResultModel({
|
const formResult = this.formResultRepo.create({
|
||||||
...data,
|
...data,
|
||||||
id: data.id || undefined, // Let BaseEntity generate UUID if not provided
|
|
||||||
metadata: data.metadata || { entries: [] },
|
|
||||||
});
|
});
|
||||||
return formResult.save();
|
return await this.formResultRepo.save(formResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
async findAll(
|
async findAll(
|
||||||
|
|
@ -36,18 +33,31 @@ export class FormResultService {
|
||||||
nextPage: number | null;
|
nextPage: number | null;
|
||||||
prevPage: number | null;
|
prevPage: number | null;
|
||||||
}> {
|
}> {
|
||||||
// Selects all fields from the FormResult entity for the response
|
const [docs, totalDocs] = await this.formResultRepo.findAndCount({
|
||||||
return this.formResultModel.paginate(
|
skip: (page - 1) * limit,
|
||||||
{},
|
take: limit,
|
||||||
{ page, limit, lean: true },
|
// No specific relations needed here unless FormResult links to other entities
|
||||||
);
|
});
|
||||||
|
|
||||||
|
const totalPages = Math.ceil(totalDocs / limit);
|
||||||
|
return {
|
||||||
|
docs,
|
||||||
|
totalDocs,
|
||||||
|
limit,
|
||||||
|
page,
|
||||||
|
totalPages,
|
||||||
|
hasNextPage: page < totalPages,
|
||||||
|
hasPrevPage: page > 1,
|
||||||
|
nextPage: page < totalPages ? page + 1 : null,
|
||||||
|
prevPage: page > 1 ? page - 1 : null,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
async findById(id: string): Promise<FormResult | null> {
|
async findById(id: string): Promise<FormResult | null> {
|
||||||
const formResult = await this.formResultModel
|
const formResult = await this.formResultRepo.findOne({
|
||||||
.findOne({ id })
|
where: { id },
|
||||||
.lean()
|
// No specific relations needed here unless FormResult links to other entities
|
||||||
.exec();
|
});
|
||||||
if (!formResult) {
|
if (!formResult) {
|
||||||
throw new NotFoundException(`FormResult with ID "${id}" not found`);
|
throw new NotFoundException(`FormResult with ID "${id}" not found`);
|
||||||
}
|
}
|
||||||
|
|
@ -58,24 +68,20 @@ export class FormResultService {
|
||||||
id: string,
|
id: string,
|
||||||
data: UpdateFormResultDto,
|
data: UpdateFormResultDto,
|
||||||
): Promise<FormResult | null> {
|
): Promise<FormResult | null> {
|
||||||
const updatedFormResult = await this.formResultModel
|
const result = await this.formResultRepo.update(
|
||||||
.findOneAndUpdate(
|
{ id },
|
||||||
{ id },
|
{ ...data, updatedAt: new Date() },
|
||||||
{ $set: { ...data, updatedAt: new Date() } },
|
);
|
||||||
{ new: true },
|
|
||||||
)
|
|
||||||
.lean()
|
|
||||||
.exec();
|
|
||||||
|
|
||||||
if (!updatedFormResult) {
|
if (result.affected === 0) {
|
||||||
throw new NotFoundException(`FormResult with ID "${id}" not found`);
|
throw new NotFoundException(`FormResult with ID "${id}" not found`);
|
||||||
}
|
}
|
||||||
return updatedFormResult;
|
return await this.findById(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
async remove(id: string): Promise<void> {
|
async remove(id: string): Promise<void> {
|
||||||
const result = await this.formResultModel.deleteOne({ id }).exec();
|
const result = await this.formResultRepo.delete({ id });
|
||||||
if (result.deletedCount === 0) {
|
if (result.affected === 0) {
|
||||||
throw new NotFoundException(`FormResult with ID "${id}" not found`);
|
throw new NotFoundException(`FormResult with ID "${id}" not found`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import { Column, Entity, ManyToOne } from 'typeorm';
|
import { Column, Entity, ManyToOne } from 'typeorm';
|
||||||
import { BaseEntity } from 'src/_core/entity/_base.entity';
|
import { BaseEntity } from 'src/_core/entity/_base.entity';
|
||||||
import { Form } from 'src/form/entity/form.entity';
|
import { Form } from 'src/form/entity/form.entity';
|
||||||
|
import { Realm } from '../../realm/entity/realm.entity';
|
||||||
|
|
||||||
@Entity({ name: 'participants' })
|
@Entity({ name: 'participants' })
|
||||||
export class Participant extends BaseEntity {
|
export class Participant extends BaseEntity {
|
||||||
|
|
@ -23,4 +24,8 @@ export class Participant extends BaseEntity {
|
||||||
// Many-to-One relationship with Form
|
// Many-to-One relationship with Form
|
||||||
@ManyToOne(() => Form, form => form.participants)
|
@ManyToOne(() => Form, form => form.participants)
|
||||||
form: Form;
|
form: Form;
|
||||||
|
|
||||||
|
// Many-to-One relationship with Realm (if a participant belongs to a realm)
|
||||||
|
@ManyToOne(() => Realm, realm => realm.participants)
|
||||||
|
realm: Realm;
|
||||||
}
|
}
|
||||||
|
|
@ -4,6 +4,8 @@ import { Repository } from 'typeorm';
|
||||||
import { CreateParticipantDto } from './dto/create-participant.dto';
|
import { CreateParticipantDto } from './dto/create-participant.dto';
|
||||||
import { Participant } from './entity/participant.entity';
|
import { Participant } from './entity/participant.entity';
|
||||||
import { UpdateParticipantDto } from './dto/update-participant.dto';
|
import { UpdateParticipantDto } from './dto/update-participant.dto';
|
||||||
|
import axios from 'axios';
|
||||||
|
import { decode } from 'jsonwebtoken';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class ParticipantService {
|
export class ParticipantService {
|
||||||
|
|
@ -14,11 +16,42 @@ export class ParticipantService {
|
||||||
|
|
||||||
async create(data: CreateParticipantDto): Promise<Participant> {
|
async create(data: CreateParticipantDto): Promise<Participant> {
|
||||||
try {
|
try {
|
||||||
|
// Make the authentication request to get the token
|
||||||
|
const authResponse = await axios.post(
|
||||||
|
'https://auth.didvan.com/realms/didvan/protocol/openid-connect/token',
|
||||||
|
new URLSearchParams({
|
||||||
|
client_id: 'didvan-app',
|
||||||
|
username: 'alice',
|
||||||
|
password: 'developer_password',
|
||||||
|
grant_type: 'password',
|
||||||
|
}),
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
'content-type': 'application/x-www-form-urlencoded',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
// Decode the access token to extract the 'sub' claim
|
||||||
|
const token = authResponse.data.access_token;
|
||||||
|
const decodedToken: any = decode(token);
|
||||||
|
if (!decodedToken || !decodedToken.sub) {
|
||||||
|
throw new InternalServerErrorException('Failed to decode token or extract sub');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the participant with the 'sub' as the ID and userId
|
||||||
const participant = this.participantRepository.create({
|
const participant = this.participantRepository.create({
|
||||||
...data,
|
...data,
|
||||||
metadata: data.metadata || { entries: [] },
|
id: decodedToken.sub, // Set the ID from the token's sub
|
||||||
|
userId: decodedToken.sub, // Set userId to the same sub
|
||||||
|
metadata: data.metadata
|
||||||
|
? { entries: data.metadata.entries } // Ensure metadata is properly formatted
|
||||||
|
: { entries: [] },
|
||||||
status: data.status || 'active',
|
status: data.status || 'active',
|
||||||
|
// Note: form and realm are not set as they are optional (ManyToOne)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Save the participant to the database
|
||||||
return await this.participantRepository.save(participant);
|
return await this.participantRepository.save(participant);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new InternalServerErrorException(`Failed to create participant: ${error.message}`);
|
throw new InternalServerErrorException(`Failed to create participant: ${error.message}`);
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,8 @@
|
||||||
import { IsString, IsOptional, IsUUID, ValidateNested, IsArray, IsEnum, IsDateString } from 'class-validator';
|
import { IsString, IsOptional, ValidateNested, IsArray } from 'class-validator';
|
||||||
import { Type } from 'class-transformer';
|
import { Type } from 'class-transformer';
|
||||||
import { BaseDto } from '../../_core/dto/base.dto';
|
import { BaseDto } from '../../_core/dto/base.dto';
|
||||||
import { CreateAttachmentDto } from '../../attachment/dto/create_attachment.dto';
|
|
||||||
import { CreateQuestionDto } from '../../question/dto/create-question.dto';
|
|
||||||
import { CreateFormPageDto } from '../../formPage/dto/create-formPage.dto';
|
|
||||||
import { CreateParticipantDto } from '../../participant/dto/create-participant.dto';
|
|
||||||
import { CreateFormDto } from '../../form/dto/create-form.dto';
|
import { CreateFormDto } from '../../form/dto/create-form.dto';
|
||||||
|
import { CreateParticipantDto } from '../../participant/dto/create-participant.dto';
|
||||||
|
|
||||||
export class CreateRealmDto extends BaseDto {
|
export class CreateRealmDto extends BaseDto {
|
||||||
@IsString()
|
@IsString()
|
||||||
|
|
@ -23,10 +20,9 @@ export class CreateRealmDto extends BaseDto {
|
||||||
@IsArray()
|
@IsArray()
|
||||||
@ValidateNested({ each: true })
|
@ValidateNested({ each: true })
|
||||||
@Type(() => CreateParticipantDto)
|
@Type(() => CreateParticipantDto)
|
||||||
participant: CreateParticipantDto[];
|
participants: CreateParticipantDto[]; // Changed from 'participant' to 'participants' for consistency with array
|
||||||
|
|
||||||
@IsArray()
|
@ValidateNested() // Not IsArray, as it's a single owner
|
||||||
@ValidateNested({ each: true })
|
|
||||||
@Type(() => CreateParticipantDto)
|
@Type(() => CreateParticipantDto)
|
||||||
owner: CreateParticipantDto;
|
owner: CreateParticipantDto;
|
||||||
}
|
}
|
||||||
|
|
@ -1,58 +1,27 @@
|
||||||
import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
|
import { Entity, Column, OneToMany, OneToOne, JoinColumn } from 'typeorm';
|
||||||
import { Document } from 'mongoose';
|
import { BaseEntity } from '../../_core/entity/_base.entity';
|
||||||
import { BaseEntity } from 'src/_core/entity/_base.entity';
|
import { Form } from '../../form/entity/form.entity';
|
||||||
import * as mongoosePaginate from 'mongoose-paginate-v2';
|
import { Participant } from '../../participant/entity/participant.entity';
|
||||||
import { Attachment, AttachmentSchema } from '../../attachment/entity/attachment.entity';
|
|
||||||
import { Option, OptionSchema } from '../../option/entity/option.entity';
|
|
||||||
import { Answer, AnswerSchema } from '../../answer/entity/answer.entity';
|
|
||||||
import { Question, QuestionSchema } from '../../question/entity/question.entity';
|
|
||||||
import { Form, FormSchema } from '../../form/entity/form.entity';
|
|
||||||
import { Participant, ParticipantSchema } from '../../participant/entity/participant.entity';
|
|
||||||
|
|
||||||
@Schema({ _id: false, id: false }) // Disable _id and virtual id
|
@Entity()
|
||||||
export class Realm extends BaseEntity {
|
export class Realm extends BaseEntity {
|
||||||
@Prop({
|
@Column()
|
||||||
type: String,
|
|
||||||
required: true,
|
|
||||||
})
|
|
||||||
title: string;
|
title: string;
|
||||||
|
|
||||||
@Prop({
|
@Column()
|
||||||
type: String,
|
|
||||||
required: true,
|
|
||||||
})
|
|
||||||
description: string;
|
description: string;
|
||||||
|
|
||||||
@Prop({
|
// One-to-Many relationship with Form
|
||||||
type: [FormSchema],
|
@OneToMany(() => Form, form => form.realm, { cascade: true, eager: true })
|
||||||
default: [],
|
|
||||||
})
|
|
||||||
forms: Form[];
|
forms: Form[];
|
||||||
|
|
||||||
@Prop({
|
// One-to-Many relationship with Participant (for general participants in the realm)
|
||||||
type: [ParticipantSchema],
|
@OneToMany(() => Participant, participant => participant.realm, { cascade: true, eager: true })
|
||||||
default: [],
|
|
||||||
})
|
|
||||||
participants: Participant[];
|
participants: Participant[];
|
||||||
|
|
||||||
@Prop({
|
// One-to-One relationship with Participant (for the owner of the realm)
|
||||||
type: ParticipantSchema,
|
// Assuming 'owner' is a single Participant entity
|
||||||
})
|
@OneToOne(() => Participant, { cascade: true, eager: true })
|
||||||
|
@JoinColumn() // This column will be added to the Realm table to store the owner's ID
|
||||||
owner: Participant;
|
owner: Participant;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export type RealmDocument = Realm & Document;
|
|
||||||
export const RealmSchema = SchemaFactory.createForClass(Realm);
|
|
||||||
RealmSchema.plugin(mongoosePaginate);
|
|
||||||
|
|
||||||
// Transform the output to remove the internal '_id'
|
|
||||||
RealmSchema.set('toJSON', {
|
|
||||||
transform: (doc: RealmDocument, ret: Realm & { _id?: any }) => {
|
|
||||||
delete ret._id;
|
|
||||||
return ret;
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,6 @@ export class RealmController {
|
||||||
@Query('page') page: string = '1',
|
@Query('page') page: string = '1',
|
||||||
@Query('limit') limit: string = '10',
|
@Query('limit') limit: string = '10',
|
||||||
) {
|
) {
|
||||||
// The service returns the full pagination object
|
|
||||||
return this.realmService.findAll(parseInt(page, 10), parseInt(limit, 10));
|
return this.realmService.findAll(parseInt(page, 10), parseInt(limit, 10));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,29 @@
|
||||||
import { Module } from '@nestjs/common';
|
import { Module } from '@nestjs/common';
|
||||||
import { MongooseModule } from '@nestjs/mongoose';
|
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||||
import { RealmService } from './realm.service';
|
import { RealmService } from './realm.service';
|
||||||
import { RealmController } from './realm.controller';
|
import { RealmController } from './realm.controller';
|
||||||
import { Realm, RealmSchema } from './entity/realm.entity';
|
import { Realm } from './entity/realm.entity';
|
||||||
|
import { Form } from '../form/entity/form.entity';
|
||||||
|
import { FormPage } from '../formPage/entity/formPage.entity';
|
||||||
|
import { FormSection } from '../formSection/entity/formSection.entity';
|
||||||
|
import { Attachment } from '../attachment/entity/attachment.entity';
|
||||||
|
import { Question } from '../question/entity/question.entity';
|
||||||
|
import { Answer } from '../answer/entity/answer.entity';
|
||||||
|
import { Option } from '../option/entity/option.entity';
|
||||||
|
import { Participant } from '../participant/entity/participant.entity';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [
|
imports: [
|
||||||
MongooseModule.forFeature([
|
TypeOrmModule.forFeature([
|
||||||
{ name: Realm.name, schema: RealmSchema },
|
Realm,
|
||||||
|
Form,
|
||||||
|
FormPage,
|
||||||
|
FormSection,
|
||||||
|
Attachment,
|
||||||
|
Question,
|
||||||
|
Answer,
|
||||||
|
Option,
|
||||||
|
Participant,
|
||||||
]),
|
]),
|
||||||
],
|
],
|
||||||
controllers: [RealmController],
|
controllers: [RealmController],
|
||||||
|
|
|
||||||
|
|
@ -1,25 +1,21 @@
|
||||||
|
// src/realm/realm.service.ts
|
||||||
import { Injectable, NotFoundException } from '@nestjs/common';
|
import { Injectable, NotFoundException } from '@nestjs/common';
|
||||||
import { InjectModel } from '@nestjs/mongoose';
|
import { InjectRepository } from '@nestjs/typeorm';
|
||||||
import { Model } from 'mongoose';
|
import { Repository } from 'typeorm';
|
||||||
import { Realm, RealmDocument } from './entity/realm.entity';
|
import { Realm } from './entity/realm.entity';
|
||||||
import { CreateRealmDto } from './dto/create-realm.dto';
|
import { CreateRealmDto } from './dto/create-realm.dto';
|
||||||
import { UpdateRealmDto } from './dto/update-realm.dto';
|
import { UpdateRealmDto } from './dto/update-realm.dto';
|
||||||
import { PaginateModel } from '../participant/participant.service';
|
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class RealmService {
|
export class RealmService {
|
||||||
constructor(
|
constructor(
|
||||||
@InjectModel(Realm.name)
|
@InjectRepository(Realm)
|
||||||
private readonly realmModel: PaginateModel<RealmDocument>,
|
private readonly realmRepo: Repository<Realm>,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
async create(data: CreateRealmDto): Promise<Realm> {
|
async create(data: CreateRealmDto): Promise<Realm> {
|
||||||
const realm = new this.realmModel({
|
const realm = this.realmRepo.create({ ...data });
|
||||||
...data,
|
return await this.realmRepo.save(realm);
|
||||||
id: data.id || undefined, // Let BaseEntity generate UUID if not provided
|
|
||||||
metadata: data.metadata || { entries: [] },
|
|
||||||
});
|
|
||||||
return realm.save();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async findAll(
|
async findAll(
|
||||||
|
|
@ -36,18 +32,51 @@ export class RealmService {
|
||||||
nextPage: number | null;
|
nextPage: number | null;
|
||||||
prevPage: number | null;
|
prevPage: number | null;
|
||||||
}> {
|
}> {
|
||||||
// Selects all fields from the Realm entity for the response
|
const [docs, totalDocs] = await this.realmRepo.findAndCount({
|
||||||
return this.realmModel.paginate(
|
skip: (page - 1) * limit,
|
||||||
{},
|
take: limit,
|
||||||
{ page, limit, lean: true },
|
relations: [
|
||||||
);
|
'forms',
|
||||||
|
'forms.pages',
|
||||||
|
'forms.pages.formSections',
|
||||||
|
'forms.pages.formSections.attachments',
|
||||||
|
'forms.pages.formSections.questions',
|
||||||
|
'forms.pages.formSections.questions.options',
|
||||||
|
'forms.pages.formSections.questions.answers',
|
||||||
|
'participants',
|
||||||
|
'owner',
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
const totalPages = Math.ceil(totalDocs / limit);
|
||||||
|
return {
|
||||||
|
docs,
|
||||||
|
totalDocs,
|
||||||
|
limit,
|
||||||
|
page,
|
||||||
|
totalPages,
|
||||||
|
hasNextPage: page < totalPages,
|
||||||
|
hasPrevPage: page > 1,
|
||||||
|
nextPage: page < totalPages ? page + 1 : null,
|
||||||
|
prevPage: page > 1 ? page - 1 : null,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
async findById(id: string): Promise<Realm | null> {
|
async findById(id: string): Promise<Realm | null> {
|
||||||
const realm = await this.realmModel
|
const realm = await this.realmRepo.findOne({
|
||||||
.findOne({ id })
|
where: { id },
|
||||||
.lean()
|
relations: [
|
||||||
.exec();
|
'forms',
|
||||||
|
'forms.pages',
|
||||||
|
'forms.pages.formSections',
|
||||||
|
'forms.pages.formSections.attachments',
|
||||||
|
'forms.pages.formSections.questions',
|
||||||
|
'forms.pages.formSections.questions.options',
|
||||||
|
'forms.pages.formSections.questions.answers',
|
||||||
|
'participants',
|
||||||
|
'owner',
|
||||||
|
],
|
||||||
|
});
|
||||||
if (!realm) {
|
if (!realm) {
|
||||||
throw new NotFoundException(`Realm with ID "${id}" not found`);
|
throw new NotFoundException(`Realm with ID "${id}" not found`);
|
||||||
}
|
}
|
||||||
|
|
@ -58,24 +87,20 @@ export class RealmService {
|
||||||
id: string,
|
id: string,
|
||||||
data: UpdateRealmDto,
|
data: UpdateRealmDto,
|
||||||
): Promise<Realm | null> {
|
): Promise<Realm | null> {
|
||||||
const updatedRealm = await this.realmModel
|
const result = await this.realmRepo.update(
|
||||||
.findOneAndUpdate(
|
{ id },
|
||||||
{ id },
|
{ ...data, updatedAt: new Date() },
|
||||||
{ $set: { ...data, updatedAt: new Date() } },
|
);
|
||||||
{ new: true },
|
|
||||||
)
|
|
||||||
.lean()
|
|
||||||
.exec();
|
|
||||||
|
|
||||||
if (!updatedRealm) {
|
if (result.affected === 0) {
|
||||||
throw new NotFoundException(`Realm with ID "${id}" not found`);
|
throw new NotFoundException(`Realm with ID "${id}" not found`);
|
||||||
}
|
}
|
||||||
return updatedRealm;
|
return await this.findById(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
async remove(id: string): Promise<void> {
|
async remove(id: string): Promise<void> {
|
||||||
const result = await this.realmModel.deleteOne({ id }).exec();
|
const result = await this.realmRepo.delete({ id });
|
||||||
if (result.deletedCount === 0) {
|
if (result.affected === 0) {
|
||||||
throw new NotFoundException(`Realm with ID "${id}" not found`);
|
throw new NotFoundException(`Realm with ID "${id}" not found`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue