Skip to content

Commit f89ffb1

Browse files
authored
Merge pull request #3613 from Northeastern-Electric-Racing/speeeeeeeeeeed
projects
2 parents 09a4429 + ca0c84a commit f89ffb1

38 files changed

Lines changed: 495 additions & 190 deletions

src/backend/src/controllers/projects.controllers.ts

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,31 @@
1-
import { Manufacturer, MaterialType, Project, ProjectPreview, validateWBS, WbsNumber, wbsPipe } from 'shared';
1+
import {
2+
Manufacturer,
3+
MaterialType,
4+
Project,
5+
ProjectOverview,
6+
ProjectGantt,
7+
ProjectPreview,
8+
validateWBS,
9+
WbsNumber,
10+
wbsPipe
11+
} from 'shared';
212
import { NextFunction, Request, Response } from 'express';
313
import ProjectsService from '../services/projects.services';
414
import BillOfMaterialsService from '../services/boms.services';
515

616
export default class ProjectsController {
17+
static async getAllProjectsGantt(req: Request, res: Response, next: NextFunction) {
18+
try {
19+
const projects: ProjectGantt[] = await ProjectsService.getAllProjectsGantt(req.organization);
20+
res.status(200).json(projects);
21+
} catch (error: unknown) {
22+
next(error);
23+
}
24+
}
25+
726
static async getAllProjects(req: Request, res: Response, next: NextFunction) {
827
try {
9-
const includeDeleted = req.params.deleted === 'true';
10-
const projects: ProjectPreview[] = await ProjectsService.getAllProjects(req.organization, includeDeleted);
28+
const projects: ProjectPreview[] = await ProjectsService.getAllProjects(req.organization);
1129
res.status(200).json(projects);
1230
} catch (error: unknown) {
1331
next(error);
@@ -16,7 +34,7 @@ export default class ProjectsController {
1634

1735
static async getUsersTeamsProjects(req: Request, res: Response, next: NextFunction) {
1836
try {
19-
const projects: ProjectPreview[] = await ProjectsService.getUsersTeamsProjects(req.currentUser, req.organization);
37+
const projects: ProjectOverview[] = await ProjectsService.getUsersTeamsProjects(req.currentUser, req.organization);
2038
res.status(200).json(projects);
2139
} catch (error: unknown) {
2240
next(error);
@@ -25,7 +43,7 @@ export default class ProjectsController {
2543

2644
static async getUsersLeadingProjects(req: Request, res: Response, next: NextFunction) {
2745
try {
28-
const projects: ProjectPreview[] = await ProjectsService.getUsersLeadingProjects(req.currentUser, req.organization);
46+
const projects: ProjectOverview[] = await ProjectsService.getUsersLeadingProjects(req.currentUser, req.organization);
2947
res.status(200).json(projects);
3048
} catch (error: unknown) {
3149
next(error);

src/backend/src/prisma-query-args/projects.query-args.ts

Lines changed: 75 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,15 @@ import { getUserQueryArgs } from './user.query-args';
44
import { getDescriptionBulletQueryArgs } from './description-bullets.query-args';
55
import { getTeamPreviewQueryArgs } from './teams.query-args';
66
import { getTaskQueryArgs } from './tasks.query-args';
7-
import { getWorkPackageQueryArgs } from './work-packages.query-args';
7+
import { getWorkPackagePreviewQueryArgs, getWorkPackageQueryArgs } from './work-packages.query-args';
88

99
export type ProjectQueryArgs = ReturnType<typeof getProjectQueryArgs>;
1010

11-
export type ProjectManyQueryArgs = ReturnType<typeof getProjectManyQueryArgs>;
11+
export type ProjectGanttQueryArgs = ReturnType<typeof getProjectGanttQueryArgs>;
12+
13+
export type ProjectPreviewQueryArgs = ReturnType<typeof getProjectPreviewQueryArgs>;
14+
15+
export type ProjectOverviewQueryArgs = ReturnType<typeof getProjectOverviewQueryArgs>;
1216

1317
export const getProjectQueryArgs = (organizationId: string) =>
1418
Prisma.validator<Prisma.ProjectDefaultArgs>()({
@@ -40,7 +44,7 @@ export const getProjectQueryArgs = (organizationId: string) =>
4044
}
4145
});
4246

43-
export const getProjectManyQueryArgs = (organizationId: string) =>
47+
export const getProjectGanttQueryArgs = (organizationId: string) =>
4448
Prisma.validator<Prisma.ProjectDefaultArgs>()({
4549
include: {
4650
wbsElement: {
@@ -52,16 +56,15 @@ export const getProjectManyQueryArgs = (organizationId: string) =>
5256
dateDeleted: null
5357
},
5458
...getTaskQueryArgs(organizationId)
55-
},
56-
links: {
57-
where: {
58-
dateDeleted: null
59-
},
60-
...getLinkQueryArgs(organizationId)
6159
}
6260
}
6361
},
64-
teams: getTeamPreviewQueryArgs(organizationId),
62+
teams: {
63+
select: {
64+
teamId: true,
65+
teamName: true
66+
}
67+
},
6568
workPackages: {
6669
where: {
6770
wbsElement: {
@@ -73,3 +76,65 @@ export const getProjectManyQueryArgs = (organizationId: string) =>
7376
favoritedBy: getUserQueryArgs(organizationId)
7477
}
7578
});
79+
80+
export const getProjectPreviewQueryArgs = (organizationId: string) =>
81+
Prisma.validator<Prisma.ProjectDefaultArgs>()({
82+
select: {
83+
wbsElement: {
84+
select: {
85+
wbsElementId: true,
86+
carNumber: true,
87+
projectNumber: true,
88+
workPackageNumber: true,
89+
dateCreated: true,
90+
dateDeleted: true,
91+
name: true,
92+
lead: getUserQueryArgs(organizationId),
93+
manager: getUserQueryArgs(organizationId),
94+
status: true
95+
}
96+
},
97+
workPackages: getWorkPackagePreviewQueryArgs(organizationId),
98+
projectId: true,
99+
budget: true,
100+
abbreviation: true,
101+
teams: {
102+
select: {
103+
teamId: true,
104+
teamName: true
105+
}
106+
}
107+
}
108+
});
109+
110+
export const getProjectOverviewQueryArgs = (organizationId: string) =>
111+
Prisma.validator<Prisma.ProjectDefaultArgs>()({
112+
select: {
113+
wbsElement: {
114+
select: {
115+
wbsElementId: true,
116+
carNumber: true,
117+
projectNumber: true,
118+
workPackageNumber: true,
119+
dateCreated: true,
120+
dateDeleted: true,
121+
name: true,
122+
lead: getUserQueryArgs(organizationId),
123+
manager: getUserQueryArgs(organizationId),
124+
status: true,
125+
links: getLinkQueryArgs(organizationId),
126+
tasks: getTaskQueryArgs(organizationId)
127+
}
128+
},
129+
workPackages: getWorkPackagePreviewQueryArgs(organizationId),
130+
projectId: true,
131+
budget: true,
132+
abbreviation: true,
133+
teams: {
134+
select: {
135+
teamId: true,
136+
teamName: true
137+
}
138+
}
139+
}
140+
});

src/backend/src/prisma-query-args/teams.query-args.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { Prisma } from '@prisma/client';
22
import { getUserQueryArgs } from './user.query-args';
3-
import { getProjectManyQueryArgs } from './projects.query-args';
3+
import { getProjectGanttQueryArgs } from './projects.query-args';
44

55
export type TeamQueryArgs = ReturnType<typeof getTeamQueryArgs>;
66

@@ -20,7 +20,7 @@ export const getTeamQueryArgs = (organizationId: string) =>
2020
dateDeleted: null
2121
}
2222
},
23-
...getProjectManyQueryArgs(organizationId)
23+
...getProjectGanttQueryArgs(organizationId)
2424
}
2525
}
2626
});

src/backend/src/prisma-query-args/work-packages.query-args.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { getDescriptionBulletQueryArgs } from './description-bullets.query-args'
44
import { getDesignReviewPreviewQueryArgs } from './design-reviews.query-args';
55

66
export type WorkPackageQueryArgs = ReturnType<typeof getWorkPackageQueryArgs>;
7+
export type WorkPackagePreviewQueryArgs = ReturnType<typeof getWorkPackagePreviewQueryArgs>;
78

89
export const getWorkPackageQueryArgs = (organizationId: string) =>
910
Prisma.validator<Prisma.Work_PackageDefaultArgs>()({
@@ -35,3 +36,27 @@ export const getWorkPackageQueryArgs = (organizationId: string) =>
3536
blockedBy: { where: { dateDeleted: null } }
3637
}
3738
});
39+
40+
export const getWorkPackagePreviewQueryArgs = (organizationId: string) =>
41+
Prisma.validator<Prisma.Work_PackageDefaultArgs>()({
42+
select: {
43+
wbsElement: {
44+
select: {
45+
wbsElementId: true,
46+
carNumber: true,
47+
projectNumber: true,
48+
workPackageNumber: true,
49+
dateCreated: true,
50+
dateDeleted: true,
51+
name: true,
52+
lead: getUserQueryArgs(organizationId),
53+
manager: getUserQueryArgs(organizationId),
54+
status: true
55+
}
56+
},
57+
startDate: true,
58+
duration: true,
59+
workPackageId: true,
60+
stage: true
61+
}
62+
});

src/backend/src/prisma/prisma.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { PrismaClient } from '@prisma/client';
22

3-
const SLOW_QUERY_THRESHOLD = 15000;
3+
const SLOW_QUERY_THRESHOLD = 300;
44

55
interface QueryLoggerExtension {
66
name: string;

src/backend/src/routes/projects.routes.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@ import ProjectsController from '../controllers/projects.controllers';
1111

1212
const projectRouter = express.Router();
1313

14-
projectRouter.get('/all/:deleted', ProjectsController.getAllProjects);
14+
projectRouter.get('/all-gantt', ProjectsController.getAllProjectsGantt);
15+
projectRouter.get('/all-previews', ProjectsController.getAllProjects);
1516
projectRouter.get('/users-teams', ProjectsController.getUsersTeamsProjects);
1617
projectRouter.get('/leading', ProjectsController.getUsersLeadingProjects);
1718
projectRouter.get('/teams-projects/:teamId', ProjectsController.getTeamsProjects);

src/backend/src/services/organizations.services.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import { linkTransformer } from '../transformers/links.transformer';
1414
import { getLinkQueryArgs } from '../prisma-query-args/links.query-args';
1515
import { uploadFile } from '../utils/google-integration.utils';
1616
import { getProjects } from '../utils/projects.utils';
17-
import { getProjectManyQueryArgs } from '../prisma-query-args/projects.query-args';
17+
import { getProjectPreviewQueryArgs } from '../prisma-query-args/projects.query-args';
1818
import { projectPreviewTransformer } from '../transformers/projects.transformer';
1919

2020
export default class OrganizationsService {
@@ -385,7 +385,7 @@ export default class OrganizationsService {
385385
static async getOrganizationFeaturedProjects(organizationId: string): Promise<ProjectPreview[]> {
386386
const organization = await prisma.organization.findUnique({
387387
where: { organizationId },
388-
include: { featuredProjects: getProjectManyQueryArgs(organizationId) }
388+
include: { featuredProjects: getProjectPreviewQueryArgs(organizationId) }
389389
});
390390

391391
if (!organization) {

src/backend/src/services/projects.services.ts

Lines changed: 59 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,18 @@ import {
77
LinkCreateArgs,
88
LinkType,
99
Project,
10+
ProjectOverview,
11+
ProjectGantt,
1012
ProjectPreview,
1113
WbsNumber,
1214
wbsPipe
1315
} from 'shared';
1416
import prisma from '../prisma/prisma';
15-
import projectTransformer, { projectPreviewTransformer } from '../transformers/projects.transformer';
17+
import projectTransformer, {
18+
projectOverviewTransformer,
19+
projectGanttTransformer,
20+
projectPreviewTransformer
21+
} from '../transformers/projects.transformer';
1622
import { validateChangeRequestAccepted } from '../utils/change-requests.utils';
1723
import {
1824
AccessDeniedAdminOnlyException,
@@ -28,33 +34,52 @@ import { wbsNumOf } from '../utils/utils';
2834
import WorkPackagesService from './work-packages.services';
2935
import { linkTypeTransformer } from '../transformers/links.transformer';
3036
import { userHasPermission } from '../utils/users.utils';
31-
import { getProjectManyQueryArgs, getProjectQueryArgs } from '../prisma-query-args/projects.query-args';
37+
import {
38+
getProjectGanttQueryArgs,
39+
getProjectOverviewQueryArgs,
40+
getProjectPreviewQueryArgs,
41+
getProjectQueryArgs
42+
} from '../prisma-query-args/projects.query-args';
3243
import { getLinkQueryArgs } from '../prisma-query-args/links.query-args';
3344
import { getDescriptionBulletQueryArgs } from '../prisma-query-args/description-bullets.query-args';
3445
import { getLinkTypeQueryArgs } from '../prisma-query-args/link-types.query-args';
3546

3647
export default class ProjectsService {
3748
/**
38-
* Get all the non deleted projects in the database for the given organization.
39-
* @param organizationId the id of the organization the user is currently in
40-
* @param includeDeleted whether or not to include deleted projects
41-
* @returns all the projects
49+
* Get all the non deleted projects in the database for the given organization
50+
* @param organization the organization the user is currently in
51+
* @returns all the projects with query args for use in the gantt chart
4252
*/
43-
static async getAllProjects(organization: Organization, includeDeleted: boolean): Promise<ProjectPreview[]> {
44-
const projects = includeDeleted
45-
? await prisma.project.findMany({
46-
where: { wbsElement: { organizationId: organization.organizationId } },
47-
...getProjectManyQueryArgs(organization.organizationId)
48-
})
49-
: await prisma.project.findMany({
50-
where: { wbsElement: { dateDeleted: null, organizationId: organization.organizationId } },
51-
...getProjectManyQueryArgs(organization.organizationId)
52-
});
53+
static async getAllProjectsGantt(organization: Organization): Promise<ProjectGantt[]> {
54+
const projects = await prisma.project.findMany({
55+
where: { wbsElement: { dateDeleted: null, organizationId: organization.organizationId } },
56+
...getProjectGanttQueryArgs(organization.organizationId)
57+
});
58+
59+
return projects.map(projectGanttTransformer);
60+
}
61+
62+
/**
63+
* Get all projects for given organization
64+
* @param organization the organization the user is in
65+
* @returns all the projects with preview query args
66+
*/
67+
static async getAllProjects(organization: Organization): Promise<ProjectPreview[]> {
68+
const projects = await prisma.project.findMany({
69+
where: { wbsElement: { dateDeleted: null, organizationId: organization.organizationId } },
70+
...getProjectPreviewQueryArgs(organization.organizationId)
71+
});
5372

5473
return projects.map(projectPreviewTransformer);
5574
}
5675

57-
static async getUsersLeadingProjects(user: User, organization: Organization): Promise<ProjectPreview[]> {
76+
/**
77+
* Get all projects that the user is the lead or manager of
78+
* @param user the user making the request
79+
* @param organization the oranization the user is in
80+
* @returns the projects the user is a lead or manager of with preview query args
81+
*/
82+
static async getUsersLeadingProjects(user: User, organization: Organization): Promise<ProjectOverview[]> {
5883
const projects = await prisma.project.findMany({
5984
where: {
6085
wbsElement: {
@@ -63,13 +88,19 @@ export default class ProjectsService {
6388
OR: [{ leadId: user.userId }, { managerId: user.userId }]
6489
}
6590
},
66-
...getProjectManyQueryArgs(organization.organizationId)
91+
...getProjectOverviewQueryArgs(organization.organizationId)
6792
});
6893

69-
return projects.map(projectPreviewTransformer);
94+
return projects.map(projectOverviewTransformer);
7095
}
7196

72-
static async getUsersTeamsProjects(user: User, organization: Organization): Promise<ProjectPreview[]> {
97+
/**
98+
* Get all projects related to teams the user is on
99+
* @param user the user making the request
100+
* @param organization the organization the user is in
101+
* @returns all projects associated with teams the user is on with overview card query args
102+
*/
103+
static async getUsersTeamsProjects(user: User, organization: Organization): Promise<ProjectOverview[]> {
73104
const projects = await prisma.project.findMany({
74105
where: {
75106
wbsElement: {
@@ -100,12 +131,18 @@ export default class ProjectsService {
100131
}
101132
}
102133
},
103-
...getProjectManyQueryArgs(organization.organizationId)
134+
...getProjectOverviewQueryArgs(organization.organizationId)
104135
});
105136

106-
return projects.map(projectPreviewTransformer);
137+
return projects.map(projectOverviewTransformer);
107138
}
108139

140+
/**
141+
* Get the projects for a given team
142+
* @param organization
143+
* @param teamId
144+
* @returns all the projects for the given team with full project query args
145+
*/
109146
static async getTeamsProjects(organization: Organization, teamId: string): Promise<Project[]> {
110147
const projects = await prisma.project.findMany({
111148
where: {

0 commit comments

Comments
 (0)