Skip to content

Commit

Permalink
Merge pull request #223 from chingu-x/feature/solo-project-endpoints
Browse files Browse the repository at this point in the history
Solo project GET all endpoint
  • Loading branch information
cherylli authored Nov 22, 2024
2 parents 21f7ad4 + 26dfcff commit 5cab23e
Show file tree
Hide file tree
Showing 21 changed files with 623 additions and 2 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,13 @@
- Added same site property to the clear cookies function ([#218](https://github.com/chingu-x/chingu-dashboard-be/pull/218))
- Added routes for teams to create own tech stack categories([#208](https://github.com/chingu-x/chingu-dashboard-be/pull/208))
- Added unit tests for Features controller and services ([#220](https://github.com/chingu-x/chingu-dashboard-be/pull/220))
- Added GET endpoint for solo project ([#223](https://github.com/chingu-x/chingu-dashboard-be/pull/223))

### Changed
- Updated cors origin list ([#218](https://github.com/chingu-x/chingu-dashboard-be/pull/218))
- refactored unit tests for the ideations controller and services([#219](https://github.com/chingu-x/chingu-dashboard-be/pull/219))
- revised tech selections route to update only one tech per request([#221](https://github.com/chingu-x/chingu-dashboard-be/pull/221))

### Fixed

### Removed
Expand Down
10 changes: 10 additions & 0 deletions prisma/seed/forms/solo-project.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,16 @@ export const populateSoloProjectForm = async () => {
text: "Deployed Url",
answerRequired: true,
},
{
order: 3,
inputType: {
connect: {
name: "radio",
},
},
text: "Tier",
answerRequired: true,
},
],
},
},
Expand Down
1 change: 0 additions & 1 deletion prisma/seed/responses/helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,6 @@ export const populateQuestionResponses = async (
}
case "teamMembersCheckbox": {
if (teamMemberId === 0) {
console.log(question);
throw new Error(
`teamMemberId required for input type ${question.inputType.name} (question id:${question.id}).`,
);
Expand Down
64 changes: 64 additions & 0 deletions prisma/seed/solo-project.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ export const populateSoloProjects = async () => {
select: {
id: true,
questions: {
orderBy: {
order: "asc",
},
select: {
id: true,
},
Expand Down Expand Up @@ -58,10 +61,12 @@ export const populateSoloProjects = async () => {
createMany: {
data: [
{
authorId: users[1].id,
content: "This is a tier 2 project, not tier 3",
type: "SoloProject",
},
{
authorId: users[2].id,
content: "ok",
parentCommentId: 1,
type: "SoloProject",
Expand Down Expand Up @@ -123,5 +128,64 @@ export const populateSoloProjects = async () => {
},
});

// Solo Project 3 (with option choices)
const responseGroup3 = await prisma.responseGroup.create({
data: {
responses: {
createMany: {
data: [
{
questionId: soloProjectForm!.questions[0].id,
text: "www.github.com/repo3",
},
{
questionId: soloProjectForm!.questions[1].id,
text: "www.vercel.com/3",
},
{
questionId: soloProjectForm!.questions[2].id,
optionChoiceId: 44,
},
],
},
},
},
});

await prisma.soloProject.create({
data: {
userId: users[6].id,
evaluatorUserId: users[3].id,
evaluatorFeedback: passedSampleFeedback,
statusId: (await prisma.soloProjectStatus.findUnique({
where: {
status: "Requested Changes",
},
}))!.id,
formId: soloProjectForm!.id,
responseGroupId: responseGroup3.id,
},
});

const statuses = await prisma.soloProjectStatus.findMany({});

for (let i = 0; i < 40; i++) {
await prisma.soloProject.create({
data: {
userId: users[5].id,
evaluatorUserId: users[2].id,
evaluatorFeedback: passedSampleFeedback,
statusId: (await prisma.soloProjectStatus.findUnique({
where: {
status: statuses[
Math.floor(Math.random() * statuses.length)
].status,
},
}))!.id,
formId: soloProjectForm!.id,
},
});
}

console.log("Solo projects populated.");
};
2 changes: 1 addition & 1 deletion prisma/seed/voyage-teams.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1532,7 +1532,7 @@ export const populateVoyageTeams = async () => {
},
});

//Add Tech Stack Categories
//Add Tech Stack Categories
for (let teamId = 1; teamId <= 11; teamId += 1) {
for (const category of techStackCategoriesData) {
category.voyageTeamId = teamId;
Expand Down
2 changes: 2 additions & 0 deletions src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import { DevelopmentModule } from "./development/development.module";
import { AppConfigModule } from "./config/app/appConfig.module";
import { MailConfigModule } from "./config/mail/mailConfig.module";
import { DbConfigModule } from "./config/database/dbConfig.module";
import { SoloProjectsModule } from "./solo-projects/solo-projects.module";

@Module({
imports: [
Expand Down Expand Up @@ -64,6 +65,7 @@ import { DbConfigModule } from "./config/database/dbConfig.module";
VoyagesModule,
AbilityModule,
DevelopmentModule,
SoloProjectsModule,
],
controllers: [HealthCheckController],
providers: [
Expand Down
12 changes: 12 additions & 0 deletions src/global/constants/sortMaps.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/*
key - a more user friendly name for sort field
value - prisma sort field
sorting is only supported for fields listed here
*/
export const soloProjectSortMap: Map<string, string> = new Map(
Object.entries({
status: "statusId",
createdAt: "createdAt",
updatedAt: "updatedAt",
}),
);
57 changes: 57 additions & 0 deletions src/global/global.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
import { PrismaService } from "@/prisma/prisma.service";
import { CustomRequest } from "./types/CustomRequest";
import { FormResponseDto } from "./dtos/FormResponse.dto";
import { UserWithProfile } from "@/global/types/users.types";

@Injectable()
export class GlobalService {
Expand Down Expand Up @@ -193,4 +194,60 @@ export class GlobalService {

return dbItem;
};

public formatUser = (user: UserWithProfile) => {
return {
firstname: user.firstName,
lastname: user.lastName,
email: user.email,
discordId: user.oAuthProfiles?.find(
(profile) => profile.provider.name === "discord",
)?.providerUserId,
discordUsername: user.oAuthProfiles?.find(
(profile) => profile.provider.name === "discord",
)?.providerUsername,
github: user.oAuthProfiles?.find(
(profile) => profile.provider.name === "github",
)?.providerUsername,
};
};

public formatResponses = (responses: any) => {
return responses?.map((response: any) => {
return {
question: response.question.text,
inputType: response.question.inputType.name,
text: response.text,
number: response.numeric,
boolean: response.boolean,
choice: response.optionChoice?.text || null,
};
});
};

/*
parse sort strings into format usable by prisma
sort string is in the form of "-createdAt;+status"
- for descending, + (or nothing) for ascending
valid sort fields are defined in /src/global/constants/sortMaps.ts
*/
public parseSortString = (
sortString: string,
sortFieldMap: Map<string, string>,
) => {
return sortString.split(";").map((field) => {
const direction = field[0] === "-" ? "desc" : "asc";
const fieldName =
field.charAt(0) === "+" || field.charAt(0) === "-"
? field.slice(1)
: field;
if (!sortFieldMap.get(fieldName))
throw new BadRequestException(
`Sort field ${fieldName} is not valid.`,
);
return {
[sortFieldMap.get(fieldName)!]: direction,
};
});
};
}
13 changes: 13 additions & 0 deletions src/global/selects/users.select.ts
Original file line number Diff line number Diff line change
Expand Up @@ -136,3 +136,16 @@ export const publicUserDetailSelect = {
countryCode: true,
timezone: true,
};

export const userSelectBasicWithSocial = {
firstName: true,
lastName: true,
oAuthProfiles: {
select: {
provider: true,
providerId: true,
providerUserId: true,
providerUsername: true,
},
},
};
24 changes: 24 additions & 0 deletions src/global/types/solo-project.types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { Prisma } from "@prisma/client";
import { userSelectBasicWithSocial } from "@/global/selects/users.select";

export type SoloProjectWithPayload = Prisma.SoloProjectGetPayload<{
include: {
user: {
include: typeof userSelectBasicWithSocial;
};
evaluator: {
include: typeof userSelectBasicWithSocial;
};
status: true;
comments: true;
responseGroup: {
select: {
responses: {
include: {
question: true;
};
};
};
};
};
}>;
14 changes: 14 additions & 0 deletions src/global/types/users.types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { Prisma } from "@prisma/client";

export type UserWithProfile = Prisma.UserGetPayload<{
include: {
oAuthProfiles: {
select: {
provider: true;
providerId: true;
providerUserId: true;
providerUsername: true;
};
};
};
}>;
23 changes: 23 additions & 0 deletions src/pipes/non-negative-int-default-value-pipe.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// This pipe is used to set a default value for a parameter in a route handler.
// Without the pipe, controller returns NaN for optional query, results in default value (in service files) not being applied

import {
ArgumentMetadata,
BadRequestException,
Injectable,
PipeTransform,
} from "@nestjs/common";

@Injectable()
export class NonNegativeIntDefaultValuePipe implements PipeTransform {
constructor(private readonly defaultValue: number) {}

transform(value: string, metadata: ArgumentMetadata): any {
const val = parseInt(value, 10);
if (val < 0)
throw new BadRequestException(
`Invalid ${metadata.data} value. ${metadata.data} must be non negative.`,
);
return isNaN(val) ? this.defaultValue : val;
}
}
1 change: 1 addition & 0 deletions src/solo-projects/dto/create-solo-project.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export class CreateSoloProjectDto {}
4 changes: 4 additions & 0 deletions src/solo-projects/dto/update-solo-project.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { PartialType } from "@nestjs/swagger";
import { CreateSoloProjectDto } from "./create-solo-project.dto";

export class UpdateSoloProjectDto extends PartialType(CreateSoloProjectDto) {}
1 change: 1 addition & 0 deletions src/solo-projects/entities/solo-project.entity.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export class SoloProject {}
20 changes: 20 additions & 0 deletions src/solo-projects/solo-projects.controller.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { Test, TestingModule } from "@nestjs/testing";
import { SoloProjectsController } from "./solo-projects.controller";
import { SoloProjectsService } from "./solo-projects.service";

describe("SoloProjectsController", () => {
let controller: SoloProjectsController;

beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
controllers: [SoloProjectsController],
providers: [SoloProjectsService],
}).compile();

controller = module.get<SoloProjectsController>(SoloProjectsController);
});

xit("should be defined", () => {
expect(controller).toBeDefined();
});
});
Loading

0 comments on commit 5cab23e

Please sign in to comment.