Skip to content

Commit afd5661

Browse files
authored
Merge pull request #22 from topcoder-platform/pm-1585_1
fix(PM-1585): qa feedbacks on search scorecards API
2 parents 433c764 + 3069047 commit afd5661

File tree

5 files changed

+82
-50
lines changed

5 files changed

+82
-50
lines changed

.circleci/config.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ workflows:
7777
- feat/ai-workflows
7878
- feat/scorecards
7979
- pm-1503
80+
- pm-1585_1
8081
- 'build-prod':
8182
context: org-global
8283
filters:

src/api/scorecard/scorecard.controller.ts

Lines changed: 15 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,11 @@ import {
2828
ScorecardRequestDto,
2929
ScorecardResponseDto,
3030
ScorecardWithGroupResponseDto,
31+
SearchScorecardQuery,
3132
} from 'src/dto/scorecard.dto';
3233
import { ChallengeTrack } from 'src/shared/enums/challengeTrack.enum';
3334
import { ScoreCardService } from './scorecard.service';
3435
import { PaginationHeaderInterceptor } from 'src/interceptors/PaginationHeaderInterceptor';
35-
import { $Enums } from '@prisma/client';
3636
import { User } from 'src/shared/decorators/user.decorator';
3737
import { JwtUser } from 'src/shared/modules/global/jwt.service';
3838

@@ -198,40 +198,26 @@ export class ScorecardController {
198198
})
199199
@UseInterceptors(PaginationHeaderInterceptor)
200200
async searchScorecards(
201-
@Query('challengeTrack') challengeTrack?: ChallengeTrack | ChallengeTrack[],
202-
@Query('challengeType') challengeType?: string | string[],
203-
@Query('status') status?: $Enums.ScorecardStatus | $Enums.ScorecardStatus[],
204-
@Query('scorecardType')
205-
scorecardType?: $Enums.ScorecardType | $Enums.ScorecardType[],
206-
@Query('name') name?: string,
207-
@Query('page') page: number = 1,
208-
@Query('perPage') perPage: number = 10,
201+
@Query() query: SearchScorecardQuery,
209202
): Promise<ScorecardPaginatedResponseDto> {
210-
const challengeTrackArray = Array.isArray(challengeTrack)
211-
? challengeTrack
212-
: challengeTrack
213-
? [challengeTrack]
214-
: [];
215-
const challengeTypeArray = Array.isArray(challengeType)
216-
? challengeType
217-
: challengeType
218-
? [challengeType]
219-
: [];
220-
const scorecardTypesArray = Array.isArray(scorecardType)
221-
? scorecardType
222-
: scorecardType
223-
? [scorecardType]
224-
: [];
225-
const statusArray = Array.isArray(status) ? status : status ? [status] : [];
203+
const {
204+
challengeTrack = [],
205+
challengeType = [],
206+
status = [],
207+
scorecardType = [],
208+
name,
209+
page,
210+
perPage,
211+
} = query;
226212

227213
const result = await this.scorecardService.getScoreCards({
228-
challengeTrack: challengeTrackArray,
229-
challengeType: challengeTypeArray,
214+
challengeTrack,
215+
challengeType,
230216
name,
231217
page,
232218
perPage,
233-
scorecardTypesArray,
234-
statusArray,
219+
scorecardType,
220+
status,
235221
});
236222
return result;
237223
}

src/api/scorecard/scorecard.service.ts

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,12 @@ import {
99
mapScorecardRequestToDto,
1010
ScorecardGroupBaseDto,
1111
ScorecardPaginatedResponseDto,
12-
ScorecardQueryDto,
1312
ScorecardQuestionBaseDto,
1413
ScorecardRequestDto,
1514
ScorecardResponseDto,
1615
ScorecardSectionBaseDto,
1716
ScorecardWithGroupResponseDto,
17+
SearchScorecardQuery,
1818
} from 'src/dto/scorecard.dto';
1919
import { JwtUser } from 'src/shared/modules/global/jwt.service';
2020
import { PrismaService } from 'src/shared/modules/global/prisma.service';
@@ -153,7 +153,7 @@ export class ScoreCardService {
153153
throw new NotFoundException({ message: `Scorecard not found.` });
154154
}
155155
throw new InternalServerErrorException({
156-
message: `Error: ${error.code}`,
156+
message: `Invalid scorecard id - ${id}`,
157157
});
158158
});
159159
return data as ScorecardWithGroupResponseDto;
@@ -165,15 +165,15 @@ export class ScoreCardService {
165165
* @returns response dto
166166
*/
167167
async getScoreCards(
168-
query: ScorecardQueryDto,
168+
query: SearchScorecardQuery,
169169
): Promise<ScorecardPaginatedResponseDto> {
170170
const {
171171
page = 1,
172172
perPage = 10,
173173
challengeTrack,
174174
challengeType,
175-
scorecardTypesArray,
176-
statusArray,
175+
scorecardType,
176+
status,
177177
name,
178178
} = query;
179179
const skip = (page - 1) * perPage;
@@ -188,14 +188,14 @@ export class ScoreCardService {
188188
in: challengeType,
189189
},
190190
}),
191-
...(scorecardTypesArray?.length && {
191+
...(scorecardType?.length && {
192192
type: {
193-
in: scorecardTypesArray,
193+
in: scorecardType,
194194
},
195195
}),
196-
...(statusArray?.length && {
196+
...(status?.length && {
197197
status: {
198-
in: statusArray,
198+
in: status,
199199
},
200200
}),
201201
...(name && { name: { contains: name, mode: 'insensitive' } }),

src/dto/scorecard.dto.ts

Lines changed: 56 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
import { ApiProperty } from '@nestjs/swagger';
22
import { $Enums } from '@prisma/client';
3-
import { Type } from 'class-transformer';
3+
import { Transform, Type } from 'class-transformer';
44
import {
55
IsArray,
66
IsBoolean,
77
IsEnum,
8+
IsInt,
89
IsNotEmpty,
910
IsNumber,
1011
IsOptional,
@@ -288,6 +289,60 @@ export class ScorecardResponseDto extends ScorecardBaseDto {
288289
id: string;
289290
}
290291

292+
function toArray<T = string>(value: unknown): T[] | undefined {
293+
if (value === undefined || value === null || value === '') return undefined;
294+
const asArray = Array.isArray(value) ? value : [value];
295+
return asArray
296+
.flatMap((v) => String(v).split(','))
297+
.map((s) => s.trim())
298+
.filter(Boolean) as T[];
299+
}
300+
301+
export class SearchScorecardQuery {
302+
@IsOptional()
303+
@Transform(({ value }) => toArray<ChallengeTrack>(value))
304+
@IsArray()
305+
@IsEnum(ChallengeTrack, { each: true })
306+
challengeTrack?: ChallengeTrack[];
307+
308+
@IsOptional()
309+
@Transform(({ value }) => toArray<string>(value))
310+
@IsArray()
311+
@IsString({ each: true })
312+
challengeType?: string[];
313+
314+
@IsOptional()
315+
@Transform(({ value }) => toArray<$Enums.ScorecardStatus>(value))
316+
@IsArray()
317+
@IsEnum($Enums.ScorecardStatus, {
318+
each: true,
319+
message: (args) => `Invalid value "${args.value}" for "${args.property}".`,
320+
})
321+
status?: $Enums.ScorecardStatus[];
322+
323+
@IsOptional()
324+
@Transform(({ value }) => toArray<$Enums.ScorecardType>(value))
325+
@IsArray()
326+
@IsEnum($Enums.ScorecardType, { each: true })
327+
scorecardType?: $Enums.ScorecardType[];
328+
329+
@IsOptional()
330+
@IsString()
331+
name?: string;
332+
333+
@IsOptional()
334+
@Type(() => Number)
335+
@IsInt()
336+
@Min(1)
337+
page: number = 1;
338+
339+
@IsOptional()
340+
@Type(() => Number)
341+
@IsInt()
342+
@Min(1)
343+
perPage: number = 10;
344+
}
345+
291346
export class ScorecardWithGroupResponseDto extends ScorecardBaseDto {
292347
@ApiProperty({ description: 'The ID of the scorecard', example: 'abc123' })
293348
id: string;
@@ -324,16 +379,6 @@ export class ScorecardPaginatedResponseDto {
324379
scoreCards: ScorecardResponseDto[];
325380
}
326381

327-
export class ScorecardQueryDto {
328-
challengeTrack?: ChallengeTrack[];
329-
challengeType?: string[];
330-
name?: string;
331-
page?: number;
332-
perPage?: number;
333-
statusArray?: $Enums.ScorecardStatus[];
334-
scorecardTypesArray?: $Enums.ScorecardType[];
335-
}
336-
337382
export function mapScorecardRequestForCreate(request: ScorecardRequestDto) {
338383
const userFields = {
339384
...(request.createdBy ? { createdBy: request.createdBy } : {}),

src/shared/decorators/user.decorator.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ export const User = createParamDecorator(
55
(data: string, ctx: ExecutionContext) => {
66
const request = ctx.switchToHttp().getRequest();
77
const user = request.user;
8-
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
8+
99
return (data ? user?.[data] : user) as JwtUser;
1010
},
1111
);

0 commit comments

Comments
 (0)