Skip to content

Commit

Permalink
feat: introduced bio field in member
Browse files Browse the repository at this point in the history
  • Loading branch information
navneethkrish committed Sep 2, 2024
1 parent 56ba696 commit 0eab92d
Show file tree
Hide file tree
Showing 14 changed files with 1,901 additions and 1,814 deletions.
3,124 changes: 1,578 additions & 1,546 deletions .forestadmin-schema.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions apps/web-api/prisma/fixtures/members.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ const membersFactory = Factory.define<Omit<Member, 'id'>>(
plnFriend: faker.datatype.boolean(),
airtableRecId: `airtable-rec-id-${sequence}`,
externalId: null,
bio: faker.datatype.string(),
isFeatured: faker.datatype.boolean(),
createdAt: faker.date.past(),
approvedAt: faker.date.past(),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
-- AlterTable
ALTER TABLE "Member" ADD COLUMN "bio" TEXT;

-- CreateTable
CREATE TABLE "DiscoveryQuestion" (
"id" SERIAL NOT NULL,
"uid" TEXT NOT NULL,
"title" TEXT,
"content" TEXT NOT NULL,
"viewCount" INTEGER,
"shareCount" INTEGER,
"slug" TEXT NOT NULL,
"isActive" BOOLEAN NOT NULL DEFAULT true,
"teamUid" TEXT,
"projectUid" TEXT,
"eventUid" TEXT,
"createdBy" TEXT NOT NULL,
"modifiedBy" TEXT NOT NULL,
"answer" TEXT,
"answerSources" JSONB[],
"answerSourceFrom" TEXT,
"relatedQuestions" JSONB[],
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,

CONSTRAINT "DiscoveryQuestion_pkey" PRIMARY KEY ("id")
);

-- CreateIndex
CREATE UNIQUE INDEX "DiscoveryQuestion_uid_key" ON "DiscoveryQuestion"("uid");

-- CreateIndex
CREATE UNIQUE INDEX "DiscoveryQuestion_slug_key" ON "DiscoveryQuestion"("slug");

-- AddForeignKey
ALTER TABLE "DiscoveryQuestion" ADD CONSTRAINT "DiscoveryQuestion_teamUid_fkey" FOREIGN KEY ("teamUid") REFERENCES "Team"("uid") ON DELETE SET NULL ON UPDATE CASCADE;

-- AddForeignKey
ALTER TABLE "DiscoveryQuestion" ADD CONSTRAINT "DiscoveryQuestion_projectUid_fkey" FOREIGN KEY ("projectUid") REFERENCES "Project"("uid") ON DELETE SET NULL ON UPDATE CASCADE;

-- AddForeignKey
ALTER TABLE "DiscoveryQuestion" ADD CONSTRAINT "DiscoveryQuestion_eventUid_fkey" FOREIGN KEY ("eventUid") REFERENCES "PLEvent"("uid") ON DELETE SET NULL ON UPDATE CASCADE;

-- AddForeignKey
ALTER TABLE "DiscoveryQuestion" ADD CONSTRAINT "DiscoveryQuestion_createdBy_fkey" FOREIGN KEY ("createdBy") REFERENCES "Member"("uid") ON DELETE RESTRICT ON UPDATE CASCADE;

-- AddForeignKey
ALTER TABLE "DiscoveryQuestion" ADD CONSTRAINT "DiscoveryQuestion_modifiedBy_fkey" FOREIGN KEY ("modifiedBy") REFERENCES "Member"("uid") ON DELETE RESTRICT ON UPDATE CASCADE;
23 changes: 12 additions & 11 deletions apps/web-api/prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ model Team {
eventGuests PLEventGuest[]
teamFocusAreas TeamFocusArea[]
teamFocusAreasVersionHistory TeamFocusAreaVersionHistory[]
relatedQuestions QuestionAndAnswer[] @relation("TeamRelatedQuestionAndAnswers")
relatedQuestions DiscoveryQuestion[] @relation("TeamRelatedDiscoveryQuestions")
}

model Member {
Expand All @@ -65,6 +65,7 @@ model Member {
telegramHandler String?
officeHours String?
moreDetails String?
bio String?
plnFriend Boolean @default(false)
plnStartDate DateTime?
airtableRecId String? @unique
Expand All @@ -89,8 +90,8 @@ model Member {
targetInteractions MemberInteraction[] @relation("TargetMemberInteractions")
followUps MemberFollowUp[]
feedbacks MemberFeedback[]
createdQuestions QuestionAndAnswer[] @relation("MemberCreatedQuestionAndAnswers")
modifiedQuestions QuestionAndAnswer[] @relation("MemberModifiedQuestionAndAnswers")
createdQuestions DiscoveryQuestion[] @relation("MemberCreatedDiscoveryQuestions")
modifiedQuestions DiscoveryQuestion[] @relation("MemberModifiedDiscoveryQuestions")
}

model MemberRole {
Expand Down Expand Up @@ -338,7 +339,7 @@ model Project {
isFeatured Boolean? @default(false)
projectFocusAreas ProjectFocusArea[]
contributions ProjectContribution[]
relatedQuestions QuestionAndAnswer[] @relation("ProjectRelatedQuestionAndAnswers")
relatedQuestions DiscoveryQuestion[] @relation("ProjectRelatedDiscoveryQuestions")
}

model PLEvent {
Expand Down Expand Up @@ -366,7 +367,7 @@ model PLEvent {
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
eventGuests PLEventGuest[]
relatedQuestions QuestionAndAnswer[] @relation("PLEventRelatedQuestionAndAnswers")
relatedQuestions DiscoveryQuestion[] @relation("PLEventRelatedDiscoveryQuestions")
}

model PLEventGuest {
Expand Down Expand Up @@ -505,7 +506,7 @@ model MemberFeedback {
updatedAt DateTime @updatedAt
}

model QuestionAndAnswer {
model DiscoveryQuestion {
id Int @id @default(autoincrement())
uid String @unique @default(cuid())
title String?
Expand All @@ -515,15 +516,15 @@ model QuestionAndAnswer {
slug String @unique
isActive Boolean @default(true)
teamUid String?
team Team? @relation("TeamRelatedQuestionAndAnswers", fields: [teamUid], references: [uid])
team Team? @relation("TeamRelatedDiscoveryQuestions", fields: [teamUid], references: [uid])
projectUid String?
project Project? @relation("ProjectRelatedQuestionAndAnswers", fields: [projectUid], references: [uid])
project Project? @relation("ProjectRelatedDiscoveryQuestions", fields: [projectUid], references: [uid])
eventUid String?
plevent PLEvent? @relation("PLEventRelatedQuestionAndAnswers", fields: [eventUid], references: [uid])
plevent PLEvent? @relation("PLEventRelatedDiscoveryQuestions", fields: [eventUid], references: [uid])
createdBy String
creator Member? @relation("MemberCreatedQuestionAndAnswers", fields: [createdBy], references: [uid])
creator Member? @relation("MemberCreatedDiscoveryQuestions", fields: [createdBy], references: [uid])
modifiedBy String
modifier Member? @relation("MemberModifiedQuestionAndAnswers", fields: [modifiedBy], references: [uid])
modifier Member? @relation("MemberModifiedDiscoveryQuestions", fields: [modifiedBy], references: [uid])
answer String?
answerSources Json[]
answerSourceFrom String?
Expand Down
2 changes: 2 additions & 0 deletions apps/web-api/src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import { EmptyStringToNullInterceptor } from './interceptors/empty-string-to-nul
import { OfficeHoursModule } from './office-hours/office-hours.module';
import { MemberFollowUpsModule } from './member-follow-ups/member-follow-ups.module';
import { MemberFeedbacksModule } from './member-feedbacks/member-feedbacks.module';
import { HuskyModule } from './husky/husky.module';
import { HomeModule } from './home/home.module';

@Module({
Expand Down Expand Up @@ -92,6 +93,7 @@ import { HomeModule } from './home/home.module';
OfficeHoursModule,
MemberFollowUpsModule,
MemberFeedbacksModule,
HuskyModule,
HomeModule
],
providers: [
Expand Down
78 changes: 41 additions & 37 deletions apps/web-api/src/home/home.controller.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Controller, Req, Body, Param, UsePipes, UseGuards, ForbiddenException, ConflictException } from '@nestjs/common';
import { Controller, Req, Body, Param, UsePipes, UseGuards, ForbiddenException, BadRequestException } from '@nestjs/common';
import { Api, initNestServer } from '@ts-rest/nest';
import { ZodValidationPipe } from 'nestjs-zod';
import { Request } from 'express';
Expand All @@ -7,17 +7,18 @@ import { ApiOkResponseFromZod } from '../decorators/api-response-from-zod';
import { apiHome } from 'libs/contracts/src/lib/contract-home';
import { HomeService } from './home.service';
import {
QuestionAndAnswerQueryParams,
ResponseQuestionAndAnswerSchemaWithRelations,
ResponseQuestionAndAnswerSchema,
CreateQuestionAndAnswerSchemaDto,
UpdateQuestionAndAnswerSchemaDto
DiscoveryQuestionQueryParams,
ResponseDiscoveryQuestionSchemaWithRelations,
ResponseDiscoveryQuestionSchema,
CreateDiscoveryQuestionSchemaDto,
UpdateDiscoveryQuestionSchemaDto
} from 'libs/contracts/src/schema';
import { UserTokenValidation } from '../guards/user-token-validation.guard';
import { MembersService } from '../members/members.service';
import { NoCache } from '../decorators/no-cache.decorator';
import { PrismaQueryBuilder } from '../utils/prisma-query-builder';
import { prismaQueryableFieldsFromZod } from '../utils/prisma-queryable-fields-from-zod';
import { HuskyService } from '../husky/husky.service';

const server = initNestServer(apiHome);
type RouteShape = typeof server.routeShapes;
Expand All @@ -26,42 +27,43 @@ type RouteShape = typeof server.routeShapes;
export class HomeController {
constructor(
private homeService: HomeService,
private memberService: MembersService
private memberService: MembersService,
private huskyService: HuskyService
) {}

@Api(server.route.getAllFeaturedData)
async getAllFeaturedData() {
return await this.homeService.fetchAllFeaturedData();
}

@Api(server.route.getAllQuestionAndAnswers)
@ApiQueryFromZod(QuestionAndAnswerQueryParams)
@ApiOkResponseFromZod(ResponseQuestionAndAnswerSchemaWithRelations.array())
@Api(server.route.getAllDiscoveryQuestions)
@ApiQueryFromZod(DiscoveryQuestionQueryParams)
@ApiOkResponseFromZod(ResponseDiscoveryQuestionSchemaWithRelations.array())
@NoCache()
async getQuestionAndAnswers(@Req() request: Request) {
async getDiscoveryQuestions(@Req() request: Request) {
const queryableFields = prismaQueryableFieldsFromZod(
ResponseQuestionAndAnswerSchema
ResponseDiscoveryQuestionSchema
);
const builder = new PrismaQueryBuilder(queryableFields);
const builtQuery = builder.build(request.query);
return await this.homeService.fetchQuestionAndAnswers(builtQuery);
return await this.huskyService.fetchDiscoverQuestions(builtQuery);
}


@Api(server.route.getQuestionAndAnswer)
@ApiQueryFromZod(QuestionAndAnswerQueryParams)
@ApiOkResponseFromZod(ResponseQuestionAndAnswerSchemaWithRelations)
@Api(server.route.getDiscoveryQuestion)
@ApiQueryFromZod(DiscoveryQuestionQueryParams)
@ApiOkResponseFromZod(ResponseDiscoveryQuestionSchemaWithRelations)
@NoCache()
async getQuestionAndAnswer(@Param('slug') slug: string)
async getDiscoveryQuestion(@Param('slug') slug: string)
{
return await this.homeService.fetchQuestionAndAnswerBySlug(slug);
return await this.huskyService.fetchDiscoverQuestionBySlug(slug);
}

@Api(server.route.createQuestionAndAnswer)
@Api(server.route.createDiscoveryQuestion)
@UsePipes(ZodValidationPipe)
@UseGuards(UserTokenValidation)
async addQuestionAndAnswer(
@Body() questionAndAnswer: CreateQuestionAndAnswerSchemaDto,
async addDiscoveryQuestion(
@Body() discoveryQuestion: CreateDiscoveryQuestionSchemaDto,
@Req() request
) {
const userEmail = request["userEmail"];
Expand All @@ -70,15 +72,15 @@ export class HomeController {
if (!result) {
throw new ForbiddenException(`Member with email ${userEmail} isn't admin`);
}
return await this.homeService.createQuestionAndAnswer(questionAndAnswer as any, member);
return await this.huskyService.createDiscoverQuestion(discoveryQuestion as any, member);
}

@Api(server.route.updateQuestionAndAnswer)
@Api(server.route.updateDiscoveryQuestion)
@UsePipes(ZodValidationPipe)
@UseGuards(UserTokenValidation)
async modifyQuestionAndAnswer(
async modifyDiscoveryQuestion(
@Param('slug') slug: string,
@Body() questionAndAnswer: UpdateQuestionAndAnswerSchemaDto,
@Body() discoveryQuestion: UpdateDiscoveryQuestionSchemaDto,
@Req() request
) {
const userEmail = request["userEmail"];
Expand All @@ -87,20 +89,22 @@ export class HomeController {
if (!result) {
throw new ForbiddenException(`Member with email ${userEmail} isn't admin`);
}
return await this.homeService.updateQuestionAndAnswerBySlug(slug, questionAndAnswer as any, member);
return await this.huskyService.updateDiscoveryQuestionBySlug(slug, discoveryQuestion as any, member);
}

@Api(server.route.updateQuestionAndAnswerViewCount)
async modifyQuestionAndAnswerViewCount(
@Param('slug') slug: string
) {
return await this.homeService.updateQuestionAndAnswerViewCount(slug);
}

@Api(server.route.updateQuestionAndAnswerShareCount)
async modifyQuestionAndAnswerShareCount(
@Param('slug') slug: string
@Api(server.route.updateDiscoveryQuestionShareCountOrViewCount)
async modifyDiscoveryQuestionShareCountOrViewCount(
@Param('slug') slug: string,
@Body() body
) {
return await this.homeService.updateQuestionAndAnswerShareCount(slug);
const attribute = body.attribute;
switch (attribute) {
case "shareCount":
return this.huskyService.updateDiscoveryQuestionShareCount(slug);
case "viewCount":
return this.huskyService.updateDiscoveryQuestionViewCount(slug);
default:
throw new BadRequestException(`Invalid attribute: ${attribute}`);
}
}
}
4 changes: 3 additions & 1 deletion apps/web-api/src/home/home.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { MembersModule } from '../members/members.module';
import { TeamsModule } from '../teams/teams.module';
import { ProjectsModule} from '../projects/projects.module';
import { PLEventsModule } from '../pl-events/pl-events.module';
import { HuskyModule } from '../husky/husky.module';

@Module({
controllers: [HomeController],
Expand All @@ -15,7 +16,8 @@ import { PLEventsModule } from '../pl-events/pl-events.module';
MembersModule,
TeamsModule,
ProjectsModule,
PLEventsModule
PLEventsModule,
HuskyModule
],
exports: [
HomeService
Expand Down
Loading

0 comments on commit 0eab92d

Please sign in to comment.