169 lines
4.7 KiB
TypeScript
169 lines
4.7 KiB
TypeScript
import { BadRequestException, HttpStatus, Injectable } from '@nestjs/common';
|
|
import { Repository } from 'typeorm';
|
|
import { ResultRange } from '../entities/result-range.entity';
|
|
import { InjectRepository } from '@nestjs/typeorm';
|
|
import { CreateResultRangeDTO } from '../dtos/create-result-range.dto';
|
|
import { AppTimeoutException } from '@/common/exceptions/app-timeout.exception';
|
|
import { AppException } from '@/common/exceptions/app.exception';
|
|
import { TestsService } from '@/modules/tests/providers/tests.service';
|
|
import { AppResponse } from '@/common/responses';
|
|
import { I18nService } from 'nestjs-i18n';
|
|
import { UpdateResultRangeDTO } from '../dtos/update-result-range.dto';
|
|
|
|
@Injectable()
|
|
export class ResultRangeCommandProvider {
|
|
constructor(
|
|
/**
|
|
* Inject ResultRange Repository
|
|
*/
|
|
@InjectRepository(ResultRange)
|
|
private readonly resultRangeRepository: Repository<ResultRange>,
|
|
|
|
/**
|
|
* Inject Tests Service
|
|
*/
|
|
private readonly testsService: TestsService,
|
|
|
|
/**
|
|
* Inject I18n Service
|
|
*/
|
|
private readonly i18nService: I18nService,
|
|
) {}
|
|
|
|
private async checkRangeOverlap(
|
|
test: number,
|
|
minScore: number,
|
|
maxScore: number,
|
|
excludeSelf: boolean = false,
|
|
): Promise<void> {
|
|
const queryBuilder = this.resultRangeRepository
|
|
.createQueryBuilder('resultRange')
|
|
.where('resultRange.testId = :test', { test })
|
|
.andWhere(
|
|
'(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)',
|
|
{ minScore, maxScore },
|
|
);
|
|
|
|
let overlappingRanges: Array<ResultRange>;
|
|
|
|
try {
|
|
overlappingRanges = await queryBuilder.getMany();
|
|
} catch (err) {
|
|
throw new AppTimeoutException(err);
|
|
}
|
|
|
|
if (overlappingRanges.length > (excludeSelf ? 1 : 0)) {
|
|
throw new AppException(
|
|
'scoring.errors.resultRangeOverlappingConstraint',
|
|
HttpStatus.CONFLICT,
|
|
);
|
|
}
|
|
}
|
|
|
|
private async checkResultRangeExistance(resultRangeId: number) {
|
|
let resultRange: ResultRange | null = null;
|
|
|
|
try {
|
|
resultRange = await this.resultRangeRepository.findOne({
|
|
where: {
|
|
id: resultRangeId,
|
|
},
|
|
relations: {
|
|
test: true,
|
|
},
|
|
});
|
|
} catch (err) {
|
|
throw new AppTimeoutException(err);
|
|
}
|
|
|
|
if (!resultRange) {
|
|
throw new AppException(
|
|
'common.errors.entityNotFound',
|
|
HttpStatus.NOT_FOUND,
|
|
{ entity: '$t(scoring.fields.resultRange)' },
|
|
);
|
|
}
|
|
|
|
return resultRange;
|
|
}
|
|
|
|
public async createOne(createResultRangeDto: CreateResultRangeDTO) {
|
|
const test = await this.testsService.adminGetOne(createResultRangeDto.test);
|
|
|
|
await this.checkRangeOverlap(
|
|
test.id,
|
|
createResultRangeDto.minScore,
|
|
createResultRangeDto.maxScore,
|
|
);
|
|
|
|
const newResultRange = this.resultRangeRepository.create({
|
|
...createResultRangeDto,
|
|
test,
|
|
});
|
|
|
|
try {
|
|
await this.resultRangeRepository.save(newResultRange);
|
|
return new AppResponse(
|
|
newResultRange,
|
|
this.i18nService.translate('common.messages.createSuccess', {
|
|
args: { entity: '$t(scoring.fields.resultRange)' },
|
|
}),
|
|
);
|
|
} catch (err) {
|
|
throw new AppTimeoutException(err);
|
|
}
|
|
}
|
|
|
|
public async updateOne(
|
|
id: number,
|
|
updateResultRangeDto: UpdateResultRangeDTO,
|
|
) {
|
|
const resultRange = await this.checkResultRangeExistance(id);
|
|
|
|
if (updateResultRangeDto.test) {
|
|
await this.testsService.adminGetOne(updateResultRangeDto.test);
|
|
}
|
|
|
|
const testId =
|
|
updateResultRangeDto.test !== undefined
|
|
? updateResultRangeDto.test
|
|
: resultRange.test.id;
|
|
|
|
const minScore =
|
|
updateResultRangeDto.minScore !== undefined
|
|
? updateResultRangeDto.minScore
|
|
: resultRange.minScore;
|
|
|
|
const maxScore =
|
|
updateResultRangeDto.maxScore !== undefined
|
|
? updateResultRangeDto.maxScore
|
|
: resultRange.maxScore;
|
|
|
|
if (minScore >= maxScore) {
|
|
throw new BadRequestException(
|
|
'scoring.errors.resultRangeMinMaxConstraint',
|
|
);
|
|
}
|
|
|
|
await this.checkRangeOverlap(testId, minScore, maxScore, true);
|
|
|
|
Object.assign(resultRange, updateResultRangeDto);
|
|
|
|
try {
|
|
return await this.resultRangeRepository.save(resultRange);
|
|
} catch (err) {
|
|
throw new AppTimeoutException(err);
|
|
}
|
|
}
|
|
|
|
public async deleteOne(id: number) {
|
|
const resultRange = await this.checkResultRangeExistance(id);
|
|
|
|
try {
|
|
await this.resultRangeRepository.delete(resultRange.id);
|
|
} catch (err) {
|
|
throw new AppTimeoutException(err);
|
|
}
|
|
}
|
|
}
|