From 73e8fc71bb67db9710a11286011a3839dfbeddab Mon Sep 17 00:00:00 2001 From: radmehr Date: Tue, 25 Aug 2026 23:38:24 +0330 Subject: [PATCH 1/4] debug server --- src/common/filters/global-exception.filter.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/common/filters/global-exception.filter.ts b/src/common/filters/global-exception.filter.ts index 7c24442..b7a109a 100644 --- a/src/common/filters/global-exception.filter.ts +++ b/src/common/filters/global-exception.filter.ts @@ -46,10 +46,10 @@ export class GlobalExceptionFilter implements ExceptionFilter { message, path: request.url, timestamp: new Date().toISOString(), - ...(process.env.NODE_ENV !== 'production' && { - raw: exceptionResponse, - stack: exception instanceof Error ? exception.stack : undefined, - }), + // ...(process.env.NODE_ENV !== 'production' && { + raw: exceptionResponse, + stack: exception instanceof Error ? exception.stack : undefined, + // }), }); } } From 7dd9206ca6794851cf379a5fbc9c7c2410da7ec9 Mon Sep 17 00:00:00 2001 From: radmehr Date: Wed, 26 Aug 2026 08:53:25 +0330 Subject: [PATCH 2/4] feat: add debug flag --- src/modules/tests/providers/tests-query.provider.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/modules/tests/providers/tests-query.provider.ts b/src/modules/tests/providers/tests-query.provider.ts index 4ac725f..28092d3 100644 --- a/src/modules/tests/providers/tests-query.provider.ts +++ b/src/modules/tests/providers/tests-query.provider.ts @@ -61,6 +61,10 @@ export class TestsQueryProvider { order: { createdAt: 'DESC' }, }); } catch (err) { + console.error('========== DATABASE ERROR =========='); + console.error(err); + console.error('===================================='); + throw new AppTimeoutException(err); } } From dd9a31278e980a18ef334e35aa5a567d8d12e4f8 Mon Sep 17 00:00:00 2001 From: radmehr Date: Fri, 28 Aug 2026 13:58:51 +0330 Subject: [PATCH 3/4] test: testing system and fix bugs --- src/i18n/en/submissions.json | 2 +- .../http/admin-choices.post.endpoints.http | 8 ++++---- ...in-question-transitions.delete.endpoints.http | 3 +++ ...min-question-transitions.patch.endpoints.http | 7 +++++++ ...dmin-question-transitions.post.endpoints.http | 11 ++++++----- .../http/admin-questions.post.endpoints.http | 16 ++++++++-------- .../tests/http/admin-tests.get.endpoints.http | 2 +- .../tests/http/admin-tests.patch.endpoints.http | 7 ++++--- .../tests/http/admin-tests.post.endpoints.http | 4 ++-- .../http/submissions.post.endpoints.http | 9 +++++---- .../providers/start/start-submission.provider.ts | 1 - .../validators/submission-answer.validator.ts | 10 +++++++--- 12 files changed, 48 insertions(+), 32 deletions(-) create mode 100644 src/modules/admin/question-transitions/http/admin-question-transitions.delete.endpoints.http create mode 100644 src/modules/admin/question-transitions/http/admin-question-transitions.patch.endpoints.http diff --git a/src/i18n/en/submissions.json b/src/i18n/en/submissions.json index cf6b749..a061dab 100644 --- a/src/i18n/en/submissions.json +++ b/src/i18n/en/submissions.json @@ -9,7 +9,7 @@ }, "errors": { "alreadyTookTest": "You already took this test.", - "choiceNumericConstraint": "You must send either choiceId or numericValue.", + "choiceNumericConstraint": "You must send either choiceId, choiceIds or numericValue.", "emptyNumericValue": "A numeric value should be provided as answer.", "numericValueRange": "Numeric value is out of specified range.", "emptyChoiceId": "Choice Id should be provided as answer.", diff --git a/src/modules/admin/choices/http/admin-choices.post.endpoints.http b/src/modules/admin/choices/http/admin-choices.post.endpoints.http index 58d8ab0..78089c9 100644 --- a/src/modules/admin/choices/http/admin-choices.post.endpoints.http +++ b/src/modules/admin/choices/http/admin-choices.post.endpoints.http @@ -3,9 +3,9 @@ Authorization: Bearer {{$global.accessToken}} Content-Type: application/json { - "question": 6, - "text": "Option 2", + "question": 13, + "text": "Option 4", "value": 1, - "order": 2, - "score": 8 + "order": 4, + "score": 10 } \ No newline at end of file diff --git a/src/modules/admin/question-transitions/http/admin-question-transitions.delete.endpoints.http b/src/modules/admin/question-transitions/http/admin-question-transitions.delete.endpoints.http new file mode 100644 index 0000000..453d1f2 --- /dev/null +++ b/src/modules/admin/question-transitions/http/admin-question-transitions.delete.endpoints.http @@ -0,0 +1,3 @@ +DELETE {{baseUrl}}/admin/question-transitions/26 +Authorization: Bearer {{$global.accessToken}} +Content-Type: application/json diff --git a/src/modules/admin/question-transitions/http/admin-question-transitions.patch.endpoints.http b/src/modules/admin/question-transitions/http/admin-question-transitions.patch.endpoints.http new file mode 100644 index 0000000..27cb065 --- /dev/null +++ b/src/modules/admin/question-transitions/http/admin-question-transitions.patch.endpoints.http @@ -0,0 +1,7 @@ +PATCH {{baseUrl}}/admin/question-transitions/26 +Authorization: Bearer {{$global.accessToken}} +Content-Type: application/json + +{ + "toQuestion": 13 +} \ No newline at end of file diff --git a/src/modules/admin/question-transitions/http/admin-question-transitions.post.endpoints.http b/src/modules/admin/question-transitions/http/admin-question-transitions.post.endpoints.http index 83a4631..5a9c5ae 100644 --- a/src/modules/admin/question-transitions/http/admin-question-transitions.post.endpoints.http +++ b/src/modules/admin/question-transitions/http/admin-question-transitions.post.endpoints.http @@ -3,10 +3,11 @@ Authorization: Bearer {{$global.accessToken}} Content-Type: application/json { - "test": 1, + "test": 2, "type": "end", - "fromQuestion": 7 - // "toQuestion": 7 - // "conditionValue": {"min": 51, "max": 100} - // "conditionValue": {"choiceId": 5} + "fromQuestion": 13 + // "toQuestion": 13 + // "conditionValue": {"min": 11, "max": 20} + // "conditionValue": {"choiceId": 16 } + // "conditionValue": {"choiceIds": [13, 14, 15], "operator": "all"} } \ No newline at end of file diff --git a/src/modules/admin/questions/http/admin-questions.post.endpoints.http b/src/modules/admin/questions/http/admin-questions.post.endpoints.http index 7611cfd..5f300cf 100644 --- a/src/modules/admin/questions/http/admin-questions.post.endpoints.http +++ b/src/modules/admin/questions/http/admin-questions.post.endpoints.http @@ -3,11 +3,11 @@ Authorization: Bearer {{$global.accessToken}} Content-Type: application/json { - "test": 1, - "content": "سوال هفتم", + "test": 2, + "content": "Q6", "required": true, - "type": "numeric" - // "metadata": { "min": -10, "max": 10 } + "type": "multi-choice" + // "metadata": { "min": 0, "max": 100 } } POST {{baseUrl}}/admin/questions/range-rules @@ -15,8 +15,8 @@ Authorization: Bearer {{$global.accessToken}} Content-Type: application/json { - "question": 5, - "min": 1, - "max": 10, - "score": 8 + "question": 11, + "min": 51, + "max": 100, + "score": 5 } \ No newline at end of file diff --git a/src/modules/admin/tests/http/admin-tests.get.endpoints.http b/src/modules/admin/tests/http/admin-tests.get.endpoints.http index 444d5cd..9d967a8 100644 --- a/src/modules/admin/tests/http/admin-tests.get.endpoints.http +++ b/src/modules/admin/tests/http/admin-tests.get.endpoints.http @@ -1,5 +1,5 @@ GET {{baseUrl}}/admin/tests?title=test&isActive=true&accessType=paid&sortBy=title&order=DSC&page=2&limit=1 Authorization: Bearer {{$global.accessToken}} -GET {{baseUrl}}/admin/tests/4 +GET {{baseUrl}}/admin/tests/1 Authorization: Bearer {{$global.accessToken}} diff --git a/src/modules/admin/tests/http/admin-tests.patch.endpoints.http b/src/modules/admin/tests/http/admin-tests.patch.endpoints.http index e595ccd..d01c837 100644 --- a/src/modules/admin/tests/http/admin-tests.patch.endpoints.http +++ b/src/modules/admin/tests/http/admin-tests.patch.endpoints.http @@ -1,8 +1,9 @@ -PATCH {{baseUrl}}/admin/tests/4 +PATCH {{baseUrl}}/admin/tests/2 Authorization: Bearer {{$global.accessToken}} Content-Type: application/json { - "accessType": "login", - "isActive": false + // "accessType": "login", + // "isActive": false + "status": "published" } diff --git a/src/modules/admin/tests/http/admin-tests.post.endpoints.http b/src/modules/admin/tests/http/admin-tests.post.endpoints.http index fe13ae9..ad82b1e 100644 --- a/src/modules/admin/tests/http/admin-tests.post.endpoints.http +++ b/src/modules/admin/tests/http/admin-tests.post.endpoints.http @@ -3,8 +3,8 @@ Content-Type: application/json Authorization: Bearer {{$global.accessToken}} { - "title": "Test One", - "description": "Description One", + "title": "Test Two", + "description": "Description Two", "accessType": "login", "isActive": true } \ No newline at end of file diff --git a/src/modules/submissions/http/submissions.post.endpoints.http b/src/modules/submissions/http/submissions.post.endpoints.http index 310b10d..5b2b400 100644 --- a/src/modules/submissions/http/submissions.post.endpoints.http +++ b/src/modules/submissions/http/submissions.post.endpoints.http @@ -3,14 +3,15 @@ Authorization: Bearer {{$global.accessToken}} Content-Type: application/json { - "testId": 1 + "testId": 2 } -POST {{baseUrl}}/submissions/2/answer +POST {{baseUrl}}/submissions/1/answer Authorization: Bearer {{$global.accessToken}} Content-Type: application/json { - // "choiceId": 2 - "numericValue": 8 + // "choiceId": 17 + // "numericValue": 12 + "choiceIds": [19,21] } diff --git a/src/modules/submissions/providers/start/start-submission.provider.ts b/src/modules/submissions/providers/start/start-submission.provider.ts index 0cf9603..4e1ff60 100644 --- a/src/modules/submissions/providers/start/start-submission.provider.ts +++ b/src/modules/submissions/providers/start/start-submission.provider.ts @@ -77,7 +77,6 @@ export class StartSubmissionProvider { relations: { toQuestion: { choices: true, - rangeRules: true, }, }, order: { diff --git a/src/modules/submissions/validators/submission-answer.validator.ts b/src/modules/submissions/validators/submission-answer.validator.ts index 6e3799b..6b7df45 100644 --- a/src/modules/submissions/validators/submission-answer.validator.ts +++ b/src/modules/submissions/validators/submission-answer.validator.ts @@ -14,9 +14,13 @@ export class SubmissionAnswerValidator implements ValidatorConstraintInterface { // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment const obj = validationArguments?.object as any; // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment - const { choiceId, numericValue } = obj; + const { choiceId, numericValue, choiceIds } = obj; - return choiceId !== undefined || numericValue !== undefined; + return ( + choiceId !== undefined || + numericValue !== undefined || + choiceIds !== undefined + ); } defaultMessage?(): string { @@ -24,7 +28,7 @@ export class SubmissionAnswerValidator implements ValidatorConstraintInterface { return ( i18n?.t('submissions.errors.choiceNumericConstraint') ?? - 'You must send either choiceId or numericValue.' + 'You must send either choiceId, choiceIds or numericValue.' ); } } From 9ecc9647b5eb7563c5f25629907a640c8f7e4714 Mon Sep 17 00:00:00 2001 From: radmehr Date: Sat, 29 Aug 2026 23:00:27 +0330 Subject: [PATCH 4/4] feat: add database seed script --- package-lock.json | 504 ++++++++++ package.json | 5 +- src/database/seeds/seed.ts | 887 ++++++++++++++++++ .../http/admin-tests.patch.endpoints.http | 4 +- .../http/submissions.get.endpoints.http | 2 + .../http/submissions.post.endpoints.http | 14 +- 6 files changed, 1406 insertions(+), 10 deletions(-) create mode 100644 src/database/seeds/seed.ts create mode 100644 src/modules/submissions/http/submissions.get.endpoints.http diff --git a/package-lock.json b/package-lock.json index ea59f65..2288c21 100644 --- a/package-lock.json +++ b/package-lock.json @@ -59,6 +59,7 @@ "ts-loader": "^9.5.2", "ts-node": "^10.9.2", "tsconfig-paths": "^4.2.0", + "tsx": "^4.23.12", "typescript": "^5.7.3", "typescript-eslint": "^8.20.0" } @@ -775,6 +776,448 @@ "dev": true, "license": "MIT" }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.2.tgz", + "integrity": "sha512-XExcO+dvLKvVtNTibSTBej1NCAbaGhWn9Ww1ZPx80qsahhPFe/8jgWP0IchNe0F3HwkU7n8ejhH8bjonqht8mQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.2.tgz", + "integrity": "sha512-kXXoiPVVGQcnIYGOeaovwOURpniDBpSq4A03qkQ+BMQqtGG6HYap3xne9C1O1yo4TR3qxlCX5IqqmX6fFo2Lqg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.2.tgz", + "integrity": "sha512-5YfKeeI8qWfBZIX+u2xZC3Zlb3Os/gLS2sbEKM+I4ZOcsWmHS2WLysCcQZDAFRslDUU5Oiq44gf6PYN1vGwG5A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.2.tgz", + "integrity": "sha512-O387ite7SzUyCcy3JQX4P4bLtEA7bLLkx+esve5JHnyYfNTxcVpXZo9jhdB0lTKN44gztELTdU7nS8Nr16Fs1Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.2.tgz", + "integrity": "sha512-n4KqkOQrraxHJcgjM1RvwbigfQKIKJVpM7xp+KsxiyUSrRdIXnt73VhrPAx0fV44hgfmIVKjxMN9J1t5jySVkw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.2.tgz", + "integrity": "sha512-uq6suIWYP37qzGddBKPw5QEQPi6HiLGsO7UmkpfyaYNQ3D+rN6w6WfwH+nuqcGXWvawGwxOEroO4YGnFh95azw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.2.tgz", + "integrity": "sha512-n+I0BTSRIoy+d6RPKnEVwql5UwBJolytvY4mAOIEJorKlqgPII8ix6slVVrfZ5Tnj7glIZvloylbB/EJPMWEXw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.2.tgz", + "integrity": "sha512-78XJTJkvPs0kz2w61301PJjXl4g7q3JqiYMZ/M/yVI73EHBrCRTgkhu9oqG7vPqq+a/yadEW8aD+agKlk5xrmg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.2.tgz", + "integrity": "sha512-XlDnu2q5yoqems+xay6wSAcg9DDD7K9RLKZEBOMZm3ckNpJBvOX20tSfby8KfrrhINDyv9V2YVZKY/SpoGJI8w==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.2.tgz", + "integrity": "sha512-pW4AC0P3it8c7do9MVM4p51FzHzdM/TZrerurgRcHJ2WTa1VQ1CIq18xncfpBJw4ojkiZZrKW2yIBWBP92j6Ug==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.2.tgz", + "integrity": "sha512-CYbnj78HsIeA+DhgUKgFCfvNsTHFhMMrinUrMZpDXJXKN8T3XViTZ/+wtHeVxEWY8ewSzTFN+nRmSwO2tZaLUQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.2.tgz", + "integrity": "sha512-buwkd8nsph4R+ajRvw0qM5Hja/TXQow3ptzWO2EbG/cqcIkHloRrdlBtQlshyYGTNFvfkfJ5tpPLVkY4DtsPfQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.2.tgz", + "integrity": "sha512-ZVykbDyk7519VwiNb9Lcj9m8XM6v5V9uKPvrEMkkEedVewf+0itkhahp4HDpgERXhwLRpWFypsGbG/J8s0QjJA==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.2.tgz", + "integrity": "sha512-CAXl+Dtd9UUuJd8pKKdwh6MLm3MUMiqMPmhZ3tTSXPqfyQ3vDl6R5hZdZ/kYojK4ofXtdfSv1tFq8XzWx3heNQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.2.tgz", + "integrity": "sha512-GeXCej4IQtU1B+QlDV8W/RRvbzI3O/Stss+/bCXv4lZls5WGRtu2a+3JkA3i4qIUlMXpcHebWpF8AkJhATowuA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.2.tgz", + "integrity": "sha512-3H1weTYZPxt/WOhByszQZybS9w5lKzUn1FDMsgEChbHWQwHYQQRfBxgCcZvPhjHfKyJjIievvMmEUawJrdY9Dg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.2.tgz", + "integrity": "sha512-4xTZr1FUmSoQW4XIWmit3tzQrUTZM+N3P0XV8xROKYF50XfI7xeO90+1bZvNwxIufQ9hDQVRJH5YhgPVF8A/HQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.2.tgz", + "integrity": "sha512-sSATRjPeDBg3pdgHoQfoYBob11Kk1FGa9lui5RIHZCoCkJa9QKlvl3/vKz2usCmYYjs7ymJR/2Nnsqe+Hjt5nw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.2.tgz", + "integrity": "sha512-lqnzCV+mM0gIADaKihiCg6ifgfU2L3h5E33rNQBN1Y4MaVGnzryzmvvf7UHxprpQdE8hpqLolJ9Rl+SkIRDpyw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.2.tgz", + "integrity": "sha512-AL2qJILH7lNjrDmCQDvdxMfAUIv8KMNZOvrwAQ8i8//ntL9FflhOyMJ8OZSMBb8/AWXe3/5v5S20y3zCoZWKoQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.2.tgz", + "integrity": "sha512-QtiuPytchRyC4rwUKhexJdQKvDuZ6hWloi3igqPQNUJCS1/v9EiO3UTOXR6A3FoMo4fnAKbWJdqaIwhOzh8qEw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.2.tgz", + "integrity": "sha512-WkhYDmpTjLvGlScA1rwjRUmhl4k8oXR3cIbtqWmELgU/dFeHHlEllxDvdWcNJV9rbzCexB5vz8gtNewWLgCT7Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.2.tgz", + "integrity": "sha512-GPMSkTOtMnv2U2F8gxe4Io6qmVs+YKyp832Etqqxr0hFngmXQ3rzwytelm3GIn7T4VviRUlf3sOgBOiTdvaf7g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.2.tgz", + "integrity": "sha512-PIhhEkE9uPBleRBrQEJpUn7MBnibZzbGzYWPmY3x+YoVg/95zbjB4CxPPOQ8l5tYYM4mMaCthF8/1DIfBQQyWQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.2.tgz", + "integrity": "sha512-YmJbfTlvU7Sdn9BB+4PRES4oB6pxgS37MAONj+hBr/cpXS1aBPKXxNnDbu+QCWPj0o9dgyxeq79g6c5P8KeuYA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.2.tgz", + "integrity": "sha512-5ebpxr3nWMzrL/rnUI755Jkuee0bHL/Gq0WTF9lvcpv73wAp5eu8MfBUgWK9bhWvZjj7yX8etf/8tI8Ney695g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, "node_modules/@eslint-community/eslint-utils": { "version": "4.10.1", "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.10.1.tgz", @@ -5151,6 +5594,48 @@ "node": ">= 0.4" } }, + "node_modules/esbuild": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.2.tgz", + "integrity": "sha512-HKVLS8dvII+xoKW9kmqxbRKrnWEXfJJr/FZhhJmiqIB0e053QNYFqOBouTMO/k5sID4MvCiUCvv8b9M4h32wIA==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.28.2", + "@esbuild/android-arm": "0.28.2", + "@esbuild/android-arm64": "0.28.2", + "@esbuild/android-x64": "0.28.2", + "@esbuild/darwin-arm64": "0.28.2", + "@esbuild/darwin-x64": "0.28.2", + "@esbuild/freebsd-arm64": "0.28.2", + "@esbuild/freebsd-x64": "0.28.2", + "@esbuild/linux-arm": "0.28.2", + "@esbuild/linux-arm64": "0.28.2", + "@esbuild/linux-ia32": "0.28.2", + "@esbuild/linux-loong64": "0.28.2", + "@esbuild/linux-mips64el": "0.28.2", + "@esbuild/linux-ppc64": "0.28.2", + "@esbuild/linux-riscv64": "0.28.2", + "@esbuild/linux-s390x": "0.28.2", + "@esbuild/linux-x64": "0.28.2", + "@esbuild/netbsd-arm64": "0.28.2", + "@esbuild/netbsd-x64": "0.28.2", + "@esbuild/openbsd-arm64": "0.28.2", + "@esbuild/openbsd-x64": "0.28.2", + "@esbuild/openharmony-arm64": "0.28.2", + "@esbuild/sunos-x64": "0.28.2", + "@esbuild/win32-arm64": "0.28.2", + "@esbuild/win32-ia32": "0.28.2", + "@esbuild/win32-x64": "0.28.2" + } + }, "node_modules/escalade": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", @@ -10377,6 +10862,25 @@ "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", "license": "0BSD" }, + "node_modules/tsx": { + "version": "4.23.12", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.23.12.tgz", + "integrity": "sha512-FDf4L4sYzKtzWYhU/Xm0AQFdTjdIxNo9ElTf2mxXM6k8YMHXzYUe4yODVaXP4V9uMFbVg8c0qyBccK2OOxb45Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "~0.28.0" + }, + "bin": { + "tsx": "dist/cli.mjs" + }, + "engines": { + "node": ">=18.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + } + }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", diff --git a/package.json b/package.json index 75c25b7..2ff6018 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,9 @@ "migration:run:dev": "npm run typeorm:dev -- migration:run", "migration:run:prod": "npm run typeorm:prod -- migration:run", "migration:revert:dev": "npm run typeorm:dev -- migration:revert", - "migration:revert:prod": "npm run typeorm:prod -- migration:revert" + "migration:revert:prod": "npm run typeorm:prod -- migration:revert", + "seed": "cross-env NODE_ENV=development tsx src/database/seeds/seed.ts", + "seed:prod": "cross-env NODE_ENV=production node dist/database/seeds/seed.js" }, "dependencies": { "@nestjs/common": "^11.0.1", @@ -78,6 +80,7 @@ "ts-loader": "^9.5.2", "ts-node": "^10.9.2", "tsconfig-paths": "^4.2.0", + "tsx": "^4.23.12", "typescript": "^5.7.3", "typescript-eslint": "^8.20.0" }, diff --git a/src/database/seeds/seed.ts b/src/database/seeds/seed.ts new file mode 100644 index 0000000..e83f701 --- /dev/null +++ b/src/database/seeds/seed.ts @@ -0,0 +1,887 @@ +import * as bcrypt from 'bcrypt'; +import dataSource from '../data-source'; + +import { User } from '../../modules/users/entities/user.entity'; +import { Test } from '../../modules/tests/entities/test.entity'; +import { Question } from '../../modules/questions/entities/question.entity'; +import { Choice } from '../../modules/questions/entities/choice.entity'; +import { QuestionRangeRule } from '../../modules/questions/entities/question-range-rule.entity'; +import { QuestionTransition } from '../../modules/questions/entities/question-transition.entity'; + +import { Role } from '@/common/enums/roles.enum'; +import { QuestionType } from '../../modules/questions/enums/question-type.enum'; +import { AccessType } from '@/modules/tests/enums/access-types.enum'; +import { TestStatus } from '../../modules/tests/enums/test-status.enum'; +import { QuestionTransitionType } from '../../modules/questions/enums/question-transition-type.enum'; + +const TEST_TITLE = 'تست ارزیابی خطر ابتلا به عفونت‌های منتقله از راه جنسی'; + +const SUPERUSER_PHONE = process.env.SUPERUSER_PHONE; +const SUPERUSER_PASSWORD = process.env.SUPERUSER_PASSWORD; + +async function seedSuperuser() { + if (!SUPERUSER_PHONE || !SUPERUSER_PASSWORD) { + console.log( + 'SUPERUSER_PHONE or SUPERUSER_PASSWORD is not defined. Skipping superuser seed.', + ); + + return; + } + + const userRepository = dataSource.getRepository(User); + + const existingUser = await userRepository.findOne({ + where: { + phone: SUPERUSER_PHONE, + }, + }); + + if (existingUser) { + if (existingUser.role !== Role.SUPERUSER) { + existingUser.role = Role.SUPERUSER; + await userRepository.save(existingUser); + + console.log(`User ${SUPERUSER_PHONE} promoted to SUPERUSER.`); + } else { + console.log(`Superuser ${SUPERUSER_PHONE} already exists.`); + } + + return; + } + + const passwordHash = await bcrypt.hash(SUPERUSER_PASSWORD, 12); + + const superuser = userRepository.create({ + phone: SUPERUSER_PHONE, + password: passwordHash, + role: Role.SUPERUSER, + }); + + await userRepository.save(superuser); + + console.log(`Superuser ${SUPERUSER_PHONE} created successfully.`); +} + +async function seedTest() { + const result = await dataSource.transaction(async (manager) => { + const testRepository = manager.getRepository(Test); + const questionRepository = manager.getRepository(Question); + const choiceRepository = manager.getRepository(Choice); + const rangeRuleRepository = manager.getRepository(QuestionRangeRule); + const transitionRepository = manager.getRepository(QuestionTransition); + + const existingTest = await testRepository.findOne({ + where: { + title: TEST_TITLE, + }, + }); + + if (existingTest) { + return { + created: false, + testId: existingTest.id, + }; + } + + /* + * --------------------------------------------------------- + * TEST + * --------------------------------------------------------- + */ + + const test = testRepository.create({ + title: TEST_TITLE, + description: + 'این تست برای ارزیابی عوامل مرتبط با خطر ابتلا به عفونت‌های منتقله از راه جنسی طراحی شده است.', + status: TestStatus.PUBLISHED, + accessType: AccessType.FREE, + isActive: true, + questionsCount: 12, + }); + + const savedTest = await testRepository.save(test); + + /* + * --------------------------------------------------------- + * QUESTIONS + * --------------------------------------------------------- + */ + + const q1 = questionRepository.create({ + test: savedTest, + type: QuestionType.SINGLE_CHOICE, + order: 1, + weight: 1, + required: true, + content: + 'آیا اخیراً علائمی داشته‌اید که فکر می‌کنید ممکن است ناشی از عفونت‌های منتقله از راه جنسی باشند؟', + metadata: {}, + }); + + const q2 = questionRepository.create({ + test: savedTest, + type: QuestionType.SINGLE_CHOICE, + order: 2, + weight: 1, + required: true, + content: + 'آیا تا به حال پزشک یا یکی از کادر درمان به شما گفته است که به یک یا چند بیماری مقاربتی مبتلا شده‌اید؟', + metadata: {}, + }); + + const q3 = questionRepository.create({ + test: savedTest, + type: QuestionType.MULTI_CHOICE, + order: 3, + weight: 1, + required: true, + content: + 'تاکنون به کدام‌یک از بیماری‌های مقاربتی مبتلا بوده‌اید؟ (می‌توانید بیش از یک گزینه را انتخاب کنید.)', + metadata: {}, + }); + + const q4 = questionRepository.create({ + test: savedTest, + type: QuestionType.MULTI_CHOICE, + order: 4, + weight: 1, + required: true, + content: + 'آیا اخیراً با فردی که به یکی از بیماری‌های زیر مبتلا بوده، رابطهٔ جنسی داشته‌اید؟', + metadata: {}, + }); + + const q5 = questionRepository.create({ + test: savedTest, + type: QuestionType.SINGLE_CHOICE, + order: 5, + weight: 1, + required: true, + content: 'آیا تاکنون ماده‌ای غیرقانونی را به صورت تزریقی مصرف کرده‌اید؟', + metadata: {}, + }); + + const q6 = questionRepository.create({ + test: savedTest, + type: QuestionType.SINGLE_CHOICE, + order: 6, + weight: 1, + required: true, + content: + 'در ۱۲ ماه گذشته، آیا با فردی با تابعیت غیر ایرانی رابطهٔ جنسی داشته‌اید؟ (مثلاً هنگام سفر به خارج از کشور رابطهٔ جنسی داشته‌اید، یا در ایران با فردی از کشور دیگری رابطه داشته‌اید؟)', + metadata: {}, + }); + + const q7 = questionRepository.create({ + test: savedTest, + type: QuestionType.SINGLE_CHOICE, + order: 7, + weight: 1, + required: true, + content: 'آیا در حال حاضر به عنوان کارگر جنسی فعالیت می‌کنید؟', + metadata: {}, + }); + + const q8 = questionRepository.create({ + test: savedTest, + type: QuestionType.SINGLE_CHOICE, + order: 8, + weight: 1, + required: true, + content: + 'در ۱۲ ماه گذشته، آیا با یک فرد همجنس رابطهٔ جنسی داشته‌اید؟ (مثلاً مرد با مرد)', + metadata: {}, + }); + + const q9 = questionRepository.create({ + test: savedTest, + type: QuestionType.NUMERIC, + order: 9, + weight: 1, + required: true, + content: + 'در ۱۲ ماه گذشته، با چند فرد از همجنس خود رابطهٔ جنسی داشته‌اید؟', + metadata: {}, + }); + + const q10 = questionRepository.create({ + test: savedTest, + type: QuestionType.SINGLE_CHOICE, + order: 10, + weight: 1, + required: true, + content: + 'در ۱۲ ماه گذشته، آیا با یک فرد از جنس مخالف رابطهٔ جنسی داشته‌اید؟', + metadata: {}, + }); + + const q11 = questionRepository.create({ + test: savedTest, + type: QuestionType.NUMERIC, + order: 11, + weight: 1, + required: true, + content: + 'در ۱۲ ماه گذشته، با چند نفر از جنس مخالف رابطهٔ جنسی داشته‌اید؟', + metadata: {}, + }); + + const q12 = questionRepository.create({ + test: savedTest, + type: QuestionType.SINGLE_CHOICE, + order: 12, + weight: 1, + required: true, + content: + 'در ۱۲ ماه گذشته، آیا هنگام رابطهٔ واژنی یا مقعدی از کاندوم استفاده کرده‌اید؟', + metadata: {}, + }); + + await questionRepository.save([ + q1, + q2, + q3, + q4, + q5, + q6, + q7, + q8, + q9, + q10, + q11, + q12, + ]); + + /* + * --------------------------------------------------------- + * QUESTION 1 CHOICES + * --------------------------------------------------------- + */ + + const q1Yes = choiceRepository.create({ + question: q1, + text: 'بله', + value: 1, + order: 1, + score: 1, + }); + + const q1No = choiceRepository.create({ + question: q1, + text: 'خیر', + value: 0, + order: 2, + score: 0, + }); + + await choiceRepository.save([q1Yes, q1No]); + + /* + * --------------------------------------------------------- + * QUESTION 2 CHOICES + * --------------------------------------------------------- + */ + + const q2Yes = choiceRepository.create({ + question: q2, + text: 'بله', + value: 1, + order: 1, + score: 1, + }); + + const q2No = choiceRepository.create({ + question: q2, + text: 'خیر', + value: 0, + order: 2, + score: 0, + }); + + const q2NotSure = choiceRepository.create({ + question: q2, + text: 'مطمئن نیستم', + value: 2, + order: 3, + score: 1, + }); + + await choiceRepository.save([q2Yes, q2No, q2NotSure]); + + /* + * --------------------------------------------------------- + * QUESTION 3 CHOICES + * --------------------------------------------------------- + */ + + const q3Texts = [ + 'اچ‌آی‌وی (HIV)', + 'سیفلیس', + 'سوزاک', + 'عفونت غیراختصاصی مجرای ادرار', + 'هپاتیت B', + 'هپاتیت C', + 'کلامیدیا', + 'زگیل تناسلی', + // 'سایر', + // 'مطمئن نیستم', + // 'هیچ کدام', + ]; + + const q3Choices = q3Texts.map((text, index) => + choiceRepository.create({ + question: q3, + text, + value: index + 1, + order: index + 1, + score: 2, + }), + ); + + await choiceRepository.save(q3Choices); + + /* + * --------------------------------------------------------- + * QUESTION 4 CHOICES + * --------------------------------------------------------- + */ + + const q4Texts = [ + 'سیفلیس', + 'سوزاک', + 'عفونت غیراختصاصی مجرای ادرار', + 'هپاتیت B', + 'هپاتیت C', + 'کلامیدیا', + 'زگیل تناسلی', + // 'سایر', + // 'مطمئن نیستم', + // 'هیچ کدام', + ]; + + const q4Choices = q4Texts.map((text, index) => + choiceRepository.create({ + question: q4, + text, + value: index + 1, + order: index + 1, + score: 1, + }), + ); + + await choiceRepository.save(q4Choices); + + /* + * --------------------------------------------------------- + * QUESTION 5 CHOICES + * --------------------------------------------------------- + */ + + const q5Yes = choiceRepository.create({ + question: q5, + text: 'بله', + value: 1, + order: 1, + score: 1, + }); + + const q5No = choiceRepository.create({ + question: q5, + text: 'خیر', + value: 0, + order: 2, + score: 0, + }); + + const q5NotSure = choiceRepository.create({ + question: q5, + text: 'مطمئن نیستم', + value: 2, + order: 3, + score: 1, + }); + + await choiceRepository.save([q5Yes, q5No, q5NotSure]); + + /* + * --------------------------------------------------------- + * QUESTION 6 CHOICES + * --------------------------------------------------------- + */ + + const q6Yes = choiceRepository.create({ + question: q6, + text: 'بله', + value: 1, + order: 1, + score: 1, + }); + + const q6No = choiceRepository.create({ + question: q6, + text: 'خیر', + value: 0, + order: 2, + score: 0, + }); + + const q6NotSure = choiceRepository.create({ + question: q6, + text: 'مطمئن نیستم', + value: 2, + order: 3, + score: 1, + }); + + await choiceRepository.save([q6Yes, q6No, q6NotSure]); + + /* + * --------------------------------------------------------- + * QUESTION 7 CHOICES + * --------------------------------------------------------- + */ + + const q7Yes = choiceRepository.create({ + question: q7, + text: 'بله', + value: 1, + order: 1, + score: 2, + }); + + const q7No = choiceRepository.create({ + question: q7, + text: 'خیر', + value: 0, + order: 2, + score: 0, + }); + + await choiceRepository.save([q7Yes, q7No]); + + /* + * --------------------------------------------------------- + * QUESTION 8 CHOICES + * --------------------------------------------------------- + */ + + const q8Yes = choiceRepository.create({ + question: q8, + text: 'بله', + value: 1, + order: 1, + score: 2, + }); + + const q8No = choiceRepository.create({ + question: q8, + text: 'خیر', + value: 0, + order: 2, + score: 0, + }); + + await choiceRepository.save([q8Yes, q8No]); + + /* + * --------------------------------------------------------- + * QUESTION 10 CHOICES + * --------------------------------------------------------- + */ + + const q10Yes = choiceRepository.create({ + question: q10, + text: 'بله', + value: 1, + order: 1, + score: 1, + }); + + const q10No = choiceRepository.create({ + question: q10, + text: 'خیر', + value: 0, + order: 2, + score: 0, + }); + + await choiceRepository.save([q10Yes, q10No]); + + /* + * --------------------------------------------------------- + * QUESTION 12 CHOICES + * --------------------------------------------------------- + */ + + const q12Always = choiceRepository.create({ + question: q12, + text: 'همیشه با همهٔ شرکای جنسی‌ام از کاندوم استفاده کرده‌ام.', + value: 1, + order: 1, + score: 0, + }); + + const q12Sometimes = choiceRepository.create({ + question: q12, + text: 'گاهی با شرکای جنسی‌ام از کاندوم استفاده کرده‌ام.', + value: 2, + order: 2, + score: 2, + }); + + const q12Never = choiceRepository.create({ + question: q12, + text: 'هیچ‌وقت با هیچ‌کدام از شرکای جنسی‌ام از کاندوم استفاده نکرده‌ام.', + value: 3, + order: 3, + score: 5, + }); + + const q12NotApplicable = choiceRepository.create({ + question: q12, + text: 'سؤال در مورد من صحت ندارد؛ چون که رابطهٔ واژنی یا مقعدی نداشته‌ام.', + value: 4, + order: 4, + score: 1, + }); + + const q12NotSure = choiceRepository.create({ + question: q12, + text: 'مطمئن نیستم.', + value: 5, + order: 5, + score: 2, + }); + + await choiceRepository.save([ + q12Always, + q12Sometimes, + q12Never, + q12NotApplicable, + q12NotSure, + ]); + + /* + * --------------------------------------------------------- + * QUESTION 9 RANGE RULES + * --------------------------------------------------------- + * + * 1 person => 2 + * 2 people => 3 + * 3 or more => 5 + */ + + await rangeRuleRepository.save([ + rangeRuleRepository.create({ + question: q9, + min: 1, + max: 1, + score: 2, + }), + + rangeRuleRepository.create({ + question: q9, + min: 2, + max: 2, + score: 3, + }), + + rangeRuleRepository.create({ + question: q9, + min: 3, + max: 2147483647, + score: 5, + }), + ]); + + /* + * --------------------------------------------------------- + * QUESTION 11 RANGE RULES + * --------------------------------------------------------- + * + * 1 person => 1 + * 2 people => 2 + * 3 or more => 3 + */ + + await rangeRuleRepository.save([ + rangeRuleRepository.create({ + question: q11, + min: 1, + max: 1, + score: 1, + }), + + rangeRuleRepository.create({ + question: q11, + min: 2, + max: 2, + score: 2, + }), + + rangeRuleRepository.create({ + question: q11, + min: 3, + max: 2147483647, + score: 3, + }), + ]); + + /* + * --------------------------------------------------------- + * QUESTION TRANSITIONS + * --------------------------------------------------------- + */ + + /* + * START -> Q1 + */ + + await transitionRepository.save( + transitionRepository.create({ + test: savedTest, + fromQuestion: null, + toQuestion: q1, + type: QuestionTransitionType.START, + condition: null, + }), + ); + + /* + * Q1 -> Q2 + */ + + await transitionRepository.save( + transitionRepository.create({ + test: savedTest, + fromQuestion: q1, + toQuestion: q2, + type: QuestionTransitionType.DEFAULT, + condition: null, + }), + ); + + /* + * Q2 -> Q3 + */ + + await transitionRepository.save( + transitionRepository.create({ + test: savedTest, + fromQuestion: q2, + toQuestion: q3, + type: QuestionTransitionType.DEFAULT, + condition: null, + }), + ); + + /* + * Q3 -> Q4 + */ + + await transitionRepository.save( + transitionRepository.create({ + test: savedTest, + fromQuestion: q3, + toQuestion: q4, + type: QuestionTransitionType.DEFAULT, + condition: null, + }), + ); + + /* + * Q4 -> Q5 + */ + + await transitionRepository.save( + transitionRepository.create({ + test: savedTest, + fromQuestion: q4, + toQuestion: q5, + type: QuestionTransitionType.DEFAULT, + condition: null, + }), + ); + + /* + * Q5 -> Q6 + */ + + await transitionRepository.save( + transitionRepository.create({ + test: savedTest, + fromQuestion: q5, + toQuestion: q6, + type: QuestionTransitionType.DEFAULT, + condition: null, + }), + ); + + /* + * Q6 -> Q7 + */ + + await transitionRepository.save( + transitionRepository.create({ + test: savedTest, + fromQuestion: q6, + toQuestion: q7, + type: QuestionTransitionType.DEFAULT, + condition: null, + }), + ); + + /* + * Q7 -> Q8 + */ + + await transitionRepository.save( + transitionRepository.create({ + test: savedTest, + fromQuestion: q7, + toQuestion: q8, + type: QuestionTransitionType.DEFAULT, + condition: null, + }), + ); + + /* + * --------------------------------------------------------- + * Q8 BRANCH + * --------------------------------------------------------- + * + * YES -> Q9 + * NO -> Q10 + */ + + await transitionRepository.save( + transitionRepository.create({ + test: savedTest, + fromQuestion: q8, + toQuestion: q9, + type: QuestionTransitionType.CHOICE, + condition: { + choiceId: q8Yes.id, + }, + }), + ); + + await transitionRepository.save( + transitionRepository.create({ + test: savedTest, + fromQuestion: q8, + toQuestion: q10, + type: QuestionTransitionType.DEFAULT, + condition: null, + }), + ); + + /* + * Q9 -> Q10 + */ + + await transitionRepository.save( + transitionRepository.create({ + test: savedTest, + fromQuestion: q9, + toQuestion: q10, + type: QuestionTransitionType.DEFAULT, + condition: null, + }), + ); + + /* + * --------------------------------------------------------- + * Q10 BRANCH + * --------------------------------------------------------- + * + * YES -> Q11 + * NO -> Q12 + */ + + await transitionRepository.save( + transitionRepository.create({ + test: savedTest, + fromQuestion: q10, + toQuestion: q11, + type: QuestionTransitionType.CHOICE, + condition: { + choiceId: q10Yes.id, + }, + }), + ); + + await transitionRepository.save( + transitionRepository.create({ + test: savedTest, + fromQuestion: q10, + toQuestion: q12, + type: QuestionTransitionType.DEFAULT, + condition: null, + }), + ); + + /* + * Q11 -> Q12 + */ + + await transitionRepository.save( + transitionRepository.create({ + test: savedTest, + fromQuestion: q11, + toQuestion: q12, + type: QuestionTransitionType.DEFAULT, + condition: null, + }), + ); + + /* + * Q12 -> END + */ + + await transitionRepository.save( + transitionRepository.create({ + test: savedTest, + fromQuestion: q12, + toQuestion: null, + type: QuestionTransitionType.END, + condition: null, + }), + ); + + return { + created: true, + testId: savedTest.id, + }; + }); + + if (result.created) { + console.log(`Test created successfully. ID: ${result.testId}`); + } else { + console.log( + `Test already exists. ID: ${result.testId}. Nothing was created.`, + ); + } +} + +async function seed() { + try { + await dataSource.initialize(); + + console.log('Database connection initialized.'); + + await seedSuperuser(); + await seedTest(); + + console.log('Seed completed successfully.'); + } catch (error) { + console.error('Seed failed:', error); + process.exitCode = 1; + } finally { + if (dataSource.isInitialized) { + await dataSource.destroy(); + } + } +} + +void seed(); diff --git a/src/modules/admin/tests/http/admin-tests.patch.endpoints.http b/src/modules/admin/tests/http/admin-tests.patch.endpoints.http index d01c837..7828c90 100644 --- a/src/modules/admin/tests/http/admin-tests.patch.endpoints.http +++ b/src/modules/admin/tests/http/admin-tests.patch.endpoints.http @@ -3,7 +3,7 @@ Authorization: Bearer {{$global.accessToken}} Content-Type: application/json { - // "accessType": "login", + "accessType": "free" // "isActive": false - "status": "published" + // "status": "published" } diff --git a/src/modules/submissions/http/submissions.get.endpoints.http b/src/modules/submissions/http/submissions.get.endpoints.http new file mode 100644 index 0000000..14f567e --- /dev/null +++ b/src/modules/submissions/http/submissions.get.endpoints.http @@ -0,0 +1,2 @@ +GET {{baseUrl}}/submissions/6183e332-d28d-45ba-90a7-942f9d15100f/history +Authorization: Bearer {{$global.accessToken}} \ No newline at end of file diff --git a/src/modules/submissions/http/submissions.post.endpoints.http b/src/modules/submissions/http/submissions.post.endpoints.http index 5b2b400..80b2cdb 100644 --- a/src/modules/submissions/http/submissions.post.endpoints.http +++ b/src/modules/submissions/http/submissions.post.endpoints.http @@ -1,17 +1,17 @@ POST {{baseUrl}}/submissions/start -Authorization: Bearer {{$global.accessToken}} Content-Type: application/json +# Authorization: Bearer {{$global.accessToken}} { - "testId": 2 + "testId": 3 } -POST {{baseUrl}}/submissions/1/answer -Authorization: Bearer {{$global.accessToken}} +POST {{baseUrl}}/submissions/6183e332-d28d-45ba-90a7-942f9d15100f/answer Content-Type: application/json +# Authorization: Bearer {{$global.accessToken}} { - // "choiceId": 17 - // "numericValue": 12 - "choiceIds": [19,21] + "choiceId": 57 + // "numericValue": 10 + // "choiceIds": [45] }