Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
178 changes: 36 additions & 142 deletions __tests__/schema/opportunity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -455,14 +455,14 @@ describe('query opportunityById', () => {
});
});

describe('query getOpportunities', () => {
describe('query opportunities', () => {
const GET_OPPORTUNITIES_QUERY = /* GraphQL */ `
query GetOpportunities(
$state: ProtoEnumValue
$first: Int
$after: String
) {
getOpportunities(state: $state, first: $first, after: $after) {
opportunities(state: $state, first: $first, after: $after) {
pageInfo {
hasNextPage
hasPreviousPage
Expand Down Expand Up @@ -515,8 +515,8 @@ describe('query getOpportunities', () => {
});

expect(res.errors).toBeFalsy();
expect(res.data.getOpportunities.edges).toHaveLength(3);
expect(res.data.getOpportunities.pageInfo.hasNextPage).toBe(false);
expect(res.data.opportunities.edges).toHaveLength(3);
expect(res.data.opportunities.pageInfo.hasNextPage).toBe(false);
});

it('should return only recruiter DRAFT opportunities for authenticated non-team member', async () => {
Expand All @@ -527,8 +527,8 @@ describe('query getOpportunities', () => {
});

expect(res.errors).toBeFalsy();
expect(res.data.getOpportunities.edges).toHaveLength(1);
expect(res.data.getOpportunities.edges[0].node).toEqual(
expect(res.data.opportunities.edges).toHaveLength(1);
expect(res.data.opportunities.edges[0].node).toEqual(
expect.objectContaining({
id: '550e8400-e29b-41d4-a716-446655440003',
state: OpportunityState.DRAFT,
Expand All @@ -544,8 +544,8 @@ describe('query getOpportunities', () => {
});

expect(res.errors).toBeFalsy();
expect(res.data.getOpportunities.edges).toHaveLength(1);
expect(res.data.getOpportunities.edges[0].node).toEqual(
expect(res.data.opportunities.edges).toHaveLength(1);
expect(res.data.opportunities.edges[0].node).toEqual(
expect.objectContaining({
id: '550e8400-e29b-41d4-a716-446655440004',
state: OpportunityState.DRAFT,
Expand All @@ -562,8 +562,8 @@ describe('query getOpportunities', () => {
});

expect(res.errors).toBeFalsy();
expect(res.data.getOpportunities.edges).toHaveLength(2);
const nodes = res.data.getOpportunities.edges.map(
expect(res.data.opportunities.edges).toHaveLength(2);
const nodes = res.data.opportunities.edges.map(
(e: { node: unknown }) => e.node,
);
expect(nodes).toEqual(
Expand All @@ -590,9 +590,9 @@ describe('query getOpportunities', () => {
});

expect(res.errors).toBeFalsy();
expect(res.data.getOpportunities.edges).toHaveLength(2);
expect(res.data.getOpportunities.pageInfo.hasNextPage).toBe(true);
expect(res.data.getOpportunities.pageInfo.endCursor).toBeTruthy();
expect(res.data.opportunities.edges).toHaveLength(2);
expect(res.data.opportunities.pageInfo.hasNextPage).toBe(true);
expect(res.data.opportunities.pageInfo.endCursor).toBeTruthy();
});

it('should support pagination with after cursor', async () => {
Expand All @@ -604,19 +604,17 @@ describe('query getOpportunities', () => {
});

expect(firstPage.errors).toBeFalsy();
const endCursor = firstPage.data.getOpportunities.pageInfo.endCursor;
const endCursor = firstPage.data.opportunities.pageInfo.endCursor;

// Get second page
const secondPage = await client.query(GET_OPPORTUNITIES_QUERY, {
variables: { state: OpportunityState.LIVE, first: 2, after: endCursor },
});

expect(secondPage.errors).toBeFalsy();
expect(secondPage.data.getOpportunities.edges).toHaveLength(1);
expect(secondPage.data.getOpportunities.pageInfo.hasNextPage).toBe(false);
expect(secondPage.data.getOpportunities.pageInfo.hasPreviousPage).toBe(
true,
);
expect(secondPage.data.opportunities.edges).toHaveLength(1);
expect(secondPage.data.opportunities.pageInfo.hasNextPage).toBe(false);
expect(secondPage.data.opportunities.pageInfo.hasPreviousPage).toBe(true);
});
});

Expand Down Expand Up @@ -736,14 +734,14 @@ describe('query getOpportunityMatch', () => {
});
});

describe('query getOpportunityMatches', () => {
describe('query opportunityMatches', () => {
const GET_OPPORTUNITY_MATCHES_QUERY = /* GraphQL */ `
query GetOpportunityMatches(
$opportunityId: ID!
$first: Int
$after: String
) {
getOpportunityMatches(
opportunityMatches(
opportunityId: $opportunityId
first: $first
after: $after
Expand Down Expand Up @@ -827,9 +825,9 @@ describe('query getOpportunityMatches', () => {
});

expect(res.errors).toBeFalsy();
expect(res.data.getOpportunityMatches.edges).toHaveLength(3);
expect(res.data.opportunityMatches.edges).toHaveLength(3);

const statuses = res.data.getOpportunityMatches.edges.map(
const statuses = res.data.opportunityMatches.edges.map(
(e: { node: { status: string } }) => e.node.status,
);

Expand All @@ -856,7 +854,7 @@ describe('query getOpportunityMatches', () => {

expect(res.errors).toBeFalsy();

const acceptedMatch = res.data.getOpportunityMatches.edges.find(
const acceptedMatch = res.data.opportunityMatches.edges.find(
(e: { node: { status: string } }) =>
e.node.status === 'candidate_accepted',
);
Expand Down Expand Up @@ -884,7 +882,7 @@ describe('query getOpportunityMatches', () => {

expect(res.errors).toBeFalsy();

const acceptedMatch = res.data.getOpportunityMatches.edges.find(
const acceptedMatch = res.data.opportunityMatches.edges.find(
(e: { node: { status: string } }) =>
e.node.status === 'candidate_accepted',
);
Expand Down Expand Up @@ -915,9 +913,9 @@ describe('query getOpportunityMatches', () => {
});

expect(res.errors).toBeFalsy();
expect(res.data.getOpportunityMatches.edges).toHaveLength(2);
expect(res.data.getOpportunityMatches.pageInfo.hasNextPage).toBe(true);
expect(res.data.getOpportunityMatches.pageInfo.endCursor).toBeTruthy();
expect(res.data.opportunityMatches.edges).toHaveLength(2);
expect(res.data.opportunityMatches.pageInfo.hasNextPage).toBe(true);
expect(res.data.opportunityMatches.pageInfo.endCursor).toBeTruthy();
});

it('should support pagination with after cursor', async () => {
Expand All @@ -932,14 +930,12 @@ describe('query getOpportunityMatches', () => {
});

expect(firstPage.errors).toBeFalsy();
expect(firstPage.data.getOpportunityMatches.edges).toHaveLength(2);
expect(firstPage.data.getOpportunityMatches.pageInfo.hasNextPage).toBe(
true,
);
const firstUserIds = firstPage.data.getOpportunityMatches.edges.map(
expect(firstPage.data.opportunityMatches.edges).toHaveLength(2);
expect(firstPage.data.opportunityMatches.pageInfo.hasNextPage).toBe(true);
const firstUserIds = firstPage.data.opportunityMatches.edges.map(
(e: { node: { userId: string } }) => e.node.userId,
);
const endCursor = firstPage.data.getOpportunityMatches.pageInfo.endCursor;
const endCursor = firstPage.data.opportunityMatches.pageInfo.endCursor;

// Get second page
const secondPage = await client.query(GET_OPPORTUNITY_MATCHES_QUERY, {
Expand All @@ -951,15 +947,13 @@ describe('query getOpportunityMatches', () => {
});

expect(secondPage.errors).toBeFalsy();
expect(secondPage.data.getOpportunityMatches.edges).toHaveLength(1);
expect(secondPage.data.getOpportunityMatches.pageInfo.hasNextPage).toBe(
false,
);
expect(secondPage.data.opportunityMatches.edges).toHaveLength(1);
expect(secondPage.data.opportunityMatches.pageInfo.hasNextPage).toBe(false);
// Verify we got different results
expect(firstUserIds).not.toContain(
secondPage.data.getOpportunityMatches.edges[0].node.userId,
secondPage.data.opportunityMatches.edges[0].node.userId,
);
expect(secondPage.data.getOpportunityMatches.pageInfo.hasPreviousPage).toBe(
expect(secondPage.data.opportunityMatches.pageInfo.hasPreviousPage).toBe(
true,
);
});
Expand Down Expand Up @@ -1014,8 +1008,8 @@ describe('query getOpportunityMatches', () => {
});

expect(res.errors).toBeFalsy();
expect(res.data.getOpportunityMatches.edges).toHaveLength(0);
expect(res.data.getOpportunityMatches.pageInfo.hasNextPage).toBe(false);
expect(res.data.opportunityMatches.edges).toHaveLength(0);
expect(res.data.opportunityMatches.pageInfo.hasNextPage).toBe(false);
});
});

Expand Down Expand Up @@ -1874,22 +1868,6 @@ describe('mutation acceptOpportunityMatch', () => {
'Access denied! Match is not pending',
);
});

it('should return error when the opportunity is not live', async () => {
loggedUser = '1';

await testMutationErrorCode(
client,
{
mutation: MUTATION,
variables: {
id: '550e8400-e29b-41d4-a716-446655440003',
},
},
'FORBIDDEN',
'Access denied! Opportunity is not live',
);
});
});

describe('mutation rejectOpportunityMatch', () => {
Expand Down Expand Up @@ -1990,22 +1968,6 @@ describe('mutation rejectOpportunityMatch', () => {
'Access denied! Match is not pending',
);
});

it('should return error when the opportunity is not live', async () => {
loggedUser = '1';

await testMutationErrorCode(
client,
{
mutation: MUTATION,
variables: {
id: '550e8400-e29b-41d4-a716-446655440003',
},
},
'FORBIDDEN',
'Access denied! Opportunity is not live',
);
});
});

describe('mutation recruiterAcceptOpportunityMatch', () => {
Expand Down Expand Up @@ -2107,40 +2069,6 @@ describe('mutation recruiterAcceptOpportunityMatch', () => {
);
});

it('should return error when the opportunity is not live', async () => {
loggedUser = '1';

await saveFixtures(con, OpportunityUser, [
{
opportunityId: opportunitiesFixture[2].id,
userId: usersFixture[0].id,
type: OpportunityUserType.Recruiter,
},
]);

// Update the existing Pending match to CandidateAccepted
await con.getRepository(OpportunityMatch).update(
{
opportunityId: opportunitiesFixture[2].id,
userId: usersFixture[0].id,
},
{ status: OpportunityMatchStatus.CandidateAccepted },
);

await testMutationErrorCode(
client,
{
mutation: MUTATION,
variables: {
opportunityId: '550e8400-e29b-41d4-a716-446655440003', // DRAFT opportunity
candidateUserId: '1',
},
},
'FORBIDDEN',
'Access denied! Opportunity is not live',
);
});

it('should return error when match does not exist', async () => {
loggedUser = '1';

Expand Down Expand Up @@ -2427,40 +2355,6 @@ describe('mutation recruiterRejectOpportunityMatch', () => {
);
});

it('should return error when the opportunity is not live', async () => {
loggedUser = '1';

await saveFixtures(con, OpportunityUser, [
{
opportunityId: opportunitiesFixture[2].id,
userId: usersFixture[0].id,
type: OpportunityUserType.Recruiter,
},
]);

// Update the existing Pending match to CandidateAccepted
await con.getRepository(OpportunityMatch).update(
{
opportunityId: opportunitiesFixture[2].id,
userId: usersFixture[0].id,
},
{ status: OpportunityMatchStatus.CandidateAccepted },
);

await testMutationErrorCode(
client,
{
mutation: MUTATION,
variables: {
opportunityId: '550e8400-e29b-41d4-a716-446655440003', // DRAFT opportunity
candidateUserId: '1',
},
},
'FORBIDDEN',
'Access denied! Opportunity is not live',
);
});

it('should return error when match does not exist', async () => {
loggedUser = '1';

Expand Down
4 changes: 2 additions & 2 deletions src/common/googleCloud.ts
Original file line number Diff line number Diff line change
Expand Up @@ -145,13 +145,13 @@ export const generateSignedUrl = async ({
* Generate a signed URL for a resume/CV file
*/
export const generateResumeSignedUrl = async (
userId: string,
blobName: string,
expiresInMinutes?: number,
): Promise<string | null> => {
const { bucketName } = gcsBucketMap.resume;
return generateSignedUrl({
bucketName,
blobName: userId,
blobName,
expiresInMinutes,
});
};
Expand Down
6 changes: 6 additions & 0 deletions src/graphorm/graphorm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@ export interface GraphORMType {
fields?: { [name: string]: GraphORMField };
// Array of columns to select regardless of the resolve tree
requiredColumns?: (string | RequiredColumnConfig)[];
// Array of columns to ignore
ignoredColumns?: (string | RequiredColumnConfig)[];
// Restricted columns when the user is not authenticated
anonymousRestrictedColumns?: (string | RequiredColumnConfig)[];
// Define a function to manipulate the query every time
Expand Down Expand Up @@ -292,6 +294,7 @@ export class GraphORM {
): QueryBuilder {
const childType = Object.keys(field.fieldsByTypeName)[0];
const mapping = this.mappings?.[type]?.fields?.[field.name];

if (mapping?.alias) {
const fieldsByTypeName = childType
? {
Expand Down Expand Up @@ -387,6 +390,9 @@ export class GraphORM {
let newBuilder = builder.from(tableName, alias).select([]);

fields.forEach((field) => {
if (this.mappings?.[type]?.ignoredColumns?.includes(field.name)) {
return;
}
if (this.checkIsColumnRestricted(ctx, type, field.name)) {
return;
}
Expand Down
Loading
Loading