File

src/project/project.service.ts

Index

Methods

Constructor

constructor(prisma: PrismaService, requestService: RequestService, policyService: PolicyService, projectSettings: SettingsService)
Parameters :
Name Type Optional
prisma PrismaService No
requestService RequestService No
policyService PolicyService No
projectSettings SettingsService No

Methods

Async create
create(createProjectDto: CreateProjectDto)
Parameters :
Name Type Optional
createProjectDto CreateProjectDto No
Returns : Promise<Project>
Async fetchProjectServiceUser
fetchProjectServiceUser(project: Project)

Gets user details of the project's service user

Parameters :
Name Type Optional Description
project Project No

project for which the service user needs to be fetched

Returns : unknown
Async findAll
findAll(metrics)
Parameters :
Name Optional Default value
metrics No false
Returns : Promise<Project[]>
Async findOne
findOne(id: number)
Parameters :
Name Type Optional
id number No
Async findOrThrow
findOrThrow(id: number)

Fetches project - Throws an error if project doesn't exist

Parameters :
Name Type Optional Description
id number No

project ID

Returns : Promise<Project>
Async getProjectApprovers
getProjectApprovers(projectID: number)

this function returns list for approvers for a project

Parameters :
Name Type Optional
projectID number No
Returns : Promise<string[]>

list of userids eg:- ["test@me.com", "turo@me.com", "pallavi@me.com"]

Async getProjectCredentials
getProjectCredentials(id: number)

Gets access token for project's service user

Parameters :
Name Type Optional Description
id number No

project ID

Returns : unknown
Async getUserPendingAccessProjectIdList
getUserPendingAccessProjectIdList(userId)

function to get map for pending project access request

Parameters :
Name Optional
userId No
Returns : unknown

pendingAccessProjectIdMap

Async remove
remove(id: number)
Parameters :
Name Type Optional
id number No
Returns : Promise<Project>
Async requestProjectCreate
requestProjectCreate(createProjectDto: CreateProjectDto, requestedBy: string)
Parameters :
Name Type Optional
createProjectDto CreateProjectDto No
requestedBy string No
Returns : unknown
Async update
update(id: number, updateProjectDto: UpdateProjectDto)
Parameters :
Name Type Optional
id number No
updateProjectDto UpdateProjectDto No
Returns : Promise<Project>
Async updateProjectStage
updateProjectStage(projectId, stage)
Parameters :
Name Optional
projectId No
stage No
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;
  }
}

results matching ""

    No results matching ""