Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
31 changes: 30 additions & 1 deletion backend/src/api/public/middlewares/errorHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,13 @@ import {
UnauthorizedError as Auth0UnauthorizedError,
} from 'express-oauth2-jwt-bearer'

import { HttpError, InsufficientScopeError, InternalError, UnauthorizedError } from '@crowd/common'
import {
ConflictError,
HttpError,
InsufficientScopeError,
InternalError,
UnauthorizedError,
} from '@crowd/common'
import { SlackChannel, SlackPersona, sendSlackNotification } from '@crowd/slack'

/**
Expand All @@ -17,6 +23,29 @@ export const errorHandler: ErrorRequestHandler = (
res: Response,
_next: NextFunction,
) => {
if (error instanceof ConflictError) {
const memberIds = (error as ConflictError & { memberIds?: string[] }).memberIds
req.log.warn({ memberIds }, 'Public API conflict')
sendSlackNotification(
SlackChannel.CDP_LFX_SELF_SERVE_ALERTS,
SlackPersona.WARNING_PROPAGATOR,
Comment thread
joanagmaia marked this conversation as resolved.
`Public API Conflict 409: ${req.method} ${req.url}`,
[
{
title: 'Request',
text: `*Method:* \`${req.method}\`\n*URL:* \`${req.url}\``,
},
Comment thread
joanagmaia marked this conversation as resolved.
{
title: 'Conflict',
text: `*Message:* ${error.message}`,
},
...(memberIds ? [{ title: 'Member IDs', text: memberIds.join(', ') }] : []),
],
)
Comment thread
joanagmaia marked this conversation as resolved.
res.status(error.status).json(error.toJSON())
return
}
Comment thread
joanagmaia marked this conversation as resolved.

if (error instanceof HttpError) {
res.status(error.status).json(error.toJSON())
return
Expand Down
8 changes: 7 additions & 1 deletion backend/src/api/public/v1/members/resolveMember.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,13 @@ export async function resolveMemberByIdentities(req: Request, res: Response): Pr
if (memberIds.length === 0) {
throw new NotFoundError('Member not found')
} else if (memberIds.length > 1) {
throw new ConflictError('Conflicting identities')
const error = new ConflictError('Conflicting identities')
Object.defineProperty(error, 'memberIds', {
value: memberIds,
enumerable: false,
configurable: true,
})
throw error
Comment on lines +35 to +41
}

const memberId = memberIds[0]
Expand Down
44 changes: 17 additions & 27 deletions services/apps/members_enrichment_worker/src/activities/member.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,14 +77,8 @@ export async function getIdentitiesExistInOtherMembers(
excludeMemberId: string,
identities: IMemberIdentity[],
): Promise<IMemberIdentity[]> {
let rows: IMemberIdentity[] = []

try {
const db = svc.postgres.reader
rows = await getIdentitiesExistInOthers(db, excludeMemberId, identities)
} catch (err) {
throw err
}
const db = svc.postgres.reader
const rows = await getIdentitiesExistInOthers(db, excludeMemberId, identities)

return rows
}
Expand All @@ -94,25 +88,21 @@ export async function updateMemberWithEnrichmentData(
identities: IMemberIdentity[],
attributes?: IAttributes,
): Promise<void> {
try {
await svc.postgres.writer.connection().tx(async (tx) => {
for (const identity of identities) {
await createMemberIdentity(new PgPromiseQueryExecutor(tx), {
memberId,
platform: identity.platform,
value: identity.value,
type: identity.type,
verified: identity.verified || false,
source: 'enrichment',
})
}
if (attributes) {
await updateMemberAttributes(tx, memberId, attributes)
}
})
} catch (err) {
throw err
}
await svc.postgres.writer.connection().tx(async (tx) => {
for (const identity of identities) {
await createMemberIdentity(new PgPromiseQueryExecutor(tx), {
memberId,
platform: identity.platform,
value: identity.value,
type: identity.type,
verified: identity.verified || false,
source: 'enrichment',
})
}
if (attributes) {
await updateMemberAttributes(tx, memberId, attributes)
}
})
}

export async function mergeMembers(
Expand Down
1 change: 1 addition & 0 deletions services/libs/slack/src/channels.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ const CHANNEL_WEBHOOK_URLS: Record<SlackChannel, string | undefined> = {
[SlackChannel.CDP_PROJECTS_ALERTS]: process.env.CDP_PROJECTS_ALERTS_SLACK_WEBHOOK_URL,
[SlackChannel.INSIGHTS_ALERTS]: process.env.INSIGHTS_ALERTS_SLACK_WEBHOOK_URL,
[SlackChannel.INSIGHTS_CRITICAL_ALERTS]: process.env.INSIGHTS_CRITICAL_ALERTS_SLACK_WEBHOOK_URL,
[SlackChannel.CDP_LFX_SELF_SERVE_ALERTS]: process.env.CDP_LFX_SELF_SERVE_ALERTS_SLACK_WEBHOOK_URL,
}

// Check for missing webhook URLs on initialization
Expand Down
1 change: 1 addition & 0 deletions services/libs/slack/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export enum SlackChannel {
CDP_PROJECTS_ALERTS = 'CDP_PROJECTS_ALERTS',
INSIGHTS_ALERTS = 'INSIGHTS_ALERTS',
INSIGHTS_CRITICAL_ALERTS = 'INSIGHTS_CRITICAL_ALERTS',
CDP_LFX_SELF_SERVE_ALERTS = 'CDP_LFX_SELF_SERVE_ALERTS',
}

export enum SlackPersona {
Expand Down
Loading