Skip to content
35 changes: 24 additions & 11 deletions backend/src/services/memberService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import validator from 'validator'
import { captureApiChange, memberMergeAction, memberUnmergeAction } from '@crowd/audit-logs'
import {
Error400,
Error409,
getEarliestValidDate,
getProperDisplayName,
isDomainExcluded,
Expand All @@ -23,6 +24,7 @@ import {
queryMembersAdvanced,
removeMemberTags,
} from '@crowd/data-access-layer/src/members'
import { findMergeAction } from '@crowd/data-access-layer/src/mergeActions/repo'
import { QueryExecutor, optionsQx } from '@crowd/data-access-layer/src/queryExecutor'
// import { getActivityCountOfMemberIdentities } from '@crowd/data-access-layer'
import { fetchManySegments } from '@crowd/data-access-layer/src/segments'
Expand Down Expand Up @@ -1204,10 +1206,21 @@ export default class MemberService extends LoggerBase {
}
}

const qx = SequelizeRepository.getQueryExecutor(this.options)

const mergeAction = await findMergeAction(qx, originalId, toMergeId)

// prevent multiple merge operations
if (
mergeAction?.state === MergeActionState.IN_PROGRESS ||
mergeAction?.state === MergeActionState.PENDING
) {
throw new Error409(this.options.language, 'merge.errors.multipleMerge', mergeAction?.state)
}

let tx

const getMemberById = async (memberId: string) => {
const qx = SequelizeRepository.getQueryExecutor(this.options)
const member = await findMemberById(qx, memberId, [
MemberField.ID,
MemberField.DISPLAY_NAME,
Expand Down Expand Up @@ -1346,21 +1359,21 @@ export default class MemberService extends LoggerBase {
currentSegments: secondMemberSegments,
})

await MergeActionsRepository.setMergeAction(
MergeActionType.MEMBER,
originalId,
toMergeId,
repoOptions,
{
step: MergeActionStep.MERGE_SYNC_DONE,
},
)

await SequelizeRepository.commitTransaction(tx)
return { original, toMerge }
}),
)

await MergeActionsRepository.setMergeAction(
MergeActionType.MEMBER,
originalId,
toMergeId,
this.options,
{
step: MergeActionStep.MERGE_SYNC_DONE,
},
)

await this.options.temporal.workflow.start('finishMemberMerging', {
taskQueue: 'entity-merging',
workflowId: `finishMemberMerging/${originalId}/${toMergeId}`,
Expand Down
13 changes: 12 additions & 1 deletion backend/src/services/organizationService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@ import {
organizationMergeAction,
organizationUnmergeAction,
} from '@crowd/audit-logs'
import { websiteNormalizer } from '@crowd/common'
import { Error409, websiteNormalizer } from '@crowd/common'
import { hasLfxMembership } from '@crowd/data-access-layer/src/lfx_memberships'
import { findMergeAction } from '@crowd/data-access-layer/src/mergeActions/repo'
import { findOrgAttributes, upsertOrgIdentities } from '@crowd/data-access-layer/src/organizations'
import { LoggerBase } from '@crowd/logging'
import { WorkflowIdReusePolicy } from '@crowd/temporal'
Expand Down Expand Up @@ -402,6 +403,16 @@ export default class OrganizationService extends LoggerBase {
const qx = SequelizeRepository.getQueryExecutor(this.options)
const tenantId = this.options.currentTenant.id

const mergeAction = await findMergeAction(qx, originalId, toMergeId)

// prevent multiple merge operations
if (
mergeAction?.state === MergeActionState.IN_PROGRESS ||
mergeAction?.state === MergeActionState.PENDING
) {
throw new Error409(this.options.language, 'merge.errors.multipleMerge', mergeAction?.state)
}

try {
const { original, toMerge } = await captureApiChange(
this.options,
Expand Down
6 changes: 6 additions & 0 deletions services/libs/common/src/i18n/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,12 @@ const en = {
alreadyExists: '{0}',
},

merge: {
errors: {
multipleMerge: 'Cannot merge suggestions - found existing merge with {0} state',
},
},

email: {
error: `Email provider is not configured.`,
},
Expand Down
31 changes: 30 additions & 1 deletion services/libs/data-access-layer/src/mergeActions/repo.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import validator from 'validator'

import { IMergeAction } from '@crowd/types'
import { IMergeAction, MergeActionState } from '@crowd/types'

import { QueryExecutor } from '../queryExecutor'

Expand Down Expand Up @@ -50,3 +50,32 @@ export async function queryMergeActions(

return result
}

export async function findMergeAction(
qx: QueryExecutor,
primaryId: string,
secondaryId: string,
{ state }: { state?: MergeActionState } = {},
): Promise<IMergeAction> {
let where = ''

const params = {
primaryId,
secondaryId,
}

if (state) {
where += ` and "state" = $(state)`
params['state'] = state
}

return qx.selectOneOrNone(
`
select * from "mergeActions"
where "primaryId" = $(primaryId)
and "secondaryId" = $(secondaryId)
${where}
`,
params,
)
}
1 change: 0 additions & 1 deletion services/libs/types/src/enums/merging.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ export enum MergeActionState {
IN_PROGRESS = 'in-progress',
MERGED = 'merged',
UNMERGED = 'unmerged',
FINISHING = 'finishing',
ERROR = 'error',
}

Expand Down
Loading