Skip to content

Commit

Permalink
feat: introduced question and answer api
Browse files Browse the repository at this point in the history
  • Loading branch information
navneethkrish authored and madan-ideas2it committed Sep 9, 2024
1 parent adfb775 commit 485bf53
Show file tree
Hide file tree
Showing 8 changed files with 868 additions and 24 deletions.
402 changes: 402 additions & 0 deletions .forestadmin-schema.json

Large diffs are not rendered by default.

48 changes: 39 additions & 9 deletions apps/web-api/prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ model Team {
eventGuests PLEventGuest[]
teamFocusAreas TeamFocusArea[]
teamFocusAreasVersionHistory TeamFocusAreaVersionHistory[]
relatedQuestions QuestionAndAnswer[] @relation("TeamRelatedQuestionAndAnswers")
}

model Member {
Expand Down Expand Up @@ -88,6 +89,8 @@ model Member {
targetInteractions MemberInteraction[] @relation("TargetMemberInteractions")
followUps MemberFollowUp[]
feedbacks MemberFeedback[]
createdQuestions QuestionAndAnswer[] @relation("MemberCreatedQuestionAndAnswers")
modifiedQuestions QuestionAndAnswer[] @relation("MemberModifiedQuestionAndAnswers")
}

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

model PLEvent {
id Int @id @default(autoincrement())
uid String @unique @default(cuid())
id Int @id @default(autoincrement())
uid String @unique @default(cuid())
type PLEventType?
eventsCount Int?
telegramId String?
logoUid String?
logo Image? @relation("logo", fields: [logoUid], references: [uid])
logo Image? @relation("logo", fields: [logoUid], references: [uid])
bannerUid String?
banner Image? @relation("banner", fields: [bannerUid], references: [uid])
banner Image? @relation("banner", fields: [bannerUid], references: [uid])
name String
description String?
shortDescription String?
websiteURL String?
isFeatured Boolean? @default(false)
isFeatured Boolean? @default(false)
location String
slugURL String @unique
slugURL String @unique
resources Json[]
priority Int?
additionalInfo Json?
startDate DateTime
endDate DateTime
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
eventGuests PLEventGuest[]
relatedQuestions QuestionAndAnswer[] @relation("PLEventRelatedQuestionAndAnswers")
}

model PLEventGuest {
Expand Down Expand Up @@ -500,4 +505,29 @@ model MemberFeedback {
updatedAt DateTime @updatedAt
}


model QuestionAndAnswer {
id Int @id @default(autoincrement())
uid String @unique @default(cuid())
title String?
content String
viewCount Int?
shareCount Int?
slug String @unique
isActive Boolean @default(true)
teamUid String?
team Team? @relation("TeamRelatedQuestionAndAnswers", fields: [teamUid], references: [uid])
projectUid String?
project Project? @relation("ProjectRelatedQuestionAndAnswers", fields: [projectUid], references: [uid])
eventUid String?
plevent PLEvent? @relation("PLEventRelatedQuestionAndAnswers", fields: [eventUid], references: [uid])
createdBy String
creator Member? @relation("MemberCreatedQuestionAndAnswers", fields: [createdBy], references: [uid])
modifiedBy String
modifier Member? @relation("MemberModifiedQuestionAndAnswers", fields: [modifiedBy], references: [uid])
answer String?
answerSources Json[]
answerSourceFrom String?
relatedQuestions Json[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
18 changes: 18 additions & 0 deletions apps/web-api/src/focus-areas/focus-areas.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,15 @@ export class FocusAreasService {
...this.buildTeamFilter(query)
}
},
select: {
team: {
select: {
uid: true,
name: true,
logo: true
}
}
},
distinct: "teamUid"
}
}
Expand All @@ -62,6 +71,15 @@ export class FocusAreasService {
...this.buildProjectFilter(query)
}
},
select: {
project: {
select: {
uid: true,
name: true,
logo: true
}
}
},
distinct: "projectUid"
}
}
Expand Down
94 changes: 91 additions & 3 deletions apps/web-api/src/home/home.controller.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,106 @@
import { Controller, Req } from '@nestjs/common';
import { Controller, Req, Body, Param, UsePipes, UseGuards, ForbiddenException, ConflictException } from '@nestjs/common';
import { Api, initNestServer } from '@ts-rest/nest';
import { ZodValidationPipe } from 'nestjs-zod';
import { Request } from 'express';
import { ApiQueryFromZod } from '../decorators/api-query-from-zod';
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
} 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';

const server = initNestServer(apiHome);
type RouteShape = typeof server.routeShapes;

@Controller()
export class HomeController {
constructor(private homeService: HomeService) {}
constructor(
private homeService: HomeService,
private memberService: MembersService
) {}

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

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


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

@Api(server.route.createQuestionAndAnswer)
@UsePipes(ZodValidationPipe)
@UseGuards(UserTokenValidation)
async addQuestionAndAnswer(
@Body() questionAndAnswer: CreateQuestionAndAnswerSchemaDto,
@Req() request
) {
const userEmail = request["userEmail"];
const member: any = await this.memberService.findMemberByEmail(userEmail);
const result = await this.memberService.checkIfAdminUser(member);
if (!result) {
throw new ForbiddenException(`Member with email ${userEmail} isn't admin`);
}
return await this.homeService.createQuestionAndAnswer(questionAndAnswer as any, member);
}

@Api(server.route.updateQuestionAndAnswer)
@UsePipes(ZodValidationPipe)
@UseGuards(UserTokenValidation)
async modifyQuestionAndAnswer(
@Param('slug') slug: string,
@Body() questionAndAnswer: UpdateQuestionAndAnswerSchemaDto,
@Req() request
) {
const userEmail = request["userEmail"];
const member: any = await this.memberService.findMemberByEmail(userEmail);
const result = await this.memberService.checkIfAdminUser(member);
if (!result) {
throw new ForbiddenException(`Member with email ${userEmail} isn't admin`);
}
return await this.homeService.updateQuestionAndAnswerBySlug(slug, questionAndAnswer 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
) {
return await this.homeService.updateQuestionAndAnswerShareCount(slug);
}
}
Loading

0 comments on commit 485bf53

Please sign in to comment.