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

Solo project GET all endpoint #223

Merged
merged 20 commits into from
Nov 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
8e9142b
generate solo project module. [WIP] Get endpoint
cherylli Oct 21, 2024
e5ecd4e
refactor(solo-projects.service.ts): restructure user and solo project…
cherylli Oct 22, 2024
5a596cd
feat(prisma): add authorId to solo project seeds for better data inte…
cherylli Oct 22, 2024
a715e20
move shared functions to global
cherylli Oct 23, 2024
7c04a4b
feat(prisma): add solo project seeding logic to populate sample data …
cherylli Oct 23, 2024
c2c2b39
add IntDefaultValue pipe to parse empty values on swagger
cherylli Oct 23, 2024
f7e796a
Merge branch 'dev' of github-personal:chingu-x/chingu-dashboard-be in…
cherylli Oct 27, 2024
c3e1365
feat(prisma/seed/voyage-teams.ts): add support for adding tech stack …
cherylli Nov 6, 2024
7affc3b
[WIP] Add sorting to get solo project
cherylli Nov 12, 2024
4b6f27d
refactor: move parseSortString and sortMap to global module
cherylli Nov 12, 2024
6d8fd5e
clean up comments
cherylli Nov 13, 2024
6f0becb
feat(solo-project.types.ts): extend SoloProjectWithPayload type to in…
cherylli Nov 13, 2024
ff6ed91
feat(prisma/seed/forms/solo-project.ts): add new question for "Tier" …
cherylli Nov 14, 2024
574d1ba
feat(global/global.service.ts): add support for retrieving discord an…
cherylli Nov 14, 2024
3e6da0a
feat(solo-projects.response.ts): add parentCommentId property to Comm…
cherylli Nov 17, 2024
0586689
fix(global.service.ts): change InternalServerErrorException to BadReq…
cherylli Nov 20, 2024
06899a1
Merge branch 'dev' of github-personal:chingu-x/chingu-dashboard-be in…
cherylli Nov 20, 2024
65e9cc8
update change log
cherylli Nov 20, 2024
a9d3ddf
chore: remove unused file 'test/solo-projects.e2e-spec.ts'
cherylli Nov 20, 2024
26dfcff
skip solo project tests
cherylli Nov 20, 2024
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
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
Loading