From 62c969d1ff27198918b0bab971428ad2088c7b03 Mon Sep 17 00:00:00 2001 From: prathamesh0 <42446521+prathamesh0@users.noreply.github.com> Date: Thu, 18 Jan 2024 14:06:49 +0530 Subject: [PATCH] Fetch additional projects data and implement resolver for deployments query (#22) * Add resolver function for fetching all deployments for a project * Fetch project members while fetching organization data * Map db project member and deployment entity to graphql type * Fetch environment variables data while fetching organizations * Add domain field in deployment --------- Co-authored-by: neeraj --- packages/backend/src/database.ts | 64 +++++++++++++++++-- .../backend/src/entity/EnvironmentVariable.ts | 8 ++- packages/backend/src/entity/ProjectMember.ts | 11 ++-- .../backend/src/entity/UserOrganization.ts | 2 +- packages/backend/src/resolvers.ts | 36 +++++++++-- packages/backend/src/utils.ts | 44 ++++++++++++- 6 files changed, 145 insertions(+), 20 deletions(-) diff --git a/packages/backend/src/database.ts b/packages/backend/src/database.ts index dce51f7b..17bd29c8 100644 --- a/packages/backend/src/database.ts +++ b/packages/backend/src/database.ts @@ -7,6 +7,9 @@ import { User } from './entity/User'; import { Organization } from './entity/Organization'; import { UserOrganization } from './entity/UserOrganization'; import { Project } from './entity/Project'; +import { Deployment } from './entity/Deployment'; +import { ProjectMember } from './entity/ProjectMember'; +import { EnvironmentVariable } from './entity/EnvironmentVariable'; const log = debug('snowball:database'); @@ -37,16 +40,16 @@ export class Database { return user; } - async getOrganizationsbyUserId (userId: number) : Promise { + async getOrganizationsByUserId (userId: number) : Promise { const userOrganizationRepository = this.dataSource.getRepository(UserOrganization); const userOrgs = await userOrganizationRepository.find({ relations: { - user: true, + member: true, organization: true }, where: { - user: { + member: { id: userId } } @@ -56,7 +59,7 @@ export class Database { return organizations; } - async getProjectsbyOrganizationId (organizationId: number): Promise { + async getProjectsByOrganizationId (organizationId: number): Promise { const projectRepository = this.dataSource.getRepository(Project); const projects = await projectRepository.find({ @@ -73,4 +76,57 @@ export class Database { return projects; } + + async getDeploymentsByProjectId (projectId: string): Promise { + const deploymentRepository = this.dataSource.getRepository(Deployment); + + const deployments = await deploymentRepository.find({ + relations: { + project: true, + domain: true + }, + where: { + project: { + id: projectId + } + } + }); + + return deployments; + } + + async getProjectMembers (projectId: string): Promise { + const projectMemberRepository = this.dataSource.getRepository(ProjectMember); + + const projectMembers = await projectMemberRepository.find({ + relations: { + project: true, + member: true + }, + where: { + project: { + id: projectId + } + } + }); + + return projectMembers; + } + + async getEnvironmentVariablesByProjectId (projectId: string): Promise { + const environmentVariableRepository = this.dataSource.getRepository(EnvironmentVariable); + + const environmentVariables = await environmentVariableRepository.find({ + relations: { + project: true + }, + where: { + project: { + id: projectId + } + } + }); + + return environmentVariables; + } } diff --git a/packages/backend/src/entity/EnvironmentVariable.ts b/packages/backend/src/entity/EnvironmentVariable.ts index b2ef66ff..d148bb68 100644 --- a/packages/backend/src/entity/EnvironmentVariable.ts +++ b/packages/backend/src/entity/EnvironmentVariable.ts @@ -10,6 +10,12 @@ import { import { Project } from './Project'; +enum Environment { + Production = 'Production', + Preview = 'Preview', + Development = 'Development', +} + @Entity() export class EnvironmentVariable { @PrimaryGeneratedColumn() @@ -22,7 +28,7 @@ export class EnvironmentVariable { @Column({ type: 'simple-array' }) - environments!: string[]; + environments!: Environment[]; @Column('varchar') key!: string; diff --git a/packages/backend/src/entity/ProjectMember.ts b/packages/backend/src/entity/ProjectMember.ts index 2c208c7b..d1e4cc80 100644 --- a/packages/backend/src/entity/ProjectMember.ts +++ b/packages/backend/src/entity/ProjectMember.ts @@ -12,9 +12,8 @@ import { Project } from './Project'; import { User } from './User'; enum Permissions { - Owner = 'Owner', - Maintainer = 'Maintainer', - Reader = 'Reader', + View = 'View', + Edit = 'Edit' } @Entity() @@ -24,16 +23,16 @@ export class ProjectMember { @ManyToOne(() => User, { onDelete: 'CASCADE' }) @JoinColumn({ name: 'userId' }) - user!: User; + member!: User; @ManyToOne(() => Project, { onDelete: 'CASCADE' }) @JoinColumn({ name: 'projectId' }) project!: Project; @Column({ - enum: Permissions + type: 'simple-array' }) - role!: Permissions; + permissions!: Permissions[]; @CreateDateColumn() createdAt!: Date; diff --git a/packages/backend/src/entity/UserOrganization.ts b/packages/backend/src/entity/UserOrganization.ts index 5d11c4c8..3e7c7dc8 100644 --- a/packages/backend/src/entity/UserOrganization.ts +++ b/packages/backend/src/entity/UserOrganization.ts @@ -24,7 +24,7 @@ export class UserOrganization { @ManyToOne(() => User, { onDelete: 'CASCADE' }) @JoinColumn({ name: 'userId' }) - user!: User; + member!: User; @ManyToOne(() => Organization, { onDelete: 'CASCADE' }) @JoinColumn({ name: 'organizationId' }) diff --git a/packages/backend/src/resolvers.ts b/packages/backend/src/resolvers.ts index c7511a6e..f687b786 100644 --- a/packages/backend/src/resolvers.ts +++ b/packages/backend/src/resolvers.ts @@ -1,5 +1,5 @@ import { Database } from './database'; -import { projectToGqlType } from './utils'; +import { deploymentToGqlType, projectMemberToGqlType, projectToGqlType, environmentVariableToGqlType } from './utils'; export const createResolvers = async (db: Database): Promise => { return { @@ -10,25 +10,47 @@ export const createResolvers = async (db: Database): Promise => { }, organizations: async (_:any, __: any, context: any) => { - const organizations = await db.getOrganizationsbyUserId(context.userId); + const organizations = await db.getOrganizationsByUserId(context.userId); const orgsWithProjectsPromises = organizations.map(async (org) => { - const dbProjects = await db.getProjectsbyOrganizationId(org.id); + const dbProjects = await db.getProjectsByOrganizationId(org.id); - const projects = dbProjects.map(dbProject => { - return projectToGqlType(dbProject); + const projectsWithPromises = dbProjects.map(async (dbProject) => { + const dbProjectMembers = await db.getProjectMembers(dbProject.id); + const dbEnvironmentVariables = await db.getEnvironmentVariablesByProjectId(dbProject.id); + + const projectMembers = dbProjectMembers.map(dbProjectMember => { + return projectMemberToGqlType(dbProjectMember); + }); + + const environmentVariables = dbEnvironmentVariables.map(dbEnvironmentVariable => { + return environmentVariableToGqlType(dbEnvironmentVariable); + }); + + return projectToGqlType(dbProject, projectMembers, environmentVariables); }); + const projects = await Promise.all(projectsWithPromises); + return { ...org, projects }; }); + // TODO: Add organizationMembers field when / if required const orgsWithProjects = await Promise.all(orgsWithProjectsPromises); - - // TODO: Populate members field when / if required return orgsWithProjects; + }, + + deployments: async (_: any, { projectId }: { projectId: string }) => { + const dbDeployments = await db.getDeploymentsByProjectId(projectId); + + const deployments = dbDeployments.map(dbDeployment => { + return deploymentToGqlType(dbDeployment); + }); + + return deployments; } } }; diff --git a/packages/backend/src/utils.ts b/packages/backend/src/utils.ts index 6e276d73..c33f585d 100644 --- a/packages/backend/src/utils.ts +++ b/packages/backend/src/utils.ts @@ -4,6 +4,9 @@ import toml from 'toml'; import debug from 'debug'; import { Project } from './entity/Project'; +import { ProjectMember } from './entity/ProjectMember'; +import { Deployment } from './entity/Deployment'; +import { EnvironmentVariable } from './entity/EnvironmentVariable'; const log = debug('snowball:utils'); @@ -22,7 +25,7 @@ export const getConfig = async ( return config; }; -export const projectToGqlType = (dbProject: Project): any => { +export const projectToGqlType = (dbProject: Project, projectMembers: ProjectMember[], environmentVariables: EnvironmentVariable[]): any => { return { id: dbProject.id, owner: dbProject.owner, @@ -33,7 +36,46 @@ export const projectToGqlType = (dbProject: Project): any => { template: dbProject.template, framework: dbProject.framework, webhooks: dbProject.webhooks, + members: projectMembers, + environmentVariables: environmentVariables, createdAt: dbProject.createdAt, updatedAt: dbProject.updatedAt }; }; + +// TODO: Add domain field to deployment +export const deploymentToGqlType = (dbDeployment: Deployment): any => { + return { + id: dbDeployment.id, + domain: dbDeployment.domain, + branch: dbDeployment.branch, + commitHash: dbDeployment.commitHash, + title: dbDeployment.title, + environment: dbDeployment.environment, + isCurrent: dbDeployment.isCurrent, + status: dbDeployment.status, + createdAt: dbDeployment.createdAt, + updatedAt: dbDeployment.updatedAt + }; +}; + +export const projectMemberToGqlType = (dbProjectMember: ProjectMember): any => { + return { + id: dbProjectMember.id, + member: dbProjectMember.member, + permissions: dbProjectMember.permissions, + createdAt: dbProjectMember.createdAt, + updatedAt: dbProjectMember.updatedAt + }; +}; + +export const environmentVariableToGqlType = (dbEnvironmentVariable: EnvironmentVariable): any => { + return { + id: dbEnvironmentVariable.id, + environments: dbEnvironmentVariable.environments, + key: dbEnvironmentVariable.key, + value: dbEnvironmentVariable.value, + createdAt: dbEnvironmentVariable.createdAt, + updatedAt: dbEnvironmentVariable.updatedAt + }; +};