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

feat(ask): feature ask implemnetation #2097

Open
wants to merge 1 commit into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
23 changes: 23 additions & 0 deletions apps/web-api/prisma/migrations/20250124072138_ask/migration.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
-- CreateTable
CREATE TABLE "Ask" (
"id" SERIAL NOT NULL,
"uid" TEXT NOT NULL,
"title" TEXT NOT NULL,
"description" TEXT NOT NULL,
"tags" TEXT[],
"teamUid" TEXT,
"projectUid" TEXT,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,

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

-- CreateIndex
CREATE UNIQUE INDEX "Ask_uid_key" ON "Ask"("uid");

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

-- AddForeignKey
ALTER TABLE "Ask" ADD CONSTRAINT "Ask_projectUid_fkey" FOREIGN KEY ("projectUid") REFERENCES "Project"("uid") ON DELETE SET NULL ON UPDATE CASCADE;
16 changes: 16 additions & 0 deletions apps/web-api/prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,22 @@ model Team {
teamFocusAreas TeamFocusArea[]
teamFocusAreasVersionHistory TeamFocusAreaVersionHistory[]
relatedQuestions DiscoveryQuestion[] @relation("TeamRelatedDiscoveryQuestions")
asks Ask[]
}
model Ask {
id Int @id @default(autoincrement())
uid String @unique @default(cuid())
title String
description String
tags String[]
team Team? @relation(fields: [teamUid], references: [uid])
teamUid String?
project Project? @relation(fields: [projectUid], references: [uid])
projectUid String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}


model Member {
id Int @id @default(autoincrement())
Expand Down Expand Up @@ -354,6 +369,7 @@ model Project {
projectFocusAreas ProjectFocusArea[]
contributions ProjectContribution[]
relatedQuestions DiscoveryQuestion[] @relation("ProjectRelatedDiscoveryQuestions")
asks Ask[]
}

model PLEventLocation {
Expand Down
31 changes: 28 additions & 3 deletions apps/web-api/src/projects/projects.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,26 @@ export class ProjectsController {

@Api(server.route.getProjectFilters)
@NoCache()
async getProjectFilters() {
return await this.projectsService.getProjectFilters();
async getProjectFilters(@Req() req) {
// return await this.projectsService.getProjectFilters();
const queryableFields = prismaQueryableFieldsFromZod(
ResponseProjectWithRelationsSchema
);
const builder = new PrismaQueryBuilder(queryableFields);
const builtQuery = builder.build(req.query);
const { focusAreas }: any = req.query;
builtQuery.where = {
AND: [
{
isDeleted: false,
},
builtQuery.where ? builtQuery.where : {},
this.projectsService.buildFocusAreaFilters(focusAreas),
this.projectsService.buildRecentProjectsFilter(req.query),
this.projectsService.buildAskTagFilter(req.query)
]
}
return await this.projectsService.getProjectFilters(builtQuery);
}

@Api(server.route.createProject)
Expand Down Expand Up @@ -60,7 +78,8 @@ export class ProjectsController {
AND: [
builtQuery.where ? builtQuery.where : {},
this.projectsService.buildFocusAreaFilters(focusAreas),
this.projectsService.buildRecentProjectsFilter(req.query)
this.projectsService.buildRecentProjectsFilter(req.query),
this.projectsService.buildAskTagFilter(req.query)
]
}
return this.projectsService.getProjects(builtQuery);
Expand Down Expand Up @@ -89,4 +108,10 @@ export class ProjectsController {
return this.projectsService.removeProjectByUid(uid, request.userEmail);
}

@Api(server.route.patchAskProject)
@UseGuards(UserTokenValidation)
async addEditAsk(@Param('uid') projectUid, @Body() body, @Req() req) {
return await this.projectsService.addEditProjectAsk(projectUid,req.userEmail,body);
}

}
92 changes: 90 additions & 2 deletions apps/web-api/src/projects/projects.service.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/* eslint-disable prettier/prettier */
import { BadRequestException, ConflictException, ForbiddenException, Injectable, NotFoundException } from '@nestjs/common';
import { LogService } from '../shared/log.service';
import { PrismaService } from '../shared/prisma.service';
Expand Down Expand Up @@ -147,6 +148,15 @@ export class ProjectsService {
}
}
}
},
asks: {
select: {
uid: true,
title: true,
description: true,
tags: true,
projectUid: true
}
}
}
});
Expand Down Expand Up @@ -387,12 +397,24 @@ export class ProjectsService {
return {};
}

buildAskTagFilter(queryParams){
const { askTags } = queryParams;
let tagFilter={}
if(askTags){
const tags = askTags.split(',')
tagFilter={
asks: { some: { tags: { hasSome: tags }, }, },
};
}
return tagFilter;
}

/**
* Fetches team names that maintain atleast a single project.
*
* @returns Set of team names.
*/
async getProjectFilters() {
async getProjectFilters(queryParams) {
const maintainingTeams = await this.prisma.team.findMany({
where: {
maintainingProjects: {
Expand All @@ -409,6 +431,72 @@ export class ProjectsService {
}
}
})
return { maintainedBy: maintainingTeams.map((team) => ({ uid: team.uid, name: team.name, logo: team.logo?.url })) };


const askTags = await this.prisma.ask.findMany({
where: {
project: queryParams.where,
},
select: {
tags: true,
},
})
// Flatten the tags and calculate counts
const tagCounts = askTags
.flatMap(item => item.tags) // Flatten the tags array
.reduce((acc, tag) => {
acc[tag] = (acc[tag] || 0) + 1; // Count occurrences
return acc;
}, {});
return {
askTags: Object.entries(tagCounts).map(([tag, count]) => ({ tag, count }))
}
// return { maintainedBy: maintainingTeams.map((team) => ({ uid: team.uid, name: team.name, logo: team.logo?.url })) };
}


async addEditProjectAsk(projectUid, requestorEmail, data){
let res;
try{
//checking if the member has edit access
const member: any = await this.memberService.findMemberByEmail(requestorEmail);
const existingData: any = await this.getProjectByUid(projectUid);
const contributingTeamsUid = existingData?.contributingTeams?.map(team => team.uid) || [];
await this.isMemberAllowedToEdit(
member,
[existingData?.maintainingTeamUid, ...contributingTeamsUid],
existingData
);

if (data.uid) {
if (data.isDeleted) {
//deleting asks
res = await this.prisma.ask.delete({
where: { uid: data.uid },
});
} else {
//updating asks
res = await this.prisma.ask.update({
where: { uid: data.uid },
data: {
...data,
},
});
}
}else{
//creating asks
res = await this.prisma.ask.create({
data: {
...data,
projectUid,
},
});
}
await this.cacheService.reset({ service: 'projects'});
return res;
}catch(err){
console.error(err);
throw err;
}
}
}
15 changes: 13 additions & 2 deletions apps/web-api/src/teams/teams.controller.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/* eslint-disable prettier/prettier */
import { Controller, Req, UseGuards, Body, Param, UsePipes } from '@nestjs/common';
import { ApiNotFoundResponse, ApiParam } from '@nestjs/swagger';
import { Api, ApiDecorator, initNestServer } from '@ts-rest/nest';
Expand Down Expand Up @@ -27,6 +28,7 @@ export class TeamsController {

@Api(server.route.teamFilters)
@ApiQueryFromZod(TeamQueryParams)
@NoCache()
async getTeamFilters(@Req() request: Request) {
const queryableFields = prismaQueryableFieldsFromZod(
ResponseTeamWithRelationsSchema
Expand All @@ -42,7 +44,8 @@ export class TeamsController {
builtQuery.where ? builtQuery.where : {},
this.teamsService.buildFocusAreaFilters(focusAreas),
this.teamsService.buildRecentTeamsFilter(request.query),
this.teamsService.buildParticipationTypeFilter(request.query)
this.teamsService.buildParticipationTypeFilter(request.query),
this.teamsService.buildAskTagFilter(request.query)
]
}
return await this.teamsService.getTeamFilters(builtQuery);
Expand All @@ -66,7 +69,8 @@ export class TeamsController {
builtQuery.where ? builtQuery.where : {},
this.teamsService.buildFocusAreaFilters(focusAreas),
this.teamsService.buildRecentTeamsFilter(request.query),
this.teamsService.buildParticipationTypeFilter(request.query)
this.teamsService.buildParticipationTypeFilter(request.query),
this.teamsService.buildAskTagFilter(request.query)
],
};
// Check for the office hours blank when OH not null is passed
Expand Down Expand Up @@ -109,4 +113,11 @@ export class TeamsController {
return await this.teamsService.updateTeamFromParticipantsRequest(teamUid, body, req.userEmail);
}

@Api(server.route.patchTeam)
@UseGuards(UserTokenValidation)
async addAsk(@Param('uid') teamUid, @Body() body, @Req() req) {
await this.teamsService.validateRequestor(req.userEmail, teamUid);
const res = await this.teamsService.addEditTeamAsk(teamUid,body.teamName,req.userEmail,body.ask);
return res;
}
}
6 changes: 5 additions & 1 deletion apps/web-api/src/teams/teams.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@ import { ParticipantsRequestModule } from '../participants-request/participants-
import { MembersModule } from '../members/members.module';

@Module({
imports: [forwardRef(() => ParticipantsRequestModule), forwardRef(() => MembersModule), SharedModule],
imports: [
forwardRef(() => ParticipantsRequestModule),
forwardRef(() => MembersModule),
SharedModule,
],
controllers: [TeamsController],
providers: [TeamsService],
exports: [TeamsService]
Expand Down
Loading
Loading