From 0fac50f40ca4a7a5ee103220e3ed919ad2423ded Mon Sep 17 00:00:00 2001 From: Chris Bongers Date: Fri, 31 Oct 2025 10:04:31 +0200 Subject: [PATCH 1/3] fix: add safeguards for opportunity --- .../candidateOpportunityMatchNotification.ts | 13 +++------- .../notifications/warmIntroNotification.ts | 19 +++++---------- .../storeCandidateApplicationScore.ts | 6 +++++ .../storeCandidateOpportunityMatch.ts | 24 +++++++------------ 4 files changed, 24 insertions(+), 38 deletions(-) diff --git a/src/workers/notifications/candidateOpportunityMatchNotification.ts b/src/workers/notifications/candidateOpportunityMatchNotification.ts index 51b328e7c0..aea7a037b2 100644 --- a/src/workers/notifications/candidateOpportunityMatchNotification.ts +++ b/src/workers/notifications/candidateOpportunityMatchNotification.ts @@ -2,7 +2,7 @@ import { NotificationType } from '../../notifications/common'; import { TypedNotificationWorker } from '../worker'; import { TypeORMQueryFailedError } from '../../errors'; import { MatchedCandidate } from '@dailydotdev/schema'; -import { Feature, FeatureType } from '../../entity'; +import { User } from '../../entity'; const candidateOpportunityMatchNotification: TypedNotificationWorker<'gondul.v1.candidate-opportunity-match'> = { @@ -18,15 +18,8 @@ const candidateOpportunityMatchNotification: TypedNotificationWorker<'gondul.v1. return; } - // TODO: Temporary until we happy to launch - const isTeamMember = await con.getRepository(Feature).exists({ - where: { - userId, - feature: FeatureType.Team, - value: 1, - }, - }); - if (!isTeamMember) { + const user = await con.getRepository(User).findOneBy({ id: userId }); + if (!user) { return; } diff --git a/src/workers/notifications/warmIntroNotification.ts b/src/workers/notifications/warmIntroNotification.ts index ae10983475..307f461157 100644 --- a/src/workers/notifications/warmIntroNotification.ts +++ b/src/workers/notifications/warmIntroNotification.ts @@ -4,7 +4,7 @@ import { logger } from '../../logger'; import { OpportunityJob } from '../../entity/opportunities/OpportunityJob'; import { OpportunityUserType } from '../../entity/opportunities/types'; import { WarmIntro } from '@dailydotdev/schema'; -import { Feature, FeatureType } from '../../entity'; +import { Feature, FeatureType, User } from '../../entity'; import { OpportunityMatch } from '../../entity/OpportunityMatch'; import { markdown } from '../../common/markdown'; @@ -27,6 +27,11 @@ export const warmIntroNotification: TypedNotificationWorker<'gondul.v1.warm-intr return; } + const user = await con.getRepository(User).findOneBy({ id: userId }); + if (!user) { + return; + } + await con .getRepository(OpportunityMatch) .createQueryBuilder() @@ -43,18 +48,6 @@ export const warmIntroNotification: TypedNotificationWorker<'gondul.v1.warm-intr ) .execute(); - // TODO: Temporary until we happy to launch - const isTeamMember = await con.getRepository(Feature).exists({ - where: { - userId, - feature: FeatureType.Team, - value: 1, - }, - }); - if (!isTeamMember) { - return; - } - const organization = await opportunity.organization; const users = await opportunity.users; diff --git a/src/workers/opportunity/storeCandidateApplicationScore.ts b/src/workers/opportunity/storeCandidateApplicationScore.ts index d621f72309..f4afb064be 100644 --- a/src/workers/opportunity/storeCandidateApplicationScore.ts +++ b/src/workers/opportunity/storeCandidateApplicationScore.ts @@ -2,6 +2,7 @@ import { TypedWorker } from '../worker'; import { ApplicationScored } from '@dailydotdev/schema'; import { OpportunityMatch } from '../../entity/OpportunityMatch'; import { applicationScoreSchema } from '../../common/schema/opportunities'; +import { User } from '../../entity'; export const storeCandidateApplicationScore: TypedWorker<'gondul.v1.candidate-application-scored'> = { @@ -14,6 +15,11 @@ export const storeCandidateApplicationScore: TypedWorker<'gondul.v1.candidate-ap ); } + const user = await con.getRepository(User).findOneBy({ id: userId }); + if (!user) { + return; + } + const applicationRank = applicationScoreSchema.parse({ score, description, diff --git a/src/workers/opportunity/storeCandidateOpportunityMatch.ts b/src/workers/opportunity/storeCandidateOpportunityMatch.ts index 144a702dc9..1ad254732d 100644 --- a/src/workers/opportunity/storeCandidateOpportunityMatch.ts +++ b/src/workers/opportunity/storeCandidateOpportunityMatch.ts @@ -2,7 +2,7 @@ import { TypedWorker } from '../worker'; import { MatchedCandidate } from '@dailydotdev/schema'; import { OpportunityMatch } from '../../entity/OpportunityMatch'; import { opportunityMatchDescriptionSchema } from '../../common/schema/opportunities'; -import { Alerts, Feature, FeatureType } from '../../entity'; +import { Alerts, User } from '../../entity'; import { IsNull } from 'typeorm'; export const storeCandidateOpportunityMatch: TypedWorker<'gondul.v1.candidate-opportunity-match'> = @@ -17,6 +17,11 @@ export const storeCandidateOpportunityMatch: TypedWorker<'gondul.v1.candidate-op ); } + const user = await con.getRepository(User).findOneBy({ id: userId }); + if (!user) { + return; + } + const description = opportunityMatchDescriptionSchema.parse({ reasoning, reasoningShort, @@ -35,20 +40,9 @@ export const storeCandidateOpportunityMatch: TypedWorker<'gondul.v1.candidate-op skipUpdateIfNoValuesChanged: true, }, ); - - // TODO: Temporary until we happy to launch - const isTeamMember = await con.getRepository(Feature).exists({ - where: { - userId, - feature: FeatureType.Team, - value: 1, - }, - }); - if (isTeamMember) { - await manager - .getRepository(Alerts) - .update({ userId, opportunityId: IsNull() }, { opportunityId }); - } + await manager + .getRepository(Alerts) + .update({ userId, opportunityId: IsNull() }, { opportunityId }); }); }, parseMessage: (message) => { From 260f3ef52673a31b66ecf41c58aff7f75ce40836 Mon Sep 17 00:00:00 2001 From: Chris Bongers Date: Fri, 31 Oct 2025 10:08:51 +0200 Subject: [PATCH 2/3] fix: add logging --- .../notifications/candidateOpportunityMatchNotification.ts | 5 +++++ src/workers/notifications/warmIntroNotification.ts | 4 ++++ src/workers/opportunity/storeCandidateApplicationScore.ts | 5 +++++ src/workers/opportunity/storeCandidateOpportunityMatch.ts | 5 +++++ 4 files changed, 19 insertions(+) diff --git a/src/workers/notifications/candidateOpportunityMatchNotification.ts b/src/workers/notifications/candidateOpportunityMatchNotification.ts index aea7a037b2..509242e318 100644 --- a/src/workers/notifications/candidateOpportunityMatchNotification.ts +++ b/src/workers/notifications/candidateOpportunityMatchNotification.ts @@ -3,6 +3,7 @@ import { TypedNotificationWorker } from '../worker'; import { TypeORMQueryFailedError } from '../../errors'; import { MatchedCandidate } from '@dailydotdev/schema'; import { User } from '../../entity'; +import { logger } from '../../logger'; const candidateOpportunityMatchNotification: TypedNotificationWorker<'gondul.v1.candidate-opportunity-match'> = { @@ -20,6 +21,10 @@ const candidateOpportunityMatchNotification: TypedNotificationWorker<'gondul.v1. const user = await con.getRepository(User).findOneBy({ id: userId }); if (!user) { + logger.error( + { opportunityId, userId }, + 'candidateOpportunityMatchNotification: User not found', + ); return; } diff --git a/src/workers/notifications/warmIntroNotification.ts b/src/workers/notifications/warmIntroNotification.ts index 307f461157..38d90224e6 100644 --- a/src/workers/notifications/warmIntroNotification.ts +++ b/src/workers/notifications/warmIntroNotification.ts @@ -29,6 +29,10 @@ export const warmIntroNotification: TypedNotificationWorker<'gondul.v1.warm-intr const user = await con.getRepository(User).findOneBy({ id: userId }); if (!user) { + logger.error( + { opportunityId, userId, opportunity }, + 'warmIntroNotification: User not found', + ); return; } diff --git a/src/workers/opportunity/storeCandidateApplicationScore.ts b/src/workers/opportunity/storeCandidateApplicationScore.ts index f4afb064be..9e831659ed 100644 --- a/src/workers/opportunity/storeCandidateApplicationScore.ts +++ b/src/workers/opportunity/storeCandidateApplicationScore.ts @@ -3,6 +3,7 @@ import { ApplicationScored } from '@dailydotdev/schema'; import { OpportunityMatch } from '../../entity/OpportunityMatch'; import { applicationScoreSchema } from '../../common/schema/opportunities'; import { User } from '../../entity'; +import { logger } from '../../logger'; export const storeCandidateApplicationScore: TypedWorker<'gondul.v1.candidate-application-scored'> = { @@ -17,6 +18,10 @@ export const storeCandidateApplicationScore: TypedWorker<'gondul.v1.candidate-ap const user = await con.getRepository(User).findOneBy({ id: userId }); if (!user) { + logger.error( + { opportunityId, userId }, + 'storeCandidateApplicationScore: User not found', + ); return; } diff --git a/src/workers/opportunity/storeCandidateOpportunityMatch.ts b/src/workers/opportunity/storeCandidateOpportunityMatch.ts index 1ad254732d..cccc8a4e61 100644 --- a/src/workers/opportunity/storeCandidateOpportunityMatch.ts +++ b/src/workers/opportunity/storeCandidateOpportunityMatch.ts @@ -4,6 +4,7 @@ import { OpportunityMatch } from '../../entity/OpportunityMatch'; import { opportunityMatchDescriptionSchema } from '../../common/schema/opportunities'; import { Alerts, User } from '../../entity'; import { IsNull } from 'typeorm'; +import { logger } from '../../logger'; export const storeCandidateOpportunityMatch: TypedWorker<'gondul.v1.candidate-opportunity-match'> = { @@ -19,6 +20,10 @@ export const storeCandidateOpportunityMatch: TypedWorker<'gondul.v1.candidate-op const user = await con.getRepository(User).findOneBy({ id: userId }); if (!user) { + logger.error( + { opportunityId, userId }, + 'storeCandidateOpportunityMatch: User not found', + ); return; } From 3c8924d850715697596e99787422ad0f3f2572d5 Mon Sep 17 00:00:00 2001 From: Chris Bongers Date: Fri, 31 Oct 2025 10:13:51 +0200 Subject: [PATCH 3/3] fix: linting --- .../notifications/candidateOpportunityMatchNotification.ts | 1 - src/workers/notifications/warmIntroNotification.ts | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/workers/notifications/candidateOpportunityMatchNotification.ts b/src/workers/notifications/candidateOpportunityMatchNotification.ts index 509242e318..fbb27b0b4b 100644 --- a/src/workers/notifications/candidateOpportunityMatchNotification.ts +++ b/src/workers/notifications/candidateOpportunityMatchNotification.ts @@ -3,7 +3,6 @@ import { TypedNotificationWorker } from '../worker'; import { TypeORMQueryFailedError } from '../../errors'; import { MatchedCandidate } from '@dailydotdev/schema'; import { User } from '../../entity'; -import { logger } from '../../logger'; const candidateOpportunityMatchNotification: TypedNotificationWorker<'gondul.v1.candidate-opportunity-match'> = { diff --git a/src/workers/notifications/warmIntroNotification.ts b/src/workers/notifications/warmIntroNotification.ts index 38d90224e6..3366d05bac 100644 --- a/src/workers/notifications/warmIntroNotification.ts +++ b/src/workers/notifications/warmIntroNotification.ts @@ -4,7 +4,7 @@ import { logger } from '../../logger'; import { OpportunityJob } from '../../entity/opportunities/OpportunityJob'; import { OpportunityUserType } from '../../entity/opportunities/types'; import { WarmIntro } from '@dailydotdev/schema'; -import { Feature, FeatureType, User } from '../../entity'; +import { User } from '../../entity'; import { OpportunityMatch } from '../../entity/OpportunityMatch'; import { markdown } from '../../common/markdown';