Skip to content

Commit d64cde5

Browse files
authored
fix: prevent member identity existence check from timing out (#4248)
Signed-off-by: Yeganathan S <63534555+skwowet@users.noreply.github.com>
1 parent bb316cd commit d64cde5

2 files changed

Lines changed: 55 additions & 42 deletions

File tree

backend/src/services/member/memberIdentityService.ts

Lines changed: 35 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,13 @@
22
import lodash from 'lodash'
33

44
import { captureApiChange, memberEditIdentitiesAction } from '@crowd/audit-logs'
5-
import { Error409 } from '@crowd/common'
5+
import { Error404, Error409 } from '@crowd/common'
66
import { createMemberIdentity, findIdentitiesForMembers, optionsQx } from '@crowd/data-access-layer'
77
import {
8-
checkMemberIdentityExistence,
98
deleteMemberIdentity,
109
fetchMemberIdentities,
1110
findMemberIdentityById,
11+
findMemberIdentityConflict,
1212
touchMemberUpdatedAt,
1313
updateMemberIdentity,
1414
} from '@crowd/data-access-layer/src/members'
@@ -58,18 +58,19 @@ export default class MemberIdentityService extends LoggerBase {
5858
const qx = SequelizeRepository.getQueryExecutor(repoOptions)
5959

6060
// Check if identity already exists
61-
const existingIdentities = await checkMemberIdentityExistence(
62-
qx,
63-
data.value,
64-
data.platform,
65-
)
66-
if (existingIdentities.length > 0) {
61+
const conflict = await findMemberIdentityConflict(qx, {
62+
value: data.value,
63+
platform: data.platform,
64+
type: data.type,
65+
})
66+
67+
if (conflict) {
6768
throw new Error409(
6869
this.options.language,
6970
'errors.alreadyExists',
7071
// @ts-ignore
7172
JSON.stringify({
72-
memberId: existingIdentities[0].memberId,
73+
memberId: conflict.memberId,
7374
}),
7475
)
7576
}
@@ -130,19 +131,19 @@ export default class MemberIdentityService extends LoggerBase {
130131

131132
// Check if any of the identities already exist
132133
for (const identity of data) {
133-
const existingIdentities = await checkMemberIdentityExistence(
134-
qx,
135-
identity.value,
136-
identity.platform,
137-
)
134+
const conflict = await findMemberIdentityConflict(qx, {
135+
value: identity.value,
136+
platform: identity.platform,
137+
type: identity.type,
138+
})
138139

139-
if (existingIdentities.length > 0) {
140+
if (conflict) {
140141
throw new Error409(
141142
this.options.language,
142143
'errors.alreadyExists',
143144
// @ts-ignore
144145
JSON.stringify({
145-
memberId: existingIdentities[0].memberId,
146+
memberId: conflict.memberId,
146147
}),
147148
)
148149
}
@@ -203,20 +204,29 @@ export default class MemberIdentityService extends LoggerBase {
203204

204205
const qx = SequelizeRepository.getQueryExecutor(repoOptions)
205206

206-
// Check if identity already exists
207-
const existingIdentities = await checkMemberIdentityExistence(
208-
qx,
209-
data.value,
210-
data.platform,
211-
)
212-
const filteredExistingIdentities = existingIdentities.filter((i) => i.id !== id)
213-
if (filteredExistingIdentities.length > 0) {
207+
const currentIdentity = memberIdentities.find((identity) => identity.id === id)
208+
if (!currentIdentity) {
209+
throw new Error404(this.options.language, 'errors.notFound.message')
210+
}
211+
212+
const value = data.value ?? currentIdentity.value
213+
const platform = data.platform ?? currentIdentity.platform
214+
const type = data.type ?? currentIdentity.type
215+
216+
const conflict = await findMemberIdentityConflict(qx, {
217+
value,
218+
platform,
219+
type,
220+
excludeMemberId: memberId,
221+
})
222+
223+
if (conflict) {
214224
throw new Error409(
215225
this.options.language,
216226
'errors.alreadyExists',
217227
// @ts-ignore
218228
JSON.stringify({
219-
memberId: filteredExistingIdentities[0].memberId,
229+
memberId: conflict.memberId,
220230
}),
221231
)
222232
}

services/libs/data-access-layer/src/members/identities.ts

Lines changed: 20 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -49,26 +49,29 @@ export async function fetchManyMemberIdentities(
4949
)
5050
}
5151

52-
export async function checkMemberIdentityExistence(
52+
interface FindMemberIdentityConflictParams {
53+
value: IMemberIdentity['value']
54+
platform: IMemberIdentity['platform']
55+
type: IMemberIdentity['type']
56+
excludeMemberId?: string
57+
}
58+
59+
export async function findMemberIdentityConflict(
5360
qx: QueryExecutor,
54-
value: string,
55-
platform: string,
56-
type?: MemberIdentityType,
57-
): Promise<IMemberIdentity[]> {
58-
return await qx.select(
61+
params: FindMemberIdentityConflictParams,
62+
): Promise<{ id: string; memberId: string } | null> {
63+
return qx.selectOneOrNone(
5964
`
60-
SELECT id, "memberId", verified
61-
FROM "memberIdentities"
62-
WHERE "value" = $(value)
63-
AND "platform" = $(platform)
64-
${type ? 'AND "type" = $(type)' : ''}
65-
AND "deletedAt" is null;
65+
SELECT id, "memberId"
66+
FROM "memberIdentities"
67+
WHERE platform = $(platform)
68+
AND type = $(type)
69+
AND lower(value) = lower($(value))
70+
AND "deletedAt" IS NULL
71+
${params.excludeMemberId ? 'AND "memberId" <> $(excludeMemberId)' : ''}
72+
LIMIT 1;
6673
`,
67-
{
68-
value,
69-
platform,
70-
type,
71-
},
74+
params,
7275
)
7376
}
7477

0 commit comments

Comments
 (0)