Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions src/dto/scorecard.dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
import {
IsGreaterThan,
IsSmallerThan,
WeightSum,
} from 'src/shared/validators/customValidators';

export enum ScorecardStatus {
Expand Down Expand Up @@ -148,6 +149,7 @@ export class ScorecardSectionRequestDto extends ScorecardSectionBaseDto {
@IsArray()
@ValidateNested({ each: true })
@Type(() => ScorecardQuestionRequestDto)
@WeightSum()
questions: ScorecardQuestionRequestDto[];
}

Expand Down Expand Up @@ -193,6 +195,7 @@ export class ScorecardGroupRequestDto extends ScorecardGroupBaseDto {
@IsArray()
@ValidateNested({ each: true })
@Type(() => ScorecardSectionRequestDto)
@WeightSum()
sections: ScorecardSectionRequestDto[];
}

Expand Down Expand Up @@ -231,13 +234,15 @@ export class ScorecardBaseDto {

@ApiProperty({ description: 'The challenge type', example: 'Code' })
@IsString()
@IsNotEmpty()
challengeType: string;

@ApiProperty({
description: 'The name of the scorecard',
example: 'Sample Scorecard',
})
@IsString()
@IsNotEmpty()
name: string;

@ApiProperty({ description: 'The version of the scorecard', example: '1.0' })
Expand Down Expand Up @@ -280,6 +285,7 @@ export class ScorecardRequestDto extends ScorecardBaseWithGroupsDto {
@IsArray()
@ValidateNested({ each: true }) // validate each item in the array
@Type(() => ScorecardGroupRequestDto)
@WeightSum()
scorecardGroups: ScorecardGroupRequestDto[];
}

Expand Down
31 changes: 31 additions & 0 deletions src/shared/validators/customValidators.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {
isArray,
registerDecorator,
ValidationOptions,
ValidationArguments,
Expand Down Expand Up @@ -85,3 +86,33 @@ export function IsSmallerThan(
},
);
}

export function WeightSum(sum = 100, validationOptions?: ValidationOptions) {
return function (object: object, propertyName: string) {
registerDecorator({
name: 'WeightSum',
target: object.constructor,
propertyName: propertyName,
constraints: [sum],
options: validationOptions,
validator: {
validate(value: { weight: number }[], args: ValidationArguments) {
const [totalSum = 100] = args.constraints as [number];

if (!isArray(value)) return false;

const sum = value.reduce((acc, item) => {
const weight = typeof item?.weight === 'number' ? item.weight : 0;
return acc + weight;
}, 0);
return sum === totalSum;
},

defaultMessage(args: ValidationArguments) {
const [totalSum = 100] = args.constraints as [number];
return `The sum of all weights must be exactly ${totalSum}`;
},
},
});
};
}