Compare commits

...
2 Commits
21 changed files with 1045 additions and 871 deletions
+306
View File
@@ -0,0 +1,306 @@
import { Choice } from '@/modules/questions/entities/choice.entity';
import { Question } from '@/modules/questions/entities/question.entity';
import { EntityManager } from 'typeorm';
export async function seedChoices(
manager: EntityManager,
questions: Record<string, Question>,
) {
const choiceRepository = manager.getRepository(Choice);
const { q1, q2, q3, q4, q5, q6, q7, q8, q10, q12 } = questions;
/*
* ---------------------------------------------------------
* QUESTION 1 CHOICES
* ---------------------------------------------------------
*/
const q1Yes = choiceRepository.create({
question: q1,
text: 'بله',
order: 1,
score: 1,
});
const q1No = choiceRepository.create({
question: q1,
text: 'خیر',
order: 2,
score: 0,
});
const q1Choices = [q1Yes, q1No];
await choiceRepository.save(q1Choices);
/*
* ---------------------------------------------------------
* QUESTION 2 CHOICES
* ---------------------------------------------------------
*/
const q2Yes = choiceRepository.create({
question: q2,
text: 'بله',
order: 1,
score: 1,
});
const q2No = choiceRepository.create({
question: q2,
text: 'خیر',
order: 2,
score: 0,
});
const q2NotSure = choiceRepository.create({
question: q2,
text: 'مطمئن نیستم',
order: 3,
score: 1,
});
const q2Choices = [q2Yes, q2No, q2NotSure];
await choiceRepository.save(q2Choices);
/*
* ---------------------------------------------------------
* QUESTION 3 CHOICES
* ---------------------------------------------------------
*/
const q3Texts = [
'اچ‌آی‌وی (HIV)',
'سیفلیس',
'سوزاک',
'عفونت غیراختصاصی مجرای ادرار',
'هپاتیت B',
'هپاتیت C',
'کلامیدیا',
'زگیل تناسلی',
// 'سایر',
// 'مطمئن نیستم',
// 'هیچ کدام',
];
const q3Choices = q3Texts.map((text, index) =>
choiceRepository.create({
question: q3,
text,
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,
order: index + 1,
score: 1,
}),
);
await choiceRepository.save(q4Choices);
/*
* ---------------------------------------------------------
* QUESTION 5 CHOICES
* ---------------------------------------------------------
*/
const q5Yes = choiceRepository.create({
question: q5,
text: 'بله',
order: 1,
score: 1,
});
const q5No = choiceRepository.create({
question: q5,
text: 'خیر',
order: 2,
score: 0,
});
const q5NotSure = choiceRepository.create({
question: q5,
text: 'مطمئن نیستم',
order: 3,
score: 1,
});
const q5Choices = [q5Yes, q5No, q5NotSure];
await choiceRepository.save(q5Choices);
/*
* ---------------------------------------------------------
* QUESTION 6 CHOICES
* ---------------------------------------------------------
*/
const q6Yes = choiceRepository.create({
question: q6,
text: 'بله',
order: 1,
score: 1,
});
const q6No = choiceRepository.create({
question: q6,
text: 'خیر',
order: 2,
score: 0,
});
const q6NotSure = choiceRepository.create({
question: q6,
text: 'مطمئن نیستم',
order: 3,
score: 1,
});
const q6Choices = [q6Yes, q6No, q6NotSure];
await choiceRepository.save(q6Choices);
/*
* ---------------------------------------------------------
* QUESTION 7 CHOICES
* ---------------------------------------------------------
*/
const q7Yes = choiceRepository.create({
question: q7,
text: 'بله',
order: 1,
score: 2,
});
const q7No = choiceRepository.create({
question: q7,
text: 'خیر',
order: 2,
score: 0,
});
const q7Choices = [q7Yes, q7No];
await choiceRepository.save(q7Choices);
/*
* ---------------------------------------------------------
* QUESTION 8 CHOICES
* ---------------------------------------------------------
*/
const q8Yes = choiceRepository.create({
question: q8,
text: 'بله',
order: 1,
score: 2,
});
const q8No = choiceRepository.create({
question: q8,
text: 'خیر',
order: 2,
score: 0,
});
const q8Choices = [q8Yes, q8No];
await choiceRepository.save(q8Choices);
/*
* ---------------------------------------------------------
* QUESTION 10 CHOICES
* ---------------------------------------------------------
*/
const q10Yes = choiceRepository.create({
question: q10,
text: 'بله',
order: 1,
score: 1,
});
const q10No = choiceRepository.create({
question: q10,
text: 'خیر',
order: 2,
score: 0,
});
const q10Choices = [q10Yes, q10No];
await choiceRepository.save(q10Choices);
/*
* ---------------------------------------------------------
* QUESTION 12 CHOICES
* ---------------------------------------------------------
*/
const q12Always = choiceRepository.create({
question: q12,
text: 'همیشه با همهٔ شرکای جنسی‌ام از کاندوم استفاده کرده‌ام.',
order: 1,
score: 0,
});
const q12Sometimes = choiceRepository.create({
question: q12,
text: 'گاهی با شرکای جنسی‌ام از کاندوم استفاده کرده‌ام.',
order: 2,
score: 2,
});
const q12Never = choiceRepository.create({
question: q12,
text: 'هیچ‌وقت با هیچ‌کدام از شرکای جنسی‌ام از کاندوم استفاده نکرده‌ام.',
order: 3,
score: 5,
});
const q12NotApplicable = choiceRepository.create({
question: q12,
text: 'سؤال در مورد من صحت ندارد؛ چون که رابطهٔ واژنی یا مقعدی نداشته‌ام.',
order: 4,
score: 1,
});
const q12NotSure = choiceRepository.create({
question: q12,
text: 'مطمئن نیستم.',
order: 5,
score: 2,
});
const q12Choices = [
q12Always,
q12Sometimes,
q12Never,
q12NotApplicable,
q12NotSure,
];
await choiceRepository.save(q12Choices);
return { q8Yes, q10Yes };
}
@@ -0,0 +1,77 @@
import { QuestionRangeRule } from '@/modules/questions/entities/question-range-rule.entity';
import { Question } from '@/modules/questions/entities/question.entity';
import { EntityManager } from 'typeorm';
export async function seedQuestionRangeRules(
manager: EntityManager,
questions: Record<string, Question>,
) {
const rangeRuleRepository = manager.getRepository(QuestionRangeRule);
const { q9, q11 } = questions;
/*
* ---------------------------------------------------------
* 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,
}),
]);
}
+161
View File
@@ -0,0 +1,161 @@
import { Question } from '@/modules/questions/entities/question.entity';
import { QuestionType } from '@/modules/questions/enums/question-type.enum';
import { Test } from '@/modules/tests/entities/test.entity';
import { EntityManager } from 'typeorm';
export async function seedQuestions(manager: EntityManager, savedTest: Test) {
const questionRepository = manager.getRepository(Question);
/*
* ---------------------------------------------------------
* 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: {},
});
const questions = {
q1,
q2,
q3,
q4,
q5,
q6,
q7,
q8,
q9,
q10,
q11,
q12,
};
await questionRepository.save(Object.values(questions));
return questions;
}
+41
View File
@@ -0,0 +1,41 @@
import { ResultRange } from '@/modules/scoring/entities/result-range.entity';
import { Test } from '@/modules/tests/entities/test.entity';
import { EntityManager } from 'typeorm';
export async function seedResultRange(manager: EntityManager, savedTest: Test) {
const resultRangeRepository = manager.getRepository(ResultRange);
await resultRangeRepository.save([
resultRangeRepository.create({
test: savedTest,
minScore: 0,
maxScore: 1,
title: 'خطر پایین',
description: 'امتیاز شما در محدوده خطر پایین قرار دارد.',
}),
resultRangeRepository.create({
test: savedTest,
minScore: 2,
maxScore: 4,
title: 'خطر متوسط',
description: 'امتیاز شما در محدوده خطر متوسط قرار دارد.',
}),
resultRangeRepository.create({
test: savedTest,
minScore: 5,
maxScore: 7,
title: 'خطر بالا',
description: 'امتیاز شما در محدوده خطر بالا قرار دارد.',
}),
resultRangeRepository.create({
test: savedTest,
minScore: 8,
maxScore: 60,
title: 'خطر بسیار بالا',
description: 'امتیاز شما در محدوده خطر بسیار بالا قرار دارد.',
}),
]);
}
+20 -813
View File
@@ -1,829 +1,36 @@
import * as bcrypt from 'bcrypt';
import dataSource from '../data-source'; import dataSource from '../data-source';
import { User } from '../../modules/users/entities/user.entity';
import { Test } from '../../modules/tests/entities/test.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 { seedSuperuser } from './superuser.seed';
import { QuestionType } from '../../modules/questions/enums/question-type.enum'; import { seedTests } from './tests.seed';
import { AccessType } from '@/modules/tests/enums/access-types.enum'; import { seedQuestions } from './questions.seed';
import { TestStatus } from '../../modules/tests/enums/test-status.enum'; import { seedChoices } from './choices.seed';
import { QuestionTransitionType } from '../../modules/questions/enums/question-transition-type.enum'; import { seedQuestionRangeRules } from './question-range-rules.seed';
import { seedTransitions } from './transitions.seed';
import { seedResultRange } from './result-range.seed';
const TEST_TITLE = 'تست ارزیابی خطر ابتلا به عفونت‌های منتقله از راه جنسی'; async function prepareTests() {
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 result = await dataSource.transaction(async (manager) => {
const testRepository = manager.getRepository(Test); const seedTestResult = await seedTests(manager);
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({ let savedTest: Test;
where: {
title: TEST_TITLE,
},
});
if (existingTest) { if (seedTestResult instanceof Test) {
return { savedTest = seedTestResult;
created: false, } else {
testId: existingTest.id, return seedTestResult;
};
} }
/* const questions = await seedQuestions(manager, savedTest);
* ---------------------------------------------------------
* TEST
* ---------------------------------------------------------
*/
const test = testRepository.create({ const choices = await seedChoices(manager, questions);
title: TEST_TITLE,
description:
'این تست برای ارزیابی عوامل مرتبط با خطر ابتلا به عفونت‌های منتقله از راه جنسی طراحی شده است.',
status: TestStatus.PUBLISHED,
accessType: AccessType.FREE,
isActive: true,
questionsCount: 12,
});
const savedTest = await testRepository.save(test); await seedQuestionRangeRules(manager, questions);
/* await seedTransitions(manager, savedTest, questions, choices);
* ---------------------------------------------------------
* QUESTIONS
* ---------------------------------------------------------
*/
const q1 = questionRepository.create({ await seedResultRange(manager, savedTest);
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: 'بله',
order: 1,
score: 1,
});
const q1No = choiceRepository.create({
question: q1,
text: 'خیر',
order: 2,
score: 0,
});
await choiceRepository.save([q1Yes, q1No]);
/*
* ---------------------------------------------------------
* QUESTION 2 CHOICES
* ---------------------------------------------------------
*/
const q2Yes = choiceRepository.create({
question: q2,
text: 'بله',
order: 1,
score: 1,
});
const q2No = choiceRepository.create({
question: q2,
text: 'خیر',
order: 2,
score: 0,
});
const q2NotSure = choiceRepository.create({
question: q2,
text: 'مطمئن نیستم',
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,
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,
order: index + 1,
score: 1,
}),
);
await choiceRepository.save(q4Choices);
/*
* ---------------------------------------------------------
* QUESTION 5 CHOICES
* ---------------------------------------------------------
*/
const q5Yes = choiceRepository.create({
question: q5,
text: 'بله',
order: 1,
score: 1,
});
const q5No = choiceRepository.create({
question: q5,
text: 'خیر',
order: 2,
score: 0,
});
const q5NotSure = choiceRepository.create({
question: q5,
text: 'مطمئن نیستم',
order: 3,
score: 1,
});
await choiceRepository.save([q5Yes, q5No, q5NotSure]);
/*
* ---------------------------------------------------------
* QUESTION 6 CHOICES
* ---------------------------------------------------------
*/
const q6Yes = choiceRepository.create({
question: q6,
text: 'بله',
order: 1,
score: 1,
});
const q6No = choiceRepository.create({
question: q6,
text: 'خیر',
order: 2,
score: 0,
});
const q6NotSure = choiceRepository.create({
question: q6,
text: 'مطمئن نیستم',
order: 3,
score: 1,
});
await choiceRepository.save([q6Yes, q6No, q6NotSure]);
/*
* ---------------------------------------------------------
* QUESTION 7 CHOICES
* ---------------------------------------------------------
*/
const q7Yes = choiceRepository.create({
question: q7,
text: 'بله',
order: 1,
score: 2,
});
const q7No = choiceRepository.create({
question: q7,
text: 'خیر',
order: 2,
score: 0,
});
await choiceRepository.save([q7Yes, q7No]);
/*
* ---------------------------------------------------------
* QUESTION 8 CHOICES
* ---------------------------------------------------------
*/
const q8Yes = choiceRepository.create({
question: q8,
text: 'بله',
order: 1,
score: 2,
});
const q8No = choiceRepository.create({
question: q8,
text: 'خیر',
order: 2,
score: 0,
});
await choiceRepository.save([q8Yes, q8No]);
/*
* ---------------------------------------------------------
* QUESTION 10 CHOICES
* ---------------------------------------------------------
*/
const q10Yes = choiceRepository.create({
question: q10,
text: 'بله',
order: 1,
score: 1,
});
const q10No = choiceRepository.create({
question: q10,
text: 'خیر',
order: 2,
score: 0,
});
await choiceRepository.save([q10Yes, q10No]);
/*
* ---------------------------------------------------------
* QUESTION 12 CHOICES
* ---------------------------------------------------------
*/
const q12Always = choiceRepository.create({
question: q12,
text: 'همیشه با همهٔ شرکای جنسی‌ام از کاندوم استفاده کرده‌ام.',
order: 1,
score: 0,
});
const q12Sometimes = choiceRepository.create({
question: q12,
text: 'گاهی با شرکای جنسی‌ام از کاندوم استفاده کرده‌ام.',
order: 2,
score: 2,
});
const q12Never = choiceRepository.create({
question: q12,
text: 'هیچ‌وقت با هیچ‌کدام از شرکای جنسی‌ام از کاندوم استفاده نکرده‌ام.',
order: 3,
score: 5,
});
const q12NotApplicable = choiceRepository.create({
question: q12,
text: 'سؤال در مورد من صحت ندارد؛ چون که رابطهٔ واژنی یا مقعدی نداشته‌ام.',
order: 4,
score: 1,
});
const q12NotSure = choiceRepository.create({
question: q12,
text: 'مطمئن نیستم.',
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 { return {
created: true, created: true,
@@ -847,7 +54,7 @@ async function seed() {
console.log('Database connection initialized.'); console.log('Database connection initialized.');
await seedSuperuser(); await seedSuperuser();
await seedTest(); await prepareTests();
console.log('Seed completed successfully.'); console.log('Seed completed successfully.');
} catch (error) { } catch (error) {
+50
View File
@@ -0,0 +1,50 @@
import * as bcrypt from 'bcrypt';
import { User } from '../../modules/users/entities/user.entity';
import { Role } from '@/common/enums/roles.enum';
import dataSource from '../data-source';
const SUPERUSER_PHONE = process.env.SUPERUSER_PHONE;
const SUPERUSER_PASSWORD = process.env.SUPERUSER_PASSWORD;
export 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.`);
}
+43
View File
@@ -0,0 +1,43 @@
import { Test } from '@/modules/tests/entities/test.entity';
import { AccessType } from '@/modules/tests/enums/access-types.enum';
import { TestStatus } from '@/modules/tests/enums/test-status.enum';
import { EntityManager } from 'typeorm';
const TEST_TITLE = 'تست ارزیابی خطر ابتلا به عفونت‌های منتقله از راه جنسی';
export async function seedTests(manager: EntityManager) {
const testRepository = manager.getRepository(Test);
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);
return savedTest;
}
+239
View File
@@ -0,0 +1,239 @@
import { Choice } from '@/modules/questions/entities/choice.entity';
import { QuestionTransition } from '@/modules/questions/entities/question-transition.entity';
import { Question } from '@/modules/questions/entities/question.entity';
import { QuestionTransitionType } from '@/modules/questions/enums/question-transition-type.enum';
import { Test } from '@/modules/tests/entities/test.entity';
import { EntityManager } from 'typeorm';
export async function seedTransitions(
manager: EntityManager,
savedTest: Test,
questions: Record<string, Question>,
choices: Record<string, Choice>,
) {
const transitionRepository = manager.getRepository(QuestionTransition);
const { q1, q2, q3, q4, q5, q6, q7, q8, q9, q10, q11, q12 } = questions;
const { q8Yes, q10Yes } = choices;
/*
* ---------------------------------------------------------
* 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,
}),
);
}
+1 -1
View File
@@ -4,6 +4,6 @@
}, },
"errors": { "errors": {
"resultRangeOverlappingConstraint": "The specified score range has some overlaps with other records.", "resultRangeOverlappingConstraint": "The specified score range has some overlaps with other records.",
"resultRangeMinMaxConstraint": "minProbability value should be less than maxProbability." "resultRangeMinMaxConstraint": "minScore value should be less than maxScore."
} }
} }
+1 -1
View File
@@ -4,6 +4,6 @@
}, },
"errors": { "errors": {
"resultRangeOverlappingConstraint": "بازه امتیاز مشخص شده با بازه های دیگر تداخل دارد.", "resultRangeOverlappingConstraint": "بازه امتیاز مشخص شده با بازه های دیگر تداخل دارد.",
"resultRangeMinMaxConstraint": "minProbability باید کمتر از maxProbability باشد." "resultRangeMinMaxConstraint": "minScore باید کمتر از maxScore باشد."
} }
} }
@@ -1,20 +1,35 @@
import { MigrationInterface, QueryRunner } from "typeorm"; import { MigrationInterface, QueryRunner } from 'typeorm';
export class ChangeResultRangeFields1788950646073 implements MigrationInterface { export class ChangeResultRangeFields1788950646073 implements MigrationInterface {
name = 'ChangeResultRangeFields1788950646073' name = 'ChangeResultRangeFields1788950646073';
public async up(queryRunner: QueryRunner): Promise<void> { public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE "result_range" DROP COLUMN "minScore"`); await queryRunner.query(
await queryRunner.query(`ALTER TABLE "result_range" DROP COLUMN "maxScore"`); `ALTER TABLE "result_range" DROP COLUMN "minScore"`,
await queryRunner.query(`ALTER TABLE "result_range" ADD "minProbability" integer NOT NULL`); );
await queryRunner.query(`ALTER TABLE "result_range" ADD "maxProbability" integer NOT NULL`); await queryRunner.query(
`ALTER TABLE "result_range" DROP COLUMN "maxScore"`,
);
await queryRunner.query(
`ALTER TABLE "result_range" ADD "minProbability" integer NOT NULL`,
);
await queryRunner.query(
`ALTER TABLE "result_range" ADD "maxProbability" integer NOT NULL`,
);
} }
public async down(queryRunner: QueryRunner): Promise<void> { public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE "result_range" DROP COLUMN "maxProbability"`); await queryRunner.query(
await queryRunner.query(`ALTER TABLE "result_range" DROP COLUMN "minProbability"`); `ALTER TABLE "result_range" DROP COLUMN "maxProbability"`,
await queryRunner.query(`ALTER TABLE "result_range" ADD "maxScore" integer NOT NULL`); );
await queryRunner.query(`ALTER TABLE "result_range" ADD "minScore" integer NOT NULL`); await queryRunner.query(
`ALTER TABLE "result_range" DROP COLUMN "minProbability"`,
);
await queryRunner.query(
`ALTER TABLE "result_range" ADD "maxScore" integer NOT NULL`,
);
await queryRunner.query(
`ALTER TABLE "result_range" ADD "minScore" integer NOT NULL`,
);
} }
} }
@@ -0,0 +1,35 @@
import { MigrationInterface, QueryRunner } from 'typeorm';
export class CalculateByScore1789906979798 implements MigrationInterface {
name = 'CalculateByScore1789906979798';
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "result_range" DROP COLUMN "minProbability"`,
);
await queryRunner.query(
`ALTER TABLE "result_range" DROP COLUMN "maxProbability"`,
);
await queryRunner.query(
`ALTER TABLE "result_range" ADD "minScore" integer NOT NULL`,
);
await queryRunner.query(
`ALTER TABLE "result_range" ADD "maxScore" integer NOT NULL`,
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "result_range" DROP COLUMN "maxScore"`,
);
await queryRunner.query(
`ALTER TABLE "result_range" DROP COLUMN "minScore"`,
);
await queryRunner.query(
`ALTER TABLE "result_range" ADD "maxProbability" integer NOT NULL`,
);
await queryRunner.query(
`ALTER TABLE "result_range" ADD "minProbability" integer NOT NULL`,
);
}
}
@@ -6,6 +6,6 @@ Content-Type: application/json
"test": 4, "test": 4,
"title": "احتمال خیلی بالا", "title": "احتمال خیلی بالا",
"description": "احتمال ابتلا خیلی بالا است.", "description": "احتمال ابتلا خیلی بالا است.",
"minProbability": 21, "minScore": 21,
"maxProbability": 40 "maxScore": 40
} }
@@ -8,11 +8,11 @@ export class CreateResultRangeDTO {
@IsNumber() @IsNumber()
@IsNotEmpty() @IsNotEmpty()
minProbability!: number; minScore!: number;
@IsNumber() @IsNumber()
@IsNotEmpty() @IsNotEmpty()
maxProbability!: number; maxScore!: number;
@IsString() @IsString()
@IsNotEmpty() @IsNotEmpty()
@@ -14,11 +14,11 @@ export class FindResultRangeDTO extends PartialType(PaginationQueryDTO) {
@IsNumber() @IsNumber()
@IsOptional() @IsOptional()
minProbability?: number; minScore?: number;
@IsNumber() @IsNumber()
@IsOptional() @IsOptional()
maxProbability?: number; maxScore?: number;
@IsString() @IsString()
@IsOptional() @IsOptional()
@@ -15,13 +15,13 @@ export class ResultRange {
type: 'int', type: 'int',
nullable: false, nullable: false,
}) })
minProbability!: number; minScore!: number;
@Column({ @Column({
type: 'int', type: 'int',
nullable: false, nullable: false,
}) })
maxProbability!: number; maxScore!: number;
@Column({ @Column({
type: 'varchar', type: 'varchar',
@@ -1,8 +1,8 @@
export enum ResultRangeSortField { export enum ResultRangeSortField {
ID = 'id', ID = 'id',
TEST = 'test', TEST = 'test',
MIN_PROBABILITY = 'minProbability', MIN_SCORE = 'minScore',
MAX_PROBABILITY = 'maxProbability', MAX_SCORE = 'maxScore',
TITLE = 'title', TITLE = 'title',
DESCRIPTION = 'description', DESCRIPTION = 'description',
} }
@@ -17,12 +17,12 @@ export const filterResultRanges = (query: FindResultRangeDTO) => {
where.title = ILike(`%${query.title}%`); where.title = ILike(`%${query.title}%`);
} }
if (query.maxProbability !== undefined) { if (query.maxScore !== undefined) {
where.maxProbability = query.maxProbability; where.maxScore = query.maxScore;
} }
if (query.minProbability !== undefined) { if (query.minScore !== undefined) {
where.minProbability = query.minProbability; where.minScore = query.minScore;
} }
return where; return where;
@@ -32,16 +32,16 @@ export class ResultRangeCommandProvider {
private async checkRangeOverlap( private async checkRangeOverlap(
test: number, test: number,
minProbability: number, minScore: number,
maxProbability: number, maxScore: number,
excludeSelf: boolean = false, excludeSelf: boolean = false,
): Promise<void> { ): Promise<void> {
const queryBuilder = this.resultRangeRepository const queryBuilder = this.resultRangeRepository
.createQueryBuilder('resultRange') .createQueryBuilder('resultRange')
.where('resultRange.testId = :test', { test }) .where('resultRange.testId = :test', { test })
.andWhere( .andWhere(
'(resultRange.minProbability BETWEEN :minProbability AND :maxProbability) OR (resultRange.maxProbability BETWEEN :minProbability AND :maxProbability) OR (:minProbability BETWEEN resultRange.minProbability AND resultRange.maxProbability) OR (:maxProbability BETWEEN resultRange.minProbability AND resultRange.maxProbability)', '(resultRange.minScore BETWEEN :minScore AND :maxScore) OR (resultRange.maxScore BETWEEN :minScore AND :maxScore) OR (:minScore BETWEEN resultRange.minScore AND resultRange.maxScore) OR (:maxScore BETWEEN resultRange.minScore AND resultRange.maxScore)',
{ minProbability, maxProbability }, { minScore, maxScore },
); );
let overlappingRanges: Array<ResultRange>; let overlappingRanges: Array<ResultRange>;
@@ -92,8 +92,8 @@ export class ResultRangeCommandProvider {
await this.checkRangeOverlap( await this.checkRangeOverlap(
test.id, test.id,
createResultRangeDto.minProbability, createResultRangeDto.minScore,
createResultRangeDto.maxProbability, createResultRangeDto.maxScore,
); );
const newResultRange = this.resultRangeRepository.create({ const newResultRange = this.resultRangeRepository.create({
@@ -129,23 +129,23 @@ export class ResultRangeCommandProvider {
? updateResultRangeDto.test ? updateResultRangeDto.test
: resultRange.test.id; : resultRange.test.id;
const minProbability = const minScore =
updateResultRangeDto.minProbability !== undefined updateResultRangeDto.minScore !== undefined
? updateResultRangeDto.minProbability ? updateResultRangeDto.minScore
: resultRange.minProbability; : resultRange.minScore;
const maxProbability = const maxScore =
updateResultRangeDto.maxProbability !== undefined updateResultRangeDto.maxScore !== undefined
? updateResultRangeDto.maxProbability ? updateResultRangeDto.maxScore
: resultRange.maxProbability; : resultRange.maxScore;
if (minProbability >= maxProbability) { if (minScore >= maxScore) {
throw new BadRequestException( throw new BadRequestException(
'scoring.errors.resultRangeMinMaxConstraint', 'scoring.errors.resultRangeMinMaxConstraint',
); );
} }
await this.checkRangeOverlap(testId, minProbability, maxProbability, true); await this.checkRangeOverlap(testId, minScore, maxScore, true);
Object.assign(resultRange, updateResultRangeDto); Object.assign(resultRange, updateResultRangeDto);
@@ -14,15 +14,15 @@ export class ResultRangeValidator implements ValidatorConstraintInterface {
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
const obj = validationArguments?.object as any; const obj = validationArguments?.object as any;
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
const { minProbability, maxProbability } = obj; const { minScore, maxScore } = obj;
return minProbability < maxProbability; return minScore < maxScore;
} }
defaultMessage?(): string { defaultMessage?(): string {
const i18n = I18nContext.current(); const i18n = I18nContext.current();
return ( return (
i18n?.t('scoring.errors.resultRangeMinMaxConstraint') || i18n?.t('scoring.errors.resultRangeMinMaxConstraint') ||
'minProbability value should be less than maxProbability.' 'minScore value should be less than maxScore.'
); );
} }
} }
@@ -72,12 +72,12 @@ export class CalculateResultProvider {
rangeRules: true, rangeRules: true,
}, },
}), }),
async (probability) => async (score) =>
manager.find(ResultRange, { manager.find(ResultRange, {
where: { where: {
test: { id: submission.test.id }, test: { id: submission.test.id },
minProbability: LessThanOrEqual(probability), minScore: LessThanOrEqual(score),
maxProbability: MoreThanOrEqual(probability), maxScore: MoreThanOrEqual(score),
}, },
}), }),
); );
@@ -119,12 +119,12 @@ export class CalculateResultProvider {
rangeRules: true, rangeRules: true,
}, },
}), }),
async (probability) => async (score) =>
this.resultRangeRepository.find({ this.resultRangeRepository.find({
where: { where: {
test: { id: submission.testId }, test: { id: submission.testId },
minProbability: LessThanOrEqual(probability), minScore: LessThanOrEqual(score),
maxProbability: MoreThanOrEqual(probability), maxScore: MoreThanOrEqual(score),
}, },
}), }),
); );
@@ -150,7 +150,7 @@ export class CalculateResultProvider {
numericValue?: number; numericValue?: number;
}>, }>,
loadQuestions: (questionIds: number[]) => Promise<Question[]>, loadQuestions: (questionIds: number[]) => Promise<Question[]>,
loadResultRanges: (probability: number) => Promise<ResultRange[]>, loadResultRanges: (score: number) => Promise<ResultRange[]>,
) { ) {
let score = 0; let score = 0;
@@ -242,7 +242,7 @@ export class CalculateResultProvider {
const probability = const probability =
totalScores > 0 ? Math.ceil((score / totalScores) * 100) : 0; totalScores > 0 ? Math.ceil((score / totalScores) * 100) : 0;
const resultRanges = await loadResultRanges(probability); const resultRanges = await loadResultRanges(score);
return { return {
score, score,