src/project/project.service.ts
Methods |
|
constructor(prisma: PrismaService, requestService: RequestService, policyService: PolicyService, projectSettings: SettingsService)
|
|||||||||||||||
|
Defined in src/project/project.service.ts:15
|
|||||||||||||||
|
Parameters :
|
| Async create | ||||||
create(createProjectDto: CreateProjectDto)
|
||||||
|
Defined in src/project/project.service.ts:72
|
||||||
|
Parameters :
Returns :
Promise<Project>
|
| Async fetchProjectServiceUser | ||||||||
fetchProjectServiceUser(project: Project)
|
||||||||
|
Defined in src/project/project.service.ts:112
|
||||||||
|
Gets user details of the project's service user
Parameters :
Returns :
unknown
|
| Async findAll | ||||||
findAll(metrics)
|
||||||
|
Defined in src/project/project.service.ts:143
|
||||||
|
Parameters :
Returns :
Promise<Project[]>
|
| Async findOne | ||||||
findOne(id: number)
|
||||||
|
Defined in src/project/project.service.ts:173
|
||||||
|
Parameters :
Returns :
Promise<Project | null>
|
| Async findOrThrow | ||||||||
findOrThrow(id: number)
|
||||||||
|
Defined in src/project/project.service.ts:27
|
||||||||
|
Fetches project - Throws an error if project doesn't exist
Parameters :
Returns :
Promise<Project>
|
| Async getProjectApprovers | ||||||
getProjectApprovers(projectID: number)
|
||||||
|
Defined in src/project/project.service.ts:237
|
||||||
|
this function returns list for approvers for a project
Parameters :
Returns :
Promise<string[]>
list of userids eg:- ["test@me.com", "turo@me.com", "pallavi@me.com"] |
| Async getProjectCredentials | ||||||||
getProjectCredentials(id: number)
|
||||||||
|
Defined in src/project/project.service.ts:41
|
||||||||
|
Gets access token for project's service user
Parameters :
Returns :
unknown
|
| Async getUserPendingAccessProjectIdList | ||||
getUserPendingAccessProjectIdList(userId)
|
||||
|
Defined in src/project/project.service.ts:272
|
||||
|
function to get map for pending project access request
Parameters :
Returns :
unknown
pendingAccessProjectIdMap |
| Async remove | ||||||
remove(id: number)
|
||||||
|
Defined in src/project/project.service.ts:214
|
||||||
|
Parameters :
Returns :
Promise<Project>
|
| Async requestProjectCreate | |||||||||
requestProjectCreate(createProjectDto: CreateProjectDto, requestedBy: string)
|
|||||||||
|
Defined in src/project/project.service.ts:51
|
|||||||||
|
Parameters :
Returns :
unknown
|
| Async update | |||||||||
update(id: number, updateProjectDto: UpdateProjectDto)
|
|||||||||
|
Defined in src/project/project.service.ts:184
|
|||||||||
|
Parameters :
Returns :
Promise<Project>
|
| Async updateProjectStage | ||||||
updateProjectStage(projectId, stage)
|
||||||
|
Defined in src/project/project.service.ts:128
|
||||||
|
Parameters :
Returns :
Promise<Project>
|
import { Injectable, InternalServerErrorException } from "@nestjs/common";
import { PrismaService } from "../common/prisma/prisma.service";
import { CreateProjectDto } from "./dto/create-project.dto";
import { UpdateProjectDto } from "./dto/update-project.dto";
import { Project, ProjectStages } from "./entities/project.entity";
import { toKebabCase } from "../common/helper";
import { RequestService, RequestStatus, RequestType } from "../request";
import { PolicyService } from "../iam/policy/policy.service";
import { SettingsService } from "./settings/settings.service";
import { Roles } from "../iam";
import { CostOverviewStatus } from "../cost/types/cost-overview.interface";
import { MetricStatus } from "../metrics/entities/metrics.entity";
@Injectable()
export class ProjectService {
constructor(
private prisma: PrismaService,
private readonly requestService: RequestService = null,
private readonly policyService: PolicyService = null,
private readonly projectSettings: SettingsService = null,
) {}
/**
* Fetches project - Throws an error if project doesn't exist
* @param {number} id project ID
*/
async findOrThrow(id: number): Promise<Project> {
const project = await this.prisma.project.findUniqueOrThrow({
where: { id: id },
include: {
businessUnit: true,
},
});
return new Project({ ...project, businessUnit: project.businessUnit.name });
}
/**
* Gets access token for project's service user
* @param {number} id project ID
*/
async getProjectCredentials(id: number) {
const project = await this.findOrThrow(id);
// TODO: restrict number of tokens per service user
await this.fetchProjectServiceUser(project);
const projectAccessToken = await this.policyService.getCredentials(
project.getProjectServiceUsername(),
);
return projectAccessToken;
}
async requestProjectCreate(
createProjectDto: CreateProjectDto,
requestedBy: string,
) {
// check if project with same slug exist
const projectSlug = toKebabCase(createProjectDto.name);
const exist = await this.prisma.project.findUnique({
where: {
slug: projectSlug,
},
});
if (exist) {
throw new InternalServerErrorException("Project with same name exist");
}
// send for create project workflow
return await this.requestService.triggerRequestWorkflow(
RequestType.PROJECT,
[createProjectDto, requestedBy],
);
}
async create(createProjectDto: CreateProjectDto): Promise<Project> {
const createProjectEntity = new Project(createProjectDto);
createProjectEntity.stage = ProjectStages.APPROVAL;
createProjectEntity.slug = toKebabCase(createProjectDto.name);
const resolvedValue = await this.prisma.project.create({
data: {
name: createProjectEntity.name,
useCaseType: createProjectEntity.useCaseType,
description: createProjectEntity.description,
businessObjective: createProjectEntity.businessObjective,
keyResults: createProjectEntity.keyResults,
kpis: createProjectEntity.kpis,
estimatedRevenue: createProjectEntity.estimatedRevenue,
impactNotes: createProjectEntity.impactNotes,
budget: createProjectEntity.budget,
targetVariable: createProjectEntity.targetVariable,
stage: createProjectEntity.stage,
slug: createProjectEntity.slug,
businessUnit: {
connect: {
name: createProjectDto.businessUnit,
},
},
},
include: {
businessUnit: true,
},
});
const project: Project = new Project({
...resolvedValue,
businessUnit: resolvedValue.businessUnit.name,
});
this.fetchProjectServiceUser(project);
return project;
}
/**
* Gets user details of the project's service user
* @param {Project} project project for which the service user needs to be fetched
*/
async fetchProjectServiceUser(project: Project) {
const projectSUUsername = project.getProjectServiceUsername();
const projectSUEmail = `${projectSUUsername}@internal.turo.com`;
const user = await this.policyService.getOrCreateUser(
projectSUUsername,
projectSUEmail,
);
// adding service user to project with appropriate access
await this.projectSettings.setProjectServiceUser(
projectSUEmail,
project.id,
);
return { username: user["username"] };
}
async updateProjectStage(projectId, stage): Promise<Project> {
const project = await this.prisma.project.update({
where: {
id: projectId,
},
data: {
stage: stage,
},
include: {
businessUnit: true,
},
});
return new Project({ ...project, businessUnit: project.businessUnit.name });
}
async findAll(metrics = false): Promise<Project[]> {
const projects = await this.prisma.project.findMany({
where: {
stage: {
notIn: [
ProjectStages.DELETED,
ProjectStages.APPROVAL,
ProjectStages.REJECTED,
],
},
},
include: {
businessUnit: true,
...(metrics && {
metrics: { where: { status: MetricStatus.ACTIVE } },
}),
},
});
return await Promise.all(
projects.map(
async (project) =>
new Project({
...project,
businessUnit: project.businessUnit.name,
owner: await this.projectSettings.getProjectOwner(project.id),
}),
),
);
}
async findOne(id: number): Promise<Project | null> {
const project = await this.prisma.project.findUnique({
where: { id: id },
include: {
businessUnit: true,
},
});
return new Project({ ...project, businessUnit: project.businessUnit.name });
}
async update(
id: number,
updateProjectDto: UpdateProjectDto,
): Promise<Project> {
const project: Project = new Project(
await this.prisma.project.update({
where: {
id: id,
NOT: {
OR: [
{ stage: { equals: ProjectStages.DELETED } },
{ stage: { equals: ProjectStages.ARCHIVED } },
{ stage: { equals: ProjectStages.APPROVAL } },
{ stage: { equals: ProjectStages.REJECTED } },
],
},
},
data: {
...updateProjectDto,
businessUnit: {
connect: {
name: updateProjectDto.businessUnit,
},
},
},
}),
);
return project;
}
async remove(id: number): Promise<Project> {
const project: Project = new Project(
await this.prisma.project.update({
where: {
id: id,
NOT: { stage: { equals: ProjectStages.DELETED } },
},
data: { stage: ProjectStages.DELETED },
}),
);
await this.policyService.removeResourceEntry("project", id);
await this.prisma.costOverview.updateMany({
where: { projectId: id },
data: { status: CostOverviewStatus.DELETED },
});
return project;
}
/**
* this function returns list for approvers for a project
* @param projectID
* @returns list of userids eg:- ["test@me.com", "turo@me.com", "pallavi@me.com"]
*/
async getProjectApprovers(projectID: number): Promise<string[]> {
const businessUnit = await this.prisma.businessUnit.findFirst({
where: {
projects: {
some: {
id: {
equals: projectID,
},
},
},
users: {
some: {
role: {
name: {
equals: Roles.BU_ADMIN,
},
},
},
},
},
include: {
users: true,
},
});
return businessUnit.users.map((approver) => {
return approver.userId;
});
}
/**
* function to get map for pending
* project access request
* @param userId
* @returns pendingAccessProjectIdMap
*/
async getUserPendingAccessProjectIdList(userId) {
const pendingRequests = await this.requestService.requests({
where: {
requestedBy: userId,
requestStatus: RequestStatus.PENDING,
requestType: RequestType.PROJECT_ACCESS,
},
});
const pendingAccessProjectIdMap = {};
for (const request of pendingRequests) {
const details = await this.requestService.getRequestDetails(request.id);
pendingAccessProjectIdMap[details.requestFieldObject["projectId"]] = true;
}
return pendingAccessProjectIdMap;
}
}