Add checks for mutations and a mutation to add environment variables to project (#33)

* Add mutation to add environment variables by project id

* Add checks while removing project members

---------

Co-authored-by: neeraj <neeraj.rtly@gmail.com>
This commit is contained in:
prathamesh0 2024-01-23 15:01:33 +05:30 committed by Ashwin Phatak
parent 58e20c15db
commit 02f7ebb9bd
4 changed files with 90 additions and 7 deletions

View File

@ -1,6 +1,7 @@
import { DataSource } from 'typeorm'; import { DataSource } from 'typeorm';
import path from 'path'; import path from 'path';
import debug from 'debug'; import debug from 'debug';
import assert from 'assert';
import { DatabaseConfig } from './config'; import { DatabaseConfig } from './config';
import { User } from './entity/User'; import { User } from './entity/User';
@ -133,6 +134,7 @@ export class Database {
async removeProjectMemberByMemberId (memberId: string): Promise<boolean> { async removeProjectMemberByMemberId (memberId: string): Promise<boolean> {
// TODO: Check if user is authorized to delete members // TODO: Check if user is authorized to delete members
const projectMemberRepository = this.dataSource.getRepository(ProjectMember); const projectMemberRepository = this.dataSource.getRepository(ProjectMember);
const deleted = await projectMemberRepository.delete(memberId); const deleted = await projectMemberRepository.delete(memberId);
if (deleted.affected) { if (deleted.affected) {
@ -141,4 +143,51 @@ export class Database {
return false; return false;
} }
} }
async addEnvironmentVariablesByProjectId (projectId: string, environmentVariables: any[]): Promise<boolean> {
const environmentVariableRepository = this.dataSource.getRepository(EnvironmentVariable);
const projectRepository = this.dataSource.getRepository(Project);
const project = await projectRepository.findOneBy({
id: projectId
});
assert(project);
const environmentVariablesPromises = environmentVariables.map(async environmentVariable => {
const envVar = new EnvironmentVariable();
envVar.key = environmentVariable.key;
envVar.value = environmentVariable.value;
envVar.environments = environmentVariable.environments;
envVar.project = project;
return environmentVariableRepository.save(envVar);
});
const savedEnvironmentVariables = await Promise.all(environmentVariablesPromises);
return savedEnvironmentVariables.length > 0;
}
async getProjectMemberByMemberId (memberId: string): Promise<ProjectMember> {
const projectMemberRepository = this.dataSource.getRepository(ProjectMember);
const projectMemberWithProject = await projectMemberRepository.find({
relations: {
project: {
owner: true
},
member: true
},
where: {
id: Number(memberId)
}
}
);
if (projectMemberWithProject.length === 0) {
throw new Error('Member does not exist');
}
return projectMemberWithProject[0];
}
} }

View File

@ -1,7 +1,8 @@
import debug from 'debug'; import debug from 'debug';
import assert from 'assert';
import { Database } from './database'; import { Database } from './database';
import { deploymentToGqlType, projectMemberToGqlType, projectToGqlType, environmentVariableToGqlType } from './utils'; import { deploymentToGqlType, projectMemberToGqlType, projectToGqlType, environmentVariableToGqlType, isUserOwner } from './utils';
const log = debug('snowball:database'); const log = debug('snowball:database');
@ -19,7 +20,7 @@ export const createResolvers = async (db: Database): Promise<any> => {
const orgsWithProjectsPromises = organizations.map(async (org) => { const orgsWithProjectsPromises = organizations.map(async (org) => {
const dbProjects = await db.getProjectsByOrganizationId(org.id); const dbProjects = await db.getProjectsByOrganizationId(org.id);
const projectsWithPromises = dbProjects.map(async (dbProject) => { const projectsPromises = dbProjects.map(async (dbProject) => {
const dbProjectMembers = await db.getProjectMembersByProjectId(dbProject.id); const dbProjectMembers = await db.getProjectMembersByProjectId(dbProject.id);
const dbEnvironmentVariables = await db.getEnvironmentVariablesByProjectId(dbProject.id); const dbEnvironmentVariables = await db.getEnvironmentVariablesByProjectId(dbProject.id);
@ -34,7 +35,7 @@ export const createResolvers = async (db: Database): Promise<any> => {
return projectToGqlType(dbProject, projectMembers, environmentVariables); return projectToGqlType(dbProject, projectMembers, environmentVariables);
}); });
const projects = await Promise.all(projectsWithPromises); const projects = await Promise.all(projectsPromises);
return { return {
...org, ...org,
@ -69,11 +70,33 @@ export const createResolvers = async (db: Database): Promise<any> => {
}, },
Mutation: { Mutation: {
removeMember: async (_: any, { memberId }:{ memberId: string }) => { removeMember: async (_: any, { memberId }: { memberId: string }, context: any) => {
try { try {
return await db.removeProjectMemberByMemberId(memberId); const member = await db.getProjectMemberByMemberId(memberId);
} catch (error) {
log(error); if (member.member.id === context.userId) {
throw new Error('Invalid operation: cannot remove self');
}
const memberProject = member.project;
assert(memberProject);
if (isUserOwner(String(context.userId), String(memberProject.owner.id))) {
return db.removeProjectMemberByMemberId(memberId);
} else {
throw new Error('Invalid operation: not authorized');
}
} catch (err) {
log(err);
return false;
}
},
addEnvironmentVariables: async (_: any, { projectId, environmentVariables }: { projectId: string, environmentVariables: { environments: string[], key: string, value: string}[] }) => {
try {
return db.addEnvironmentVariablesByProjectId(projectId, environmentVariables);
} catch (err) {
log(err);
return false; return false;
} }
} }

View File

@ -120,4 +120,11 @@ type Query {
type Mutation { type Mutation {
removeMember(memberId: String!): Boolean! removeMember(memberId: String!): Boolean!
addEnvironmentVariables(projectId: String!, environmentVariables: [AddEnvironmentVariableInput!]): Boolean!
}
input AddEnvironmentVariableInput {
environments: [Environment!]!
key: String!
value: String!
} }

View File

@ -79,3 +79,7 @@ export const environmentVariableToGqlType = (dbEnvironmentVariable: EnvironmentV
updatedAt: dbEnvironmentVariable.updatedAt updatedAt: dbEnvironmentVariable.updatedAt
}; };
}; };
export const isUserOwner = (userId: string, projectOwnerId: string): boolean => {
return userId === projectOwnerId;
};