Skip to content

Commit 790c29e

Browse files
authored
feat: parse opportunity for logged in users (#3338)
1 parent a870ac9 commit 790c29e

2 files changed

Lines changed: 130 additions & 15 deletions

File tree

__tests__/schema/opportunity.ts

Lines changed: 110 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5543,22 +5543,122 @@ describe('mutation parseOpportunity', () => {
55435543
expect(body.errors[0].message).toBe('File type not supported');
55445544
});
55455545

5546-
it('should not allow authenticated users to parse opportunity', async () => {
5546+
it('should parse opportunity for authenticated user', async () => {
55475547
loggedUser = '1';
55485548

5549-
const res = await client.mutate(MUTATION, {
5550-
variables: {
5551-
payload: {
5552-
url: 'https://example.com/opportunity',
5549+
trackingId = 'anon1';
5550+
5551+
fileTypeFromBuffer.mockResolvedValue({
5552+
ext: 'pdf',
5553+
mime: 'application/pdf',
5554+
});
5555+
5556+
const uploadResumeFromBufferSpy = jest.spyOn(
5557+
googleCloud,
5558+
'uploadResumeFromBuffer',
5559+
);
5560+
5561+
uploadResumeFromBufferSpy.mockResolvedValue(
5562+
`https://storage.cloud.google.com/${RESUME_BUCKET_NAME}/file`,
5563+
);
5564+
5565+
const deleteFileFromBucketSpy = jest.spyOn(
5566+
googleCloud,
5567+
'deleteFileFromBucket',
5568+
);
5569+
5570+
deleteFileFromBucketSpy.mockResolvedValue(true);
5571+
5572+
// Execute the mutation with a file upload
5573+
const res = await authorizeRequest(
5574+
request(app.server)
5575+
.post('/graphql')
5576+
.field(
5577+
'operations',
5578+
JSON.stringify({
5579+
query: MUTATION,
5580+
variables: {
5581+
payload: {
5582+
file: null,
5583+
},
5584+
},
5585+
}),
5586+
)
5587+
.field('map', JSON.stringify({ '0': ['variables.payload.file'] }))
5588+
.attach('0', './__tests__/fixture/screen.pdf'),
5589+
).expect(200);
5590+
5591+
const body = res.body;
5592+
expect(body.errors).toBeFalsy();
5593+
5594+
expect(body.data.parseOpportunity).toMatchObject({
5595+
title: 'Mocked Opportunity Title',
5596+
tldr: 'This is a mocked TL;DR of the opportunity.',
5597+
keywords: [
5598+
{ keyword: 'mock' },
5599+
{ keyword: 'opportunity' },
5600+
{ keyword: 'test' },
5601+
],
5602+
meta: {
5603+
employmentType: EmploymentType.FULL_TIME,
5604+
seniorityLevel: SeniorityLevel.SENIOR,
5605+
roleType: RoleType.Auto,
5606+
salary: {
5607+
min: 1000,
5608+
max: 2000,
5609+
period: SalaryPeriod.MONTHLY,
55535610
},
55545611
},
5612+
content: {
5613+
overview: {
5614+
content: 'This is the overview of the mocked opportunity.',
5615+
html: '<p>This is the overview of the mocked opportunity.</p>\n',
5616+
},
5617+
responsibilities: {
5618+
content: 'These are the responsibilities of the mocked opportunity.',
5619+
html: '<p>These are the responsibilities of the mocked opportunity.</p>\n',
5620+
},
5621+
requirements: {
5622+
content: 'These are the requirements of the mocked opportunity.',
5623+
html: '<p>These are the requirements of the mocked opportunity.</p>\n',
5624+
},
5625+
},
5626+
location: [
5627+
{
5628+
city: 'San Francisco',
5629+
country: 'USA',
5630+
subdivision: 'CA',
5631+
type: LocationType.REMOTE,
5632+
},
5633+
],
5634+
questions: [],
5635+
feedbackQuestions: [
5636+
{
5637+
title: 'Why did you reject this opportunity?',
5638+
placeholder: `E.g., Not interested in the tech stack, location doesn't work for me, compensation too low...`,
5639+
},
5640+
],
55555641
});
55565642

5557-
expect(res.errors).toBeDefined();
5558-
expect(res.errors?.[0].extensions.code).toBe('FORBIDDEN');
5559-
expect(res.errors?.[0].message).toBe(
5560-
'Not available for authenticated users yet',
5561-
);
5643+
const opportunity = await con.getRepository(OpportunityJob).findOne({
5644+
where: {
5645+
id: body.data.parseOpportunity.id,
5646+
},
5647+
});
5648+
5649+
expect(opportunity).toBeDefined();
5650+
expect(opportunity!.state).toBe(OpportunityState.DRAFT);
5651+
5652+
const opportunityRecruiter = await con
5653+
.getRepository(OpportunityUserRecruiter)
5654+
.findOne({
5655+
where: {
5656+
opportunityId: body.data.parseOpportunity.id,
5657+
userId: loggedUser,
5658+
},
5659+
});
5660+
5661+
expect(opportunityRecruiter).toBeDefined();
55625662
});
55635663
});
55645664

src/schema/opportunity.ts

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2077,8 +2077,8 @@ export const resolvers: IResolvers<unknown, BaseContext> = traceResolvers<
20772077
ctx: Context,
20782078
info,
20792079
): Promise<GQLOpportunity> => {
2080-
if (ctx.userId) {
2081-
throw new ForbiddenError('Not available for authenticated users yet');
2080+
if (!(ctx.userId || ctx.trackingId)) {
2081+
throw new ValidationError('User identifier is required');
20822082
}
20832083

20842084
const parseOpportunityPayload =
@@ -2175,16 +2175,20 @@ export const resolvers: IResolvers<unknown, BaseContext> = traceResolvers<
21752175

21762176
const opportunityResult = await ctx.con.transaction(
21772177
async (entityManager) => {
2178+
const flags: Opportunity['flags'] = {};
2179+
2180+
if (!ctx.userId) {
2181+
flags.anonUserId = ctx.trackingId; // save tracking id to attribute later
2182+
}
2183+
21782184
const opportunity = await entityManager
21792185
.getRepository(OpportunityJob)
21802186
.save(
21812187
entityManager.getRepository(OpportunityJob).create({
21822188
...parsedOpportunity,
21832189
state: OpportunityState.DRAFT,
21842190
content: opportunityContent,
2185-
flags: {
2186-
anonUserId: ctx.trackingId, // save tracking id to attribute later
2187-
},
2191+
flags,
21882192
} as DeepPartial<OpportunityJob>),
21892193
);
21902194

@@ -2200,6 +2204,17 @@ export const resolvers: IResolvers<unknown, BaseContext> = traceResolvers<
22002204
})),
22012205
);
22022206

2207+
if (ctx.userId) {
2208+
await entityManager
2209+
.getRepository(OpportunityUserRecruiter)
2210+
.insert(
2211+
entityManager.getRepository(OpportunityUserRecruiter).create({
2212+
opportunityId: opportunity.id,
2213+
userId: ctx.userId,
2214+
}),
2215+
);
2216+
}
2217+
22032218
return opportunity;
22042219
},
22052220
);

0 commit comments

Comments
 (0)