feat: add user submission functionality
This commit is contained in:
@@ -0,0 +1,168 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user