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 voyage/features endpoints to follow RESTful api naming convention #123

Merged
merged 7 commits into from
Mar 27, 2024
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ Another example [here](https://co-pilot.dev/changelog)
- 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)
- 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)

### Fixed

Expand Down
12 changes: 9 additions & 3 deletions src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,16 @@ import { TasksModule } from "./tasks/tasks.module";
{
path: "voyages",
children: [
{ path: ":teamId/resources", module: ResourcesModule },
{ path: ":teamId/techs", module: TechsModule },
{
path: "teams/:teamId/resources",
module: ResourcesModule,
},
{ path: "teams/:teamId/techs", module: TechsModule },
{ path: "/", module: FeaturesModule },
{ path: ":teamId/ideations", module: IdeationsModule },
{
path: "teams/:teamId/ideations",
module: IdeationsModule,
},
{ path: "sprints", module: SprintsModule },
],
},
Expand Down
4 changes: 2 additions & 2 deletions src/features/features.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ export class FeaturesController {
type: FeatureResponse,
})
@Permissions(AppPermissions.OWN_TEAM)
@Post("/:teamId/features")
@Post("/teams/:teamId/features")
@ApiCreatedResponse({ type: Feature })
async createFeature(
@Request() req: CustomRequest,
Expand Down Expand Up @@ -120,7 +120,7 @@ export class FeaturesController {
type: NotFoundErrorResponse,
})
@Permissions(AppPermissions.OWN_TEAM)
@Get("/:teamId/features")
@Get("/teams/:teamId/features")
findAllFeatures(@Param("teamId", ParseIntPipe) teamId: number) {
return this.featuresService.findAllFeatures(teamId);
}
Expand Down
35 changes: 24 additions & 11 deletions src/users/users.controller.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
import {
BadRequestException,
Body,
Controller,
Get,
HttpStatus,
NotFoundException,
Param,
Post,
Request,
} from "@nestjs/common";
import { UsersService } from "./users.service";
import { ApiOperation, ApiParam, ApiResponse, ApiTags } from "@nestjs/swagger";
import { ApiBody, ApiOperation, ApiParam, ApiResponse, ApiTags } from "@nestjs/swagger";

import { FullUserResponse, PrivateUserResponse } from "./users.response";
import {
Expand Down Expand Up @@ -92,7 +95,7 @@ export class UsersController {
example: "6bd33861-04c0-4270-8e96-62d4fb587527",
})
@Roles(AppRoles.Admin)
@Get("id/:userId")
@Get("/:userId")
getUserDetailsById(@Param("userId") userId: string) {
if (!isUUID(userId))
throw new BadRequestException(`${userId} is not a valid UUID.`);
Expand All @@ -104,7 +107,7 @@ export class UsersController {
description: "This is currently only for development/admin",
})
@ApiResponse({
status: HttpStatus.OK,
status: HttpStatus.CREATED,
timDeHof marked this conversation as resolved.
Show resolved Hide resolved
description: "Successfully gets the full user detail given an email.",
isArray: true,
type: FullUserResponse,
Expand All @@ -119,17 +122,27 @@ export class UsersController {
description: "Given email is not a valid email.",
type: BadRequestErrorResponse,
})
@ApiParam({
name: "email",
required: true,
description: "email",
example: "jessica.williamson@gmail.com",
@ApiBody({
schema: {
type: "object",
properties: {
email: {
type: "string",
description: "email",
},
},
},
})
@Roles(AppRoles.Admin)
@Get("email/:email")
getUserDetailsByEmail(@Param("email") email: string) {
@Post("/lookup-by-email")
async getUserDetailsByEmail(@Body("email") email: string) {
timDeHof marked this conversation as resolved.
Show resolved Hide resolved
if (!isEmail(email))
throw new BadRequestException(`${email} is not a valid Email.`);
return this.usersService.getUserDetailsByEmail(email);
const userDetails =
await this.usersService.getUserDetailsByEmail(email);
if (!userDetails) {
throw new NotFoundException(`User not found`);
}
return userDetails;
}
}
2 changes: 1 addition & 1 deletion src/users/users.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ export class UsersService {
});

if (!user) {
throw new NotFoundException(`User (email: ${email} not found`);
throw new NotFoundException(`User with ${email} not found`);
}

return this.formatUser(user);
Expand Down
28 changes: 16 additions & 12 deletions test/ideations.e2e-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ describe("IdeationsController (e2e)", () => {
await reseed();
});

it("/POST voyages/:teamId/ideations", async () => {
it("/POST voyages/teams/:teamId/ideations", async () => {
await prisma.projectIdea.delete({
where: {
id: newIdeation.id,
Expand All @@ -209,7 +209,7 @@ describe("IdeationsController (e2e)", () => {
};

return request(app.getHttpServer())
.post(`/voyages/${teamId}/ideations`)
.post(`/voyages/teams/${teamId}/ideations`)
.set("Authorization", `Bearer ${newUserAccessToken}`)
.send(createIdeationDto)
.expect(201)
Expand All @@ -223,7 +223,7 @@ describe("IdeationsController (e2e)", () => {
});
});

it("/POST voyages/:teamId/ideations/:ideationId/ideation-votes", async () => {
it("/POST voyages/teams/:teamId/ideations/:ideationId/ideation-votes", async () => {
await prisma.projectIdeaVote.delete({
where: {
id: newIdeationVote.id,
Expand All @@ -234,7 +234,9 @@ describe("IdeationsController (e2e)", () => {
const ideationId: number = newIdeation.id;

return request(app.getHttpServer())
.post(`/voyages/${teamId}/ideations/${ideationId}/ideation-votes`)
.post(
`/voyages/teams/${teamId}/ideations/${ideationId}/ideation-votes`,
)
.set("Authorization", `Bearer ${newUserAccessToken}`)
.expect(201)
.expect("Content-Type", /json/)
Expand All @@ -243,7 +245,7 @@ describe("IdeationsController (e2e)", () => {
});
});

it("/GET voyages/:teamId/ideations", async () => {
it("/GET voyages/teams/:teamId/ideations", async () => {
const teamId: number = newVoyageTeam.id;
const ideationCount: number = await prisma.projectIdea.count({
where: {
Expand All @@ -254,7 +256,7 @@ describe("IdeationsController (e2e)", () => {
});

return request(app.getHttpServer())
.get(`/voyages/${teamId}/ideations`)
.get(`/voyages/teams/${teamId}/ideations`)
.set("Authorization", `Bearer ${newUserAccessToken}`)
.expect(200)
.expect("Content-Type", /json/)
Expand All @@ -274,7 +276,7 @@ describe("IdeationsController (e2e)", () => {
});
});

it("/PATCH :teamId/ideations/:ideationId", async () => {
it("/PATCH /teams/:teamId/ideations/:ideationId", async () => {
const teamId: number = newVoyageTeam.id;
const ideationId: number = newIdeation.id;
const updateIdeationDto: UpdateIdeationDto = {
Expand All @@ -284,7 +286,7 @@ describe("IdeationsController (e2e)", () => {
};

return request(app.getHttpServer())
.patch(`/voyages/${teamId}/ideations/${ideationId}`)
.patch(`/voyages/teams/${teamId}/ideations/${ideationId}`)
.set("Authorization", `Bearer ${newUserAccessToken}`)
.send(updateIdeationDto)
.expect(200)
Expand All @@ -298,12 +300,12 @@ describe("IdeationsController (e2e)", () => {
});
});

it("/DELETE :teamId/ideations/:ideationId", async () => {
it("/DELETE /teams/:teamId/ideations/:ideationId", async () => {
const teamId: number = newVoyageTeam.id;
const ideationId: number = newIdeation.id;

return request(app.getHttpServer())
.delete(`/voyages/${teamId}/ideations/${ideationId}`)
.delete(`/voyages/teams/${teamId}/ideations/${ideationId}`)
.set("Authorization", `Bearer ${newUserAccessToken}`)
.expect((res) => {
expect(res.body).toEqual({
Expand All @@ -314,12 +316,14 @@ describe("IdeationsController (e2e)", () => {
});
});

it("/DELETE voyages/:teamId/ideations/:ideationId/ideation-votes", async () => {
it("/DELETE voyages/teams/:teamId/ideations/:ideationId/ideation-votes", async () => {
const teamId: number = newVoyageTeam.id;
const ideationId: number = newIdeation.id;

return request(app.getHttpServer())
.delete(`/voyages/${teamId}/ideations/${ideationId}/ideation-votes`)
.delete(
`/voyages/teams/${teamId}/ideations/${ideationId}/ideation-votes`,
)
.set("Authorization", `Bearer ${newUserAccessToken}`)
.expect(200)
.expect("Content-Type", /json/)
Expand Down
32 changes: 16 additions & 16 deletions test/techs.e2e-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,12 +53,12 @@ describe("Techs Controller (e2e)", () => {
beforeEach(async () => {
await loginUser();
});
describe("voyages/:teamId/techs", () => {
describe("voyages/teams/:teamId/techs", () => {
it("GET - 200 returns array of tech categories, populated with techs and votes", async () => {
const teamId: number = 2;

return await request(app.getHttpServer())
.get(`/voyages/${teamId}/techs`)
.get(`/voyages/teams/${teamId}/techs`)
.set("Authorization", `Bearer ${userAccessToken}`)
.expect(200)
.expect("Content-Type", /json/)
Expand Down Expand Up @@ -113,7 +113,7 @@ describe("Techs Controller (e2e)", () => {
const teamId: number = 2;

return request(app.getHttpServer())
.post(`/voyages/${teamId}/techs`)
.post(`/voyages/teams/${teamId}/techs`)
.set("Authorization", `Bearer ${userAccessToken}`)
.send({
techName: newTechName,
Expand Down Expand Up @@ -148,7 +148,7 @@ describe("Techs Controller (e2e)", () => {
const teamId: number = 2;

return request(app.getHttpServer())
.post(`/voyages/${teamId}/techs`)
.post(`/voyages/teams/${teamId}/techs`)
.set("Authorization", `Bearer ${undefined}`)
.send({
techName: newTechName,
Expand All @@ -170,7 +170,7 @@ describe("Techs Controller (e2e)", () => {
const teamId: number = 9999999;

return request(app.getHttpServer())
.post(`/voyages/${teamId}/techs`)
.post(`/voyages/teams/${teamId}/techs`)
.set("Authorization", `Bearer ${userAccessToken}`)
.send({
techName: newTechName,
Expand All @@ -193,7 +193,7 @@ describe("Techs Controller (e2e)", () => {
const teamId: number = 2;

return request(app.getHttpServer())
.post(`/voyages/${teamId}/techs`)
.post(`/voyages/teams/${teamId}/techs`)
.set("Authorization", `Bearer ${userAccessToken}`)
.send({
techName: newTechName,
Expand All @@ -213,13 +213,13 @@ describe("Techs Controller (e2e)", () => {
});
});

describe("voyages/:teamId/techs/:teamTechId", () => {
describe("voyages/teams/:teamId/techs/:teamTechId", () => {
it("POST - 200 vote for tech", async () => {
const teamId: number = 2;
const techId: number = 3;

return request(app.getHttpServer())
.post(`/voyages/${teamId}/techs/${techId}`)
.post(`/voyages/teams/${teamId}/techs/${techId}`)
.set("Authorization", `Bearer ${userAccessToken}`)
.expect(201)
.expect("Content-Type", /json/)
Expand Down Expand Up @@ -251,7 +251,7 @@ describe("Techs Controller (e2e)", () => {
const techId: number = 3;

return request(app.getHttpServer())
.post(`/voyages/${teamId}/techs/${techId}`)
.post(`/voyages/teams/${teamId}/techs/${techId}`)
.set("Authorization", `Bearer ${undefined}`)
.expect(401)
.expect("Content-Type", /json/)
Expand All @@ -270,7 +270,7 @@ describe("Techs Controller (e2e)", () => {
const techId: number = 3;

return request(app.getHttpServer())
.post(`/voyages/${teamId}/techs/${techId}`)
.post(`/voyages/teams/${teamId}/techs/${techId}`)
.set("Authorization", `Bearer ${userAccessToken}`)
.expect(400)
.expect("Content-Type", /json/)
Expand All @@ -290,7 +290,7 @@ describe("Techs Controller (e2e)", () => {
const techId: number = 3;

return request(app.getHttpServer())
.post(`/voyages/${teamId}/techs/${techId}`)
.post(`/voyages/teams/${teamId}/techs/${techId}`)
.set("Authorization", `Bearer ${userAccessToken}`)
.expect(409)
.expect("Content-Type", /json/)
Expand All @@ -306,13 +306,13 @@ describe("Techs Controller (e2e)", () => {
});
});

describe("voyages/:teamId/techs/:teamTechId", () => {
describe("voyages/teams/:teamId/techs/:teamTechId", () => {
it("DELETE - 200 tech vote deleted", async () => {
const teamId: number = 2;
const techId: number = 3;

return request(app.getHttpServer())
.delete(`/voyages/${teamId}/techs/${techId}`)
.delete(`/voyages/teams/${teamId}/techs/${techId}`)
.set("Authorization", `Bearer ${userAccessToken}`)
.expect(200)
.expect("Content-Type", /json/)
Expand Down Expand Up @@ -344,7 +344,7 @@ describe("Techs Controller (e2e)", () => {
const techId: number = 3;

return request(app.getHttpServer())
.delete(`/voyages/${teamId}/techs/${techId}`)
.delete(`/voyages/teams/${teamId}/techs/${techId}`)
.set("Authorization", `Bearer ${undefined}`)
.expect(401)
.expect("Content-Type", /json/)
Expand All @@ -363,7 +363,7 @@ describe("Techs Controller (e2e)", () => {
const techId: number = 3;

return request(app.getHttpServer())
.delete(`/voyages/${teamId}/techs/${techId}`)
.delete(`/voyages/teams/${teamId}/techs/${techId}`)
.set("Authorization", `Bearer ${userAccessToken}`)
.expect(400)
.expect("Content-Type", /json/)
Expand All @@ -383,7 +383,7 @@ describe("Techs Controller (e2e)", () => {
const techId: number = 3;

return request(app.getHttpServer())
.delete(`/voyages/${teamId}/techs/${techId}`)
.delete(`/voyages/teams/${teamId}/techs/${techId}`)
.set("Authorization", `Bearer ${userAccessToken}`)
.expect(404)
.expect("Content-Type", /json/)
Expand Down
Loading
Loading