Skip to content

Commit 704bb4c

Browse files
authored
Merge pull request #15 from topcoder-platform/PM-1505_clone-scorecard
PM-1505 clone scorecard
2 parents 7bf1a5f + 9081a88 commit 704bb4c

File tree

2 files changed

+100
-0
lines changed

2 files changed

+100
-0
lines changed

src/api/scorecard/scorecard.controller.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,4 +229,27 @@ export class ScorecardController {
229229
});
230230
return result;
231231
}
232+
233+
@Post('/:id/clone')
234+
@Roles(UserRole.Admin)
235+
@Scopes(Scope.CreateScorecard)
236+
@ApiOperation({
237+
summary: 'Clone a scorecard',
238+
description: 'Roles: Admin | Scopes: create:scorecard',
239+
})
240+
@ApiParam({
241+
name: 'id',
242+
description: 'The ID of the scorecard to clone',
243+
example: 'abc123',
244+
})
245+
@ApiResponse({
246+
status: 201,
247+
description: 'Scorecard cloned successfully.',
248+
type: ScorecardResponseDto,
249+
})
250+
@ApiResponse({ status: 403, description: 'Forbidden.' })
251+
@ApiResponse({ status: 404, description: 'Scorecard not found.' })
252+
async cloneScorecard(@Param('id') id: string): Promise<ScorecardResponseDto> {
253+
return this.scorecardService.cloneScorecard(id);
254+
}
232255
}

src/api/scorecard/scorecard.service.ts

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,13 @@ import {
66
import { Prisma } from '@prisma/client';
77
import {
88
mapScorecardRequestToDto,
9+
ScorecardGroupBaseDto,
910
ScorecardPaginatedResponseDto,
1011
ScorecardQueryDto,
12+
ScorecardQuestionBaseDto,
1113
ScorecardRequestDto,
1214
ScorecardResponseDto,
15+
ScorecardSectionBaseDto,
1316
ScorecardWithGroupResponseDto,
1417
} from 'src/dto/scorecard.dto';
1518
import { PrismaService } from 'src/shared/modules/global/prisma.service';
@@ -198,4 +201,78 @@ export class ScoreCardService {
198201
scoreCards: data as ScorecardResponseDto[],
199202
};
200203
}
204+
205+
async cloneScorecard(
206+
id: string
207+
): Promise<ScorecardResponseDto> {
208+
const original = await this.prisma.scorecard
209+
.findUnique({
210+
where: { id },
211+
include: {
212+
scorecardGroups: {
213+
include: {
214+
sections: {
215+
include: {
216+
questions: true,
217+
},
218+
},
219+
},
220+
},
221+
},
222+
});
223+
224+
if (!original) {
225+
throw new NotFoundException({ message: `Scorecard not found.` });
226+
}
227+
228+
// Remove id fields from nested objects for cloning
229+
const cloneGroups = original.scorecardGroups.map((group: ScorecardGroupBaseDto) => ({
230+
...group,
231+
id: undefined,
232+
createdAt: undefined,
233+
updatedAt: undefined,
234+
scorecardId: undefined,
235+
sections: group.sections.map((section: ScorecardSectionBaseDto) => ({
236+
...section,
237+
id: undefined,
238+
createdAt: undefined,
239+
updatedAt: undefined,
240+
scorecardGroupId: undefined,
241+
questions: section.questions.map((question: ScorecardQuestionBaseDto) => ({
242+
...question,
243+
id: undefined,
244+
createdAt: undefined,
245+
updatedAt: undefined,
246+
sectionId: undefined,
247+
scorecardSectionId: undefined,
248+
})),
249+
})),
250+
}));
251+
252+
const clonedScorecard = await this.prisma.scorecard.create({
253+
data: {
254+
...original,
255+
id: undefined,
256+
name: `${original.name} (Clone)`,
257+
createdAt: undefined,
258+
updatedAt: undefined,
259+
scorecardGroups: {
260+
create: cloneGroups,
261+
},
262+
},
263+
include: {
264+
scorecardGroups: {
265+
include: {
266+
sections: {
267+
include: {
268+
questions: true,
269+
},
270+
},
271+
},
272+
},
273+
},
274+
});
275+
276+
return clonedScorecard as ScorecardResponseDto;
277+
}
201278
}

0 commit comments

Comments
 (0)