feat: complete question transitions admin routes
This commit is contained in:
+8
-7
@@ -21,8 +21,8 @@ import { QuestionsModule } from './modules/questions/questions.module';
|
|||||||
import { SubmissionsModule } from './modules/submissions/submissions.module';
|
import { SubmissionsModule } from './modules/submissions/submissions.module';
|
||||||
import { ScoringModule } from './modules/scoring/scoring.module';
|
import { ScoringModule } from './modules/scoring/scoring.module';
|
||||||
import { AdminModule } from './modules/admin/admin.module';
|
import { AdminModule } from './modules/admin/admin.module';
|
||||||
import { ThrottlerModule } from '@nestjs/throttler';
|
|
||||||
import { AppThrottlerGuard } from './common/guards/app-throttler.guard';
|
import { AppThrottlerGuard } from './common/guards/app-throttler.guard';
|
||||||
|
import { ThrottlerModule } from '@nestjs/throttler';
|
||||||
|
|
||||||
const ENV = process.env.NODE_ENV;
|
const ENV = process.env.NODE_ENV;
|
||||||
|
|
||||||
@@ -71,12 +71,13 @@ const ENV = process.env.NODE_ENV;
|
|||||||
ScheduleModule.forRoot(),
|
ScheduleModule.forRoot(),
|
||||||
|
|
||||||
// Throttler
|
// Throttler
|
||||||
ThrottlerModule.forRoot([
|
// ThrottlerModule.forRoot([
|
||||||
{ name: 'default', limit: 100, ttl: 60_000 },
|
// { name: 'default', limit: 100, ttl: 60_000 },
|
||||||
{ name: 'login', limit: 5, ttl: 60_000 },
|
// { name: 'login', limit: 5, ttl: 60_000 },
|
||||||
{ name: 'otp', limit: 3, ttl: 300_000 },
|
// { name: 'otp', limit: 3, ttl: 300_000 },
|
||||||
{ name: 'admin', limit: 30, ttl: 60_000 },
|
// { name: 'admin', limit: 30, ttl: 60_000 },
|
||||||
]),
|
// ]),
|
||||||
|
ThrottlerModule.forRoot([]),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Local Modules
|
* Local Modules
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import { AdminQuestionsController } from './questions/admin-questions.controller
|
|||||||
import { AdminChoicesController } from './choices/admin-choices.controller';
|
import { AdminChoicesController } from './choices/admin-choices.controller';
|
||||||
import { ScoringModule } from '../scoring/scoring.module';
|
import { ScoringModule } from '../scoring/scoring.module';
|
||||||
import { AdminScoringController } from './scoring/admin-scoring.controller';
|
import { AdminScoringController } from './scoring/admin-scoring.controller';
|
||||||
|
import { AdminQuestionTransitionsController } from './question-transitions/admin-question-transitions.controller';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [
|
imports: [
|
||||||
@@ -27,6 +28,7 @@ import { AdminScoringController } from './scoring/admin-scoring.controller';
|
|||||||
AdminQuestionsController,
|
AdminQuestionsController,
|
||||||
AdminChoicesController,
|
AdminChoicesController,
|
||||||
AdminScoringController,
|
AdminScoringController,
|
||||||
|
AdminQuestionTransitionsController,
|
||||||
],
|
],
|
||||||
providers: [AdminAuthService],
|
providers: [AdminAuthService],
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -3,9 +3,9 @@ Authorization: Bearer {{$global.accessToken}}
|
|||||||
Content-Type: application/json
|
Content-Type: application/json
|
||||||
|
|
||||||
{
|
{
|
||||||
"question": 2,
|
"question": 6,
|
||||||
"text": "Option 3",
|
"text": "Option 2",
|
||||||
"value": 3,
|
"value": 1,
|
||||||
"order": 3,
|
"order": 2,
|
||||||
"score": 6
|
"score": 8
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
import { Role } from '@/common/enums/roles.enum';
|
||||||
|
import { Roles } from '@/modules/auth/decorators/roles.decorator';
|
||||||
|
import { CreateQuestionTransitionDTO } from '@/modules/questions/dtos/create-question-transition.dto';
|
||||||
|
import { FindQuestionTransitionsDTO } from '@/modules/questions/dtos/find-question-transitions.dto';
|
||||||
|
import { UpdateQuestionTransitionDTO } from '@/modules/questions/dtos/update-question-transition.dto';
|
||||||
|
import { QuestionTransitionService } from '@/modules/questions/providers/transition/question-transition.service';
|
||||||
|
import {
|
||||||
|
Body,
|
||||||
|
Controller,
|
||||||
|
Delete,
|
||||||
|
Get,
|
||||||
|
Param,
|
||||||
|
ParseIntPipe,
|
||||||
|
Patch,
|
||||||
|
Post,
|
||||||
|
Query,
|
||||||
|
} from '@nestjs/common';
|
||||||
|
import { Throttle } from '@nestjs/throttler';
|
||||||
|
|
||||||
|
@Controller('admin/question-transitions')
|
||||||
|
@Roles(Role.SUPERUSER, Role.ADMIN)
|
||||||
|
@Throttle({ admin: {} })
|
||||||
|
export class AdminQuestionTransitionsController {
|
||||||
|
constructor(
|
||||||
|
/**
|
||||||
|
* Inject Question Transitions Service
|
||||||
|
*/
|
||||||
|
private readonly questionTransitionService: QuestionTransitionService,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
@Post()
|
||||||
|
public async createTransition(
|
||||||
|
@Body() createQuestionTransitionDto: CreateQuestionTransitionDTO,
|
||||||
|
) {
|
||||||
|
return await this.questionTransitionService.createOne(
|
||||||
|
createQuestionTransitionDto,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Patch(':id')
|
||||||
|
public async updateTransition(
|
||||||
|
@Param('id', ParseIntPipe) id: number,
|
||||||
|
@Body() updateQuestionTransitionDto: UpdateQuestionTransitionDTO,
|
||||||
|
) {
|
||||||
|
return await this.questionTransitionService.updateOne(
|
||||||
|
id,
|
||||||
|
updateQuestionTransitionDto,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Delete(':id')
|
||||||
|
public async deleteTransition(@Param('id', ParseIntPipe) id: number) {
|
||||||
|
return await this.questionTransitionService.deleteOne(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Get()
|
||||||
|
public async getAllTransitions(@Query() query: FindQuestionTransitionsDTO) {
|
||||||
|
return await this.questionTransitionService.findAllForAdmin(query);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Get(':id')
|
||||||
|
public async getTransitionById(@Param('id', ParseIntPipe) id: number) {
|
||||||
|
return await this.questionTransitionService.findOneByIdForAdmin(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
+12
@@ -0,0 +1,12 @@
|
|||||||
|
POST {{baseUrl}}/admin/question-transitions/
|
||||||
|
Authorization: Bearer {{$global.accessToken}}
|
||||||
|
Content-Type: application/json
|
||||||
|
|
||||||
|
{
|
||||||
|
"test": 1,
|
||||||
|
"type": "end",
|
||||||
|
"fromQuestion": 7
|
||||||
|
// "toQuestion": 7
|
||||||
|
// "conditionValue": {"min": 51, "max": 100}
|
||||||
|
// "conditionValue": {"choiceId": 5}
|
||||||
|
}
|
||||||
@@ -4,10 +4,10 @@ Content-Type: application/json
|
|||||||
|
|
||||||
{
|
{
|
||||||
"test": 1,
|
"test": 1,
|
||||||
"content": "سوال سوم",
|
"content": "سوال هفتم",
|
||||||
"required": true,
|
"required": true,
|
||||||
"type": "numeric",
|
"type": "numeric"
|
||||||
"metadata": { "min": 1, "max": 20 }
|
// "metadata": { "min": -10, "max": 10 }
|
||||||
}
|
}
|
||||||
|
|
||||||
POST {{baseUrl}}/admin/questions/range-rules
|
POST {{baseUrl}}/admin/questions/range-rules
|
||||||
@@ -15,8 +15,8 @@ Authorization: Bearer {{$global.accessToken}}
|
|||||||
Content-Type: application/json
|
Content-Type: application/json
|
||||||
|
|
||||||
{
|
{
|
||||||
"question": 3,
|
"question": 5,
|
||||||
"min": 1,
|
"min": 1,
|
||||||
"max": 10,
|
"max": 10,
|
||||||
"score": 10
|
"score": 8
|
||||||
}
|
}
|
||||||
@@ -3,7 +3,7 @@ Content-Type: application/json
|
|||||||
|
|
||||||
{
|
{
|
||||||
"phone": "09333026363",
|
"phone": "09333026363",
|
||||||
"otp": "87074"
|
"otp": "55486"
|
||||||
}
|
}
|
||||||
|
|
||||||
{{
|
{{
|
||||||
|
|||||||
@@ -0,0 +1,33 @@
|
|||||||
|
import { PaginationQueryDTO } from '@/common/dtos/pagination-query.dto';
|
||||||
|
import { PartialType } from '@nestjs/swagger';
|
||||||
|
import { IsEnum, IsNumber, IsOptional } from 'class-validator';
|
||||||
|
import { QuestionTransitionType } from '../enums/question-transition-type.enum';
|
||||||
|
import { QuestionTransitionSortField } from '../enums/question-transition-sort-field.enum';
|
||||||
|
|
||||||
|
export class FindQuestionTransitionsDTO extends PartialType(
|
||||||
|
PaginationQueryDTO,
|
||||||
|
) {
|
||||||
|
@IsNumber()
|
||||||
|
@IsOptional()
|
||||||
|
id?: number;
|
||||||
|
|
||||||
|
@IsNumber()
|
||||||
|
@IsOptional()
|
||||||
|
test?: number;
|
||||||
|
|
||||||
|
@IsNumber()
|
||||||
|
@IsOptional()
|
||||||
|
fromQuestion?: number;
|
||||||
|
|
||||||
|
@IsNumber()
|
||||||
|
@IsOptional()
|
||||||
|
toQuestion?: number;
|
||||||
|
|
||||||
|
@IsEnum(QuestionTransitionType)
|
||||||
|
@IsOptional()
|
||||||
|
type?: QuestionTransitionType;
|
||||||
|
|
||||||
|
@IsEnum(QuestionTransitionSortField)
|
||||||
|
@IsOptional()
|
||||||
|
sortBy?: QuestionTransitionSortField;
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
export enum QuestionTransitionSortField {
|
||||||
|
ID = 'id',
|
||||||
|
TEST = 'test',
|
||||||
|
FROM_QUESTION = 'fromQuestion',
|
||||||
|
TO_QUESTION = 'toQuestion',
|
||||||
|
TYPE = 'type',
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
import { FindOptionsWhere } from 'typeorm';
|
||||||
|
import { FindQuestionTransitionsDTO } from '../dtos/find-question-transitions.dto';
|
||||||
|
import { QuestionTransition } from '../entities/question-transition.entity';
|
||||||
|
|
||||||
|
export const filterQuestionTransitions = (
|
||||||
|
query: FindQuestionTransitionsDTO,
|
||||||
|
) => {
|
||||||
|
const where: FindOptionsWhere<QuestionTransition> = {};
|
||||||
|
|
||||||
|
if (query.id) {
|
||||||
|
where.id = query.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (query.type !== undefined) {
|
||||||
|
where.type = query.type;
|
||||||
|
}
|
||||||
|
|
||||||
|
return where;
|
||||||
|
};
|
||||||
@@ -61,9 +61,14 @@ export class QuestionRangeRuleCommandProvider {
|
|||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const queryBuilder = this.questionRangeRulesRepository
|
const queryBuilder = this.questionRangeRulesRepository
|
||||||
.createQueryBuilder('rule')
|
.createQueryBuilder('rule')
|
||||||
.where('rule.questionId = :question', { question })
|
.where({ question: { id: question } })
|
||||||
.andWhere(
|
.andWhere(
|
||||||
'(rule.min BETWEEN :min AND :max) OR (rule.max BETWEEN :min AND :max) OR (:min BETWEEN rule.min AND rule.max) OR (:max BETWEEN rule.min AND rule.max)',
|
`(
|
||||||
|
(rule.min BETWEEN :min AND :max) OR
|
||||||
|
(rule.max BETWEEN :min AND :max) OR
|
||||||
|
(:min BETWEEN rule.min AND rule.max) OR
|
||||||
|
(:max BETWEEN rule.min AND rule.max)
|
||||||
|
)`,
|
||||||
{ min, max },
|
{ min, max },
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -52,6 +52,8 @@ export class QuestionTransitionCommandProvider {
|
|||||||
} catch (err) {
|
} catch (err) {
|
||||||
this.handleDBExceptions(err);
|
this.handleDBExceptions(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return newTransition;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async updateOne(
|
public async updateOne(
|
||||||
|
|||||||
@@ -0,0 +1,121 @@
|
|||||||
|
import { InjectRepository } from '@nestjs/typeorm';
|
||||||
|
import { QuestionTransition } from '../../entities/question-transition.entity';
|
||||||
|
import { Repository } from 'typeorm';
|
||||||
|
import { HttpStatus, Injectable } from '@nestjs/common';
|
||||||
|
import { FindQuestionTransitionsDTO } from '../../dtos/find-question-transitions.dto';
|
||||||
|
import { filterQuestionTransitions } from '../../helpers/filter-question-transitions.helper';
|
||||||
|
import Utils from '@/common/utils';
|
||||||
|
import { Test } from '@/modules/tests/entities/test.entity';
|
||||||
|
import { TestsService } from '@/modules/tests/providers/tests.service';
|
||||||
|
import { Question } from '../../entities/question.entity';
|
||||||
|
import { QuestionsQueryProvider } from '../questions-query.provider';
|
||||||
|
import { PaginatedResponse } from '@/common/responses';
|
||||||
|
import { AppTimeoutException } from '@/common/exceptions/app-timeout.exception';
|
||||||
|
import { AppException } from '@/common/exceptions/app.exception';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class QuestionTransitionQueryProvider {
|
||||||
|
constructor(
|
||||||
|
/**
|
||||||
|
* Inject QuestionTransitions Repository
|
||||||
|
*/
|
||||||
|
@InjectRepository(QuestionTransition)
|
||||||
|
private readonly transitionsRepository: Repository<QuestionTransition>,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inject Tests Service
|
||||||
|
*/
|
||||||
|
private readonly testsService: TestsService,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inject Questions Query Provider
|
||||||
|
*/
|
||||||
|
private readonly questionsQueryProvider: QuestionsQueryProvider,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
public async findAllForAdmin(query: FindQuestionTransitionsDTO) {
|
||||||
|
const filters = filterQuestionTransitions(query);
|
||||||
|
const { limit, page, skip, take } =
|
||||||
|
Utils.PaginationUtils.getPaginationOptions(query);
|
||||||
|
|
||||||
|
let selectedTest: Test | null = null;
|
||||||
|
let selectedFromQuestion: Question | null = null;
|
||||||
|
let selectedToQuestion: Question | null = null;
|
||||||
|
|
||||||
|
if (query.test !== undefined) {
|
||||||
|
selectedTest = await this.testsService.adminGetOne(query.test);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (query.fromQuestion !== undefined) {
|
||||||
|
selectedFromQuestion = await this.questionsQueryProvider.findOneForAdmin({
|
||||||
|
where: { id: query.fromQuestion },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (query.toQuestion !== undefined) {
|
||||||
|
selectedToQuestion = await this.questionsQueryProvider.findOneForAdmin({
|
||||||
|
where: { id: query.toQuestion },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const [transitions, total] =
|
||||||
|
await this.transitionsRepository.findAndCount({
|
||||||
|
where: {
|
||||||
|
...filters,
|
||||||
|
...(selectedTest && {
|
||||||
|
test: {
|
||||||
|
id: selectedTest.id,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
...(selectedFromQuestion && {
|
||||||
|
fromQuestion: {
|
||||||
|
id: selectedFromQuestion.id,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
...(selectedToQuestion && {
|
||||||
|
toQuestion: {
|
||||||
|
id: selectedToQuestion.id,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
loadRelationIds: true,
|
||||||
|
skip,
|
||||||
|
take,
|
||||||
|
order: query.sortBy
|
||||||
|
? {
|
||||||
|
[query.sortBy]: query.order ?? 'ASC',
|
||||||
|
}
|
||||||
|
: { id: 'DESC' },
|
||||||
|
});
|
||||||
|
|
||||||
|
return new PaginatedResponse(transitions, {
|
||||||
|
page,
|
||||||
|
limit,
|
||||||
|
total,
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
throw new AppTimeoutException(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async findOneByIdForAdmin(id: number) {
|
||||||
|
let transition: QuestionTransition | null = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
transition = await this.transitionsRepository.findOneBy({ id });
|
||||||
|
} catch (err) {
|
||||||
|
throw new AppTimeoutException(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!transition) {
|
||||||
|
throw new AppException(
|
||||||
|
'common.errors.entityNotFound',
|
||||||
|
HttpStatus.NOT_FOUND,
|
||||||
|
{ entity: '$t(questions.fields.questionTransition)' },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return transition;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,51 @@
|
|||||||
|
import { Injectable } from '@nestjs/common';
|
||||||
|
import { QuestionTransitionCommandProvider } from './question-transition-command.provider';
|
||||||
|
import { CreateQuestionTransitionDTO } from '../../dtos/create-question-transition.dto';
|
||||||
|
import { UpdateQuestionTransitionDTO } from '../../dtos/update-question-transition.dto';
|
||||||
|
import { FindQuestionTransitionsDTO } from '../../dtos/find-question-transitions.dto';
|
||||||
|
import { QuestionTransitionQueryProvider } from './question-transition-query.provider';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class QuestionTransitionService {
|
||||||
|
constructor(
|
||||||
|
/**
|
||||||
|
* Inject QuestionTransition Command Provider
|
||||||
|
*/
|
||||||
|
private readonly questionTransitionCommandProvider: QuestionTransitionCommandProvider,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inject QuestionTransition Query Provider
|
||||||
|
*/
|
||||||
|
private readonly questionTransitionQueryProvider: QuestionTransitionQueryProvider,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
public async createOne(
|
||||||
|
createQuestionTransitionDto: CreateQuestionTransitionDTO,
|
||||||
|
) {
|
||||||
|
return await this.questionTransitionCommandProvider.createOne(
|
||||||
|
createQuestionTransitionDto,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async updateOne(
|
||||||
|
id: number,
|
||||||
|
updateQuestionTransitionDto: UpdateQuestionTransitionDTO,
|
||||||
|
) {
|
||||||
|
return await this.questionTransitionCommandProvider.updateOne(
|
||||||
|
id,
|
||||||
|
updateQuestionTransitionDto,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async deleteOne(id: number) {
|
||||||
|
return await this.questionTransitionCommandProvider.deleteOne(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async findAllForAdmin(query: FindQuestionTransitionsDTO) {
|
||||||
|
return await this.questionTransitionQueryProvider.findAllForAdmin(query);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async findOneByIdForAdmin(id: number) {
|
||||||
|
return await this.questionTransitionQueryProvider.findOneByIdForAdmin(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
+3
-3
@@ -140,7 +140,7 @@ export class CheckTransitionDBProvider {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (options.type === QuestionTransitionType.CHOICE) {
|
if (options.type === QuestionTransitionType.CHOICE) {
|
||||||
qb.andWhere(`t.conditionValue ->> 'choiceId' = :choiceId`, {
|
qb.andWhere(`t.condition ->> 'choiceId' = :choiceId`, {
|
||||||
choiceId: String(
|
choiceId: String(
|
||||||
(options.conditionValue as SingleChoiceCondition).choiceId,
|
(options.conditionValue as SingleChoiceCondition).choiceId,
|
||||||
),
|
),
|
||||||
@@ -148,9 +148,9 @@ export class CheckTransitionDBProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (options.type === QuestionTransitionType.NUMBER_RANGE) {
|
if (options.type === QuestionTransitionType.NUMBER_RANGE) {
|
||||||
qb.andWhere(`t.conditionValue ->> 'min' = :min`, {
|
qb.andWhere(`t.condition ->> 'min' = :min`, {
|
||||||
min: String((options.conditionValue as NumericCondition).min),
|
min: String((options.conditionValue as NumericCondition).min),
|
||||||
}).andWhere(`t.conditionValue ->> 'max' = :max`, {
|
}).andWhere(`t.condition ->> 'max' = :max`, {
|
||||||
max: String((options.conditionValue as NumericCondition).max),
|
max: String((options.conditionValue as NumericCondition).max),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,9 @@ import { QuestionRangeRuleQueryProvider } from './providers/range-rule/question-
|
|||||||
import { QuestionTransition } from './entities/question-transition.entity';
|
import { QuestionTransition } from './entities/question-transition.entity';
|
||||||
import { CheckTransitionDBProvider } from './providers/transition/validations/check-transition-db.provider';
|
import { CheckTransitionDBProvider } from './providers/transition/validations/check-transition-db.provider';
|
||||||
import { QuestionTransitionValidatorProvider } from './providers/transition/validations/question-transition-validator.provider';
|
import { QuestionTransitionValidatorProvider } from './providers/transition/validations/question-transition-validator.provider';
|
||||||
|
import { QuestionTransitionCommandProvider } from './providers/transition/question-transition-command.provider';
|
||||||
|
import { QuestionTransitionQueryProvider } from './providers/transition/question-transition-query.provider';
|
||||||
|
import { QuestionTransitionService } from './providers/transition/question-transition.service';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [
|
imports: [
|
||||||
@@ -48,7 +51,15 @@ import { QuestionTransitionValidatorProvider } from './providers/transition/vali
|
|||||||
// Question Transitions
|
// Question Transitions
|
||||||
CheckTransitionDBProvider,
|
CheckTransitionDBProvider,
|
||||||
QuestionTransitionValidatorProvider,
|
QuestionTransitionValidatorProvider,
|
||||||
|
QuestionTransitionCommandProvider,
|
||||||
|
QuestionTransitionQueryProvider,
|
||||||
|
QuestionTransitionService,
|
||||||
|
],
|
||||||
|
exports: [
|
||||||
|
QuestionsService,
|
||||||
|
ChoicesService,
|
||||||
|
QuestionRangeRuleService,
|
||||||
|
QuestionTransitionService,
|
||||||
],
|
],
|
||||||
exports: [QuestionsService, ChoicesService, QuestionRangeRuleService],
|
|
||||||
})
|
})
|
||||||
export class QuestionsModule {}
|
export class QuestionsModule {}
|
||||||
|
|||||||
Reference in New Issue
Block a user