Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update response Ids - POST voyages/teams/teamId/techs #138

Merged
merged 15 commits into from
Apr 27, 2024
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
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,12 @@ Another example [here](https://co-pilot.dev/changelog)
- Update changelog ([#104](https://github.com/chingu-x/chingu-dashboard-be/pull/104))
- Update test.yml to run e2e tests on pull requests to the main branch [#105](https://github.com/chingu-x/chingu-dashboard-be/pull/105)
- Update email templates to use domain in environment variables [#110](https://github.com/chingu-x/chingu-dashboard-be/pull/110)
-Update /forms /forms/id response to include subQuestions [#115](https://github.com/chingu-x/chingu-dashboard-be/pull/115)
- Update /forms /forms/id response to include subQuestions [#115](https://github.com/chingu-x/chingu-dashboard-be/pull/115)
- Add role and permission guard to some existing routes (features, forms, ideations, teams) [#112](https://github.com/chingu-x/chingu-dashboard-be/pull/112)
- Refactor voyages endpoint paths to follow API naming conversion [#123](https://github.com/chingu-x/chingu-dashboard-be/pull/123)
- Refactor resources PATCH and DELETE URI [#127](https://github.com/chingu-x/chingu-dashboard-be/pull/127)
- Modified response for GET voyages/teams/{teamId}/resources, adding user id value [#129](https://github.com/chingu-x/chingu-dashboard-be/pull/129)
- Modified response for POST /api/v1/voyages/teams/{teamId}/techs/{teamTechId} & DELETE /api/v1/voyages/teams/{teamId}/techs/{teamTechId}, refactor id as teamTechStackItemVoteId value [#138](https://github.com/chingu-x/chingu-dashboard-be/pull/138)
- updated meeting model schema to include optional description field [#135](https://github.com/chingu-x/chingu-dashboard-be/pull/135)
- Remove teamMeetings from response for getSprintDatesByTeamId [#139](https://github.com/chingu-x/chingu-dashboard-be/pull/139)
-
Expand Down
18 changes: 11 additions & 7 deletions src/techs/techs.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,11 @@ import { TechsService } from "./techs.service";
import { ApiOperation, ApiParam, ApiResponse, ApiTags } from "@nestjs/swagger";
import { CreateTeamTechDto } from "./dto/create-tech.dto";
import { UpdateTechSelectionsDto } from "./dto/update-tech-selections.dto";
import { TeamTechResponse, TechItemResponse } from "./techs.response";
import {
TeamTechResponse,
TechItemResponse,
TechItemDeleteResponse,
} from "./techs.response";
import {
BadRequestErrorResponse,
ConflictErrorResponse,
Expand Down Expand Up @@ -119,14 +123,14 @@ export class TechsController {
description: "voyage team Id",
type: "Integer",
required: true,
example: 1,
example: 2,
})
@ApiParam({
name: "teamTechId",
description: "techId of a tech the team has select (TeamTechStackItem)",
type: "Integer",
required: true,
example: 11,
example: 6,
})
@Post("/:teamTechId")
addExistingTechVote(
Expand All @@ -143,8 +147,8 @@ export class TechsController {
@ApiResponse({
status: HttpStatus.OK,
description:
"Successfully removed a vote for an existing tech stack item by a user",
type: TechItemResponse,
"Successfully removed a vote for an existing tech stack item by a user or removes the tech stack item if no votes left",
type: TechItemDeleteResponse,
})
@ApiResponse({
status: HttpStatus.NOT_FOUND,
Expand All @@ -166,14 +170,14 @@ export class TechsController {
description: "voyage team Id",
type: "Integer",
required: true,
example: 1,
example: 2,
})
@ApiParam({
name: "teamTechId",
description: "techId of a tech the team has select (TeamTechStackItem)",
type: "Integer",
required: true,
example: 11,
example: 6,
})
@Delete("/:teamTechId")
removeVote(
Expand Down
12 changes: 10 additions & 2 deletions src/techs/techs.response.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,12 +54,12 @@ export class TeamTechResponse {

export class TechItemResponse {
@ApiProperty({ example: 10 })
id: number;
teamTechStackItemVotedId: number;

@ApiProperty({ example: 11 })
teamTechId: number;

@ApiProperty({ example: "Frontend" })
@ApiProperty({ example: 8 })
teamMemberId: number;

@ApiProperty({ example: "2023-12-01T13:55:00.611Z" })
Expand All @@ -68,3 +68,11 @@ export class TechItemResponse {
@ApiProperty({ example: "2023-12-01T13:55:00.611Z" })
updatedAt: Date;
}

export class TechItemDeleteResponse {
@ApiProperty({ example: "The vote and tech stack item were deleted" })
message: string;

@ApiProperty({ example: 200 })
statusCode: number;
}
66 changes: 50 additions & 16 deletions src/techs/techs.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -139,12 +139,20 @@ export class TechsService {
},
});

return this.prisma.teamTechStackItemVote.create({
data: {
teamTechId: newTeamTechItem.id,
teamMemberId: voyageMemberId,
},
});
const TeamTechItemFirstVote =
await this.prisma.teamTechStackItemVote.create({
data: {
teamTechId: newTeamTechItem.id,
teamMemberId: voyageMemberId,
},
});
return {
teamTechStackItemVoteId: TeamTechItemFirstVote.id,
teamTechId: newTeamTechItem.id,
teamMemberId: TeamTechItemFirstVote.teamMemberId,
createdAt: TeamTechItemFirstVote.createdAt,
updatedAt: TeamTechItemFirstVote.updatedAt,
};
} catch (e) {
if (e.code === "P2002") {
throw new ConflictException(
Expand All @@ -156,16 +164,33 @@ export class TechsService {
}

async addExistingTechVote(req, teamId, teamTechId) {
// check if team tech item exists
const teamTechItem = await this.prisma.teamTechStackItem.findUnique({
where: {
id: teamTechId,
},
});
if (!teamTechItem)
throw new BadRequestException("Team Tech Item not found");
const voyageMemberId = await this.findVoyageMemberId(req, teamId);
if (!voyageMemberId) throw new BadRequestException("Invalid User");

try {
return await this.prisma.teamTechStackItemVote.create({
data: {
teamTechId,
teamMemberId: voyageMemberId,
},
});
const teamMemberTechVote =
await this.prisma.teamTechStackItemVote.create({
data: {
teamTechId,
teamMemberId: voyageMemberId,
},
});
// If successful, it returns an object containing the details of the vote
return {
teamTechStackItemVoteId: teamMemberTechVote.id,
teamTechId,
teamMemberId: teamMemberTechVote.teamMemberId,
createdAt: teamMemberTechVote.createdAt,
updatedAt: teamMemberTechVote.updatedAt,
};
} catch (e) {
if (e.code === "P2002") {
throw new ConflictException(
Expand All @@ -181,7 +206,7 @@ export class TechsService {
if (!voyageMemberId) throw new BadRequestException("Invalid User");

try {
const deletedVote = await this.prisma.teamTechStackItemVote.delete({
await this.prisma.teamTechStackItemVote.delete({
where: {
userTeamStackVote: {
teamTechId,
Expand All @@ -201,15 +226,24 @@ export class TechsService {
},
},
);

// Check if the teamTechStackItemVotes array is empty
if (teamTechItem.teamTechStackItemVotes.length === 0) {
return this.prisma.teamTechStackItem.delete({
// If it's empty, delete the tech item from the database using Prisma ORM
await this.prisma.teamTechStackItem.delete({
where: {
id: teamTechId,
},
});

return {
message: "The vote and tech stack item were deleted",
statusCode: 200,
};
} else {
return deletedVote;
return {
message: "This vote was deleted",
statusCode: 200,
};
}
} catch (e) {
if (e.code === "P2025") {
Expand Down
39 changes: 32 additions & 7 deletions test/techs.e2e-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ describe("Techs Controller (e2e)", () => {
.expect((res) => {
expect(res.body).toEqual(
expect.objectContaining({
id: expect.any(Number),
teamTechStackItemVoteId: expect.any(Number),
teamTechId: expect.any(Number),
teamMemberId: expect.any(Number),
createdAt: expect.any(String),
Expand Down Expand Up @@ -228,7 +228,7 @@ describe("Techs Controller (e2e)", () => {
.expect((res) => {
expect(res.body).toEqual(
expect.objectContaining({
id: expect.any(Number),
teamTechStackItemVoteId: expect.any(Number),
teamTechId: expect.any(Number),
teamMemberId: expect.any(Number),
createdAt: expect.any(String),
Expand Down Expand Up @@ -321,11 +321,8 @@ describe("Techs Controller (e2e)", () => {
.expect((res) => {
expect(res.body).toEqual(
expect.objectContaining({
id: expect.any(Number),
teamTechId: expect.any(Number),
teamMemberId: expect.any(Number),
createdAt: expect.any(String),
updatedAt: expect.any(String),
message: "This vote was deleted",
statusCode: 200,
}),
);
});
Expand All @@ -341,6 +338,34 @@ describe("Techs Controller (e2e)", () => {
return expect(techStackVote[0]).toEqual(undefined);
});

it("should return 200 if tech last vote was deleted and team tech stack item is deleted", async () => {
const teamId: number = 2;
const techId: number = 9;
return request(app.getHttpServer())
.delete(`/voyages/teams/${teamId}/techs/${techId}`)
.set("Authorization", `Bearer ${userAccessToken}`)
.expect(200)
.expect("Content-Type", /json/)
.expect((res) => {
expect(res.body).toEqual(
expect.objectContaining({
message:
"The vote and tech stack item were deleted",
statusCode: 200,
}),
);
});
});

it("- verify that tech stack Item was deleted from database", async () => {
const techStackItem = await prisma.teamTechStackItem.findFirst({
where: {
name: newTechName,
},
});
return expect(techStackItem).toBeNull();
});

it("should return 401 unauthorized if not logged in", async () => {
const teamId: number = 2;
const techId: number = 3;
Expand Down
Loading