From 454eb76098176941d2faa251ddffbe37ea7cffaf Mon Sep 17 00:00:00 2001 From: Yeganathan S Date: Wed, 17 Jul 2024 16:28:59 +0530 Subject: [PATCH 01/16] todo --- services/libs/data-access-layer/src/mergeActions/repo.ts | 1 + 1 file changed, 1 insertion(+) create mode 100644 services/libs/data-access-layer/src/mergeActions/repo.ts diff --git a/services/libs/data-access-layer/src/mergeActions/repo.ts b/services/libs/data-access-layer/src/mergeActions/repo.ts new file mode 100644 index 0000000000..ebdda79f60 --- /dev/null +++ b/services/libs/data-access-layer/src/mergeActions/repo.ts @@ -0,0 +1 @@ +// todo: mergeActions repo From ade1eeab9ec3215cc434a72523114e7f8a8875a9 Mon Sep 17 00:00:00 2001 From: Yeganathan S Date: Fri, 19 Jul 2024 13:10:25 +0530 Subject: [PATCH 02/16] Add step in mergeAction to track operation --- .../scripts/merge-similar-organizations.ts | 7 +- .../U1721311363__addStepToMergeActions.sql | 1 + .../V1721311363__addStepToMergeActions.sql | 2 + .../repositories/mergeActionsRepository.ts | 67 +++++++++++++++++-- backend/src/services/memberService.ts | 33 +++++++++ backend/src/services/organizationService.ts | 33 +++++++-- .../entity_merging_worker/src/activities.ts | 2 +- .../src/activities/common.ts | 8 +-- .../src/workflows/all.ts | 37 ++++++++-- .../old/apps/entity_merging_worker/index.ts | 32 ++++++--- services/libs/types/src/enums/merging.ts | 12 ++++ services/libs/types/src/merging.ts | 2 + 12 files changed, 202 insertions(+), 34 deletions(-) create mode 100644 backend/src/database/migrations/U1721311363__addStepToMergeActions.sql create mode 100644 backend/src/database/migrations/V1721311363__addStepToMergeActions.sql diff --git a/backend/src/bin/scripts/merge-similar-organizations.ts b/backend/src/bin/scripts/merge-similar-organizations.ts index 61b7dc4268..7fb2dbe746 100644 --- a/backend/src/bin/scripts/merge-similar-organizations.ts +++ b/backend/src/bin/scripts/merge-similar-organizations.ts @@ -145,16 +145,19 @@ if (parameters.help || (!parameters.tenant && !parameters.allTenants)) { row.organizationId, row.toMergeId, userContext, + undefined ) await orgService.mergeSync(row.organizationId, row.toMergeId, null) } catch (err) { console.log('Error merging organizations - continuing with the rest', err) - await MergeActionsRepository.setState( + await MergeActionsRepository.update( MergeActionType.ORG, row.organizationId, row.toMergeId, - MergeActionState.ERROR, userContext, + { + state: MergeActionState.ERROR, + } ) } diff --git a/backend/src/database/migrations/U1721311363__addStepToMergeActions.sql b/backend/src/database/migrations/U1721311363__addStepToMergeActions.sql new file mode 100644 index 0000000000..c5812669d5 --- /dev/null +++ b/backend/src/database/migrations/U1721311363__addStepToMergeActions.sql @@ -0,0 +1 @@ +alter table "mergeActions" drop column "step"; \ No newline at end of file diff --git a/backend/src/database/migrations/V1721311363__addStepToMergeActions.sql b/backend/src/database/migrations/V1721311363__addStepToMergeActions.sql new file mode 100644 index 0000000000..1bce0447f2 --- /dev/null +++ b/backend/src/database/migrations/V1721311363__addStepToMergeActions.sql @@ -0,0 +1,2 @@ +alter table "mergeActions" add column "step" text; + diff --git a/backend/src/database/repositories/mergeActionsRepository.ts b/backend/src/database/repositories/mergeActionsRepository.ts index 3bb0b332d0..7cb57f37ab 100644 --- a/backend/src/database/repositories/mergeActionsRepository.ts +++ b/backend/src/database/repositories/mergeActionsRepository.ts @@ -8,6 +8,7 @@ import { IUnmergeBackup, MemberIdentityType, MergeActionState, + MergeActionStep, MergeActionType, OrganizationIdentityType, } from '@crowd/types' @@ -20,6 +21,7 @@ class MergeActionsRepository { primaryId: string, secondaryId: string, options: IRepositoryOptions, + step: MergeActionStep, state: MergeActionState = MergeActionState.PENDING, backup: IUnmergeBackup = undefined, ) { @@ -29,8 +31,8 @@ class MergeActionsRepository { await options.database.sequelize.query( ` - INSERT INTO "mergeActions" ("tenantId", "type", "primaryId", "secondaryId", state, "unmergeBackup", "actionBy") - VALUES (:tenantId, :type, :primaryId, :secondaryId, :state, :backup, :userId) + INSERT INTO "mergeActions" ("tenantId", "type", "primaryId", "secondaryId", state, step, "unmergeBackup", "actionBy") + VALUES (:tenantId, :type, :primaryId, :secondaryId, :state, :step, :backup, :userId) ON CONFLICT ("tenantId", "type", "primaryId", "secondaryId") DO UPDATE SET state = :state, "unmergeBackup" = :backup `, @@ -40,6 +42,7 @@ class MergeActionsRepository { type, primaryId, secondaryId, + step, state, backup: backup ? JSON.stringify(backup) : null, userId, @@ -50,11 +53,62 @@ class MergeActionsRepository { ) } - static async setState( + static async setMergeAction( type: MergeActionType, primaryId: string, secondaryId: string, - state: MergeActionState, + options: IRepositoryOptions, + data: { + step?: MergeActionStep, + state?: MergeActionState, + } + ) { + const transaction = SequelizeRepository.getTransaction(options) + const tenantId = options.currentTenant.id + + const setClauses = [] + const replacements: any = { + tenantId, + type, + primaryId, + secondaryId, + } + + if (data.step) { + setClauses.push(`step = :step`) + replacements.step = data.step + } + + if (data.state) { + setClauses.push(`state = :state`) + replacements.state = data.state + } + + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const [_, rowCount] = await options.database.sequelize.query( + ` + UPDATE "mergeActions" + SET ${setClauses.join(', ')} + WHERE "tenantId" = :tenantId + AND type = :type + AND "primaryId" = :primaryId + AND "secondaryId" = :secondaryId + `, + { + replacements, + type: QueryTypes.UPDATE, + transaction, + }, + ) + + return rowCount > 0 + } + + static async setStep( + type: MergeActionType, + primaryId: string, + secondaryId: string, + step: MergeActionStep, options: IRepositoryOptions, ) { const transaction = SequelizeRepository.getTransaction(options) @@ -64,12 +118,11 @@ class MergeActionsRepository { const [_, rowCount] = await options.database.sequelize.query( ` UPDATE "mergeActions" - SET state = :state + SET step = :step WHERE "tenantId" = :tenantId AND type = :type AND "primaryId" = :primaryId AND "secondaryId" = :secondaryId - AND state != :state `, { replacements: { @@ -77,7 +130,7 @@ class MergeActionsRepository { type, primaryId, secondaryId, - state, + step, }, type: QueryTypes.UPDATE, transaction, diff --git a/backend/src/services/memberService.ts b/backend/src/services/memberService.ts index cef6f97e38..e8076097b9 100644 --- a/backend/src/services/memberService.ts +++ b/backend/src/services/memberService.ts @@ -25,6 +25,7 @@ import { MemberRoleUnmergeStrategy, OrganizationIdentityType, IMemberRoleWithOrganization, + MergeActionStep, } from '@crowd/types' import { randomUUID } from 'crypto' import lodash from 'lodash' @@ -697,6 +698,17 @@ export default class MemberService extends LoggerBase { // create the secondary member const secondaryMember = await MemberRepository.create(payload.secondary, repoOptions) + + // track merge action + await MergeActionsRepository.add( + MergeActionType.MEMBER, + member.id, + secondaryMember.id, + repoOptions, + MergeActionStep.UNMERGE_STARTED, + MergeActionState.IN_PROGRESS + ) + // move affiliations if (payload.secondary.affiliations.length > 0) { await MemberRepository.moveSelectedAffiliationsBetweenMembers( @@ -823,6 +835,16 @@ export default class MemberService extends LoggerBase { // trigger entity-merging-worker to move activities in the background await SequelizeRepository.commitTransaction(tx) + await MergeActionsRepository.setMergeAction( + MergeActionType.MEMBER, + member.id, + secondaryMember.id, + repoOptions, + { + step: MergeActionStep.UNMERGE_SYNC_DONE, + } + ) + // responsible for moving member's activities, syncing to opensearch afterwards, recalculating activity.organizationIds and notifying frontend via websockets await this.options.temporal.workflow.start('finishMemberUnmerging', { taskQueue: 'entity-merging', @@ -1287,6 +1309,7 @@ export default class MemberService extends LoggerBase { originalId, toMergeId, this.options, + MergeActionStep.MERGE_STARTED, MergeActionState.IN_PROGRESS, backup, ) @@ -1365,6 +1388,16 @@ export default class MemberService extends LoggerBase { }), ) + 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}`, diff --git a/backend/src/services/organizationService.ts b/backend/src/services/organizationService.ts index e239dcd9a4..ad335a8be9 100644 --- a/backend/src/services/organizationService.ts +++ b/backend/src/services/organizationService.ts @@ -11,6 +11,7 @@ import { IUnmergePreviewResult, MemberRoleUnmergeStrategy, MergeActionState, + MergeActionStep, MergeActionType, OrganizationIdentityType, SyncMode, @@ -230,6 +231,15 @@ export default class OrganizationService extends LoggerBase { repoOptions, ) + await MergeActionsRepository.add( + MergeActionType.ORG, + organizationId, + secondaryOrganization.id, + this.options, + MergeActionStep.UNMERGE_STARTED, + MergeActionState.IN_PROGRESS, + ) + if (payload.mergeActionId) { const mergeAction = await MergeActionsRepository.findById( payload.mergeActionId, @@ -293,6 +303,16 @@ export default class OrganizationService extends LoggerBase { // trigger entity-merging-worker to move activities in the background await SequelizeRepository.commitTransaction(tx) + await MergeActionsRepository.setMergeAction( + MergeActionType.ORG, + organizationId, + secondaryOrganization.id, + this.options, + { + step: MergeActionStep.UNMERGE_SYNC_DONE, + } + ) + // responsible for moving organization's activities, syncing to opensearch afterwards, recalculating activity.organizationIds and notifying frontend via websockets await this.options.temporal.workflow.start('finishOrganizationUnmerging', { taskQueue: 'entity-merging', @@ -414,6 +434,7 @@ export default class OrganizationService extends LoggerBase { // not using transaction here on purpose, // so this change is visible until we finish this.options, + MergeActionStep.MERGE_STARTED, MergeActionState.IN_PROGRESS, backup, ) @@ -552,12 +573,14 @@ export default class OrganizationService extends LoggerBase { this.log.info({ originalId, toMergeId }, '[Merge Organizations] - Transaction commited! ') - await MergeActionsRepository.setState( + await MergeActionsRepository.setMergeAction( MergeActionType.ORG, originalId, toMergeId, - MergeActionState.FINISHING, this.options, + { + step: MergeActionStep.MERGE_SYNC_DONE, + } ) return { original, toMerge } @@ -615,12 +638,14 @@ export default class OrganizationService extends LoggerBase { toMergeId, }) - await MergeActionsRepository.setState( + await MergeActionsRepository.setMergeAction( MergeActionType.ORG, originalId, toMergeId, - MergeActionState.ERROR, this.options, + { + state: MergeActionState.ERROR, + } ) if (tx) { diff --git a/services/apps/entity_merging_worker/src/activities.ts b/services/apps/entity_merging_worker/src/activities.ts index cb454e41b4..d34f34797d 100644 --- a/services/apps/entity_merging_worker/src/activities.ts +++ b/services/apps/entity_merging_worker/src/activities.ts @@ -18,4 +18,4 @@ export { recalculateActivityAffiliationsOfOrganizationSynchronous, } from './activities/organizations' -export { setMergeActionState } from './activities/common' +export { setMergeAction } from './activities/common' diff --git a/services/apps/entity_merging_worker/src/activities/common.ts b/services/apps/entity_merging_worker/src/activities/common.ts index 701c06cad4..eee7ff225f 100644 --- a/services/apps/entity_merging_worker/src/activities/common.ts +++ b/services/apps/entity_merging_worker/src/activities/common.ts @@ -1,12 +1,12 @@ -import { MergeActionState } from '@crowd/types' +import { MergeActionState, MergeActionStep } from '@crowd/types' import { svc } from '../main' import { updateMergeActionState } from '@crowd/data-access-layer/src/old/apps/entity_merging_worker' -export async function setMergeActionState( +export async function setMergeAction( primaryId: string, secondaryId: string, tenantId: string, - state: MergeActionState, + data: { state?: MergeActionState; step?: MergeActionStep }, ): Promise { - await updateMergeActionState(svc.postgres.writer, primaryId, secondaryId, tenantId, state) + await updateMergeActionState(svc.postgres.writer, primaryId, secondaryId, tenantId, data) } diff --git a/services/apps/entity_merging_worker/src/workflows/all.ts b/services/apps/entity_merging_worker/src/workflows/all.ts index d3b3e34e5f..16572e7ee8 100644 --- a/services/apps/entity_merging_worker/src/workflows/all.ts +++ b/services/apps/entity_merging_worker/src/workflows/all.ts @@ -1,7 +1,7 @@ import { proxyActivities } from '@temporalio/workflow' import * as activities from '../activities' -import { IMemberIdentity, MergeActionState } from '@crowd/types' +import { IMemberIdentity, MergeActionState, MergeActionStep } from '@crowd/types' const { deleteMember, @@ -13,7 +13,7 @@ const { moveActivitiesWithIdentityToAnotherMember, recalculateActivityAffiliationsOfMemberAsync, recalculateActivityAffiliationsOfOrganizationSynchronous, - setMergeActionState, + setMergeAction, syncMember, syncOrganization, notifyFrontendMemberMergeSuccessful, @@ -31,12 +31,18 @@ export async function finishMemberMerging( tenantId: string, userId: string, ): Promise { + await setMergeAction(primaryId, secondaryId, tenantId, { + step: MergeActionStep.MERGE_ASYNC_STARTED, + }) await moveActivitiesBetweenMembers(primaryId, secondaryId, tenantId) await recalculateActivityAffiliationsOfMemberAsync(primaryId, tenantId) await syncMember(primaryId) await syncRemoveMember(secondaryId) await deleteMember(secondaryId) - await setMergeActionState(primaryId, secondaryId, tenantId, 'merged' as MergeActionState) + await setMergeAction(primaryId, secondaryId, tenantId, { + state: 'merged' as MergeActionState, + step: MergeActionStep.MERGE_DONE, + }) await notifyFrontendMemberMergeSuccessful( primaryId, secondaryId, @@ -56,12 +62,18 @@ export async function finishMemberUnmerging( tenantId: string, userId: string, ): Promise { + await setMergeAction(primaryId, secondaryId, tenantId, { + step: MergeActionStep.UNMERGE_ASYNC_STARTED, + }) await moveActivitiesWithIdentityToAnotherMember(primaryId, secondaryId, identities, tenantId) await syncMember(primaryId) await syncMember(secondaryId) await recalculateActivityAffiliationsOfMemberAsync(primaryId, tenantId) await recalculateActivityAffiliationsOfMemberAsync(secondaryId, tenantId) - await setMergeActionState(primaryId, secondaryId, tenantId, 'unmerged' as MergeActionState) + await setMergeAction(primaryId, secondaryId, tenantId, { + state: 'unmerged' as MergeActionState, + step: MergeActionStep.UNMERGE_DONE, + }) await notifyFrontendMemberUnmergeSuccessful( primaryId, secondaryId, @@ -80,13 +92,20 @@ export async function finishOrganizationMerging( tenantId: string, userId: string, ): Promise { + await setMergeAction(primaryId, secondaryId, tenantId, { + step: MergeActionStep.MERGE_ASYNC_STARTED, + }) + let movedSomething = true do { movedSomething = await moveActivitiesBetweenOrgs(primaryId, secondaryId, tenantId) } while (movedSomething) await deleteOrganization(secondaryId) - await setMergeActionState(primaryId, secondaryId, tenantId, 'merged' as MergeActionState) + await setMergeAction(primaryId, secondaryId, tenantId, { + state: 'merged' as MergeActionState, + step: MergeActionStep.MERGE_DONE, + }) await notifyFrontendOrganizationMergeSuccessful( primaryId, secondaryId, @@ -105,11 +124,17 @@ export async function finishOrganizationUnmerging( tenantId: string, userId: string, ): Promise { + await setMergeAction(primaryId, secondaryId, tenantId, { + step: MergeActionStep.UNMERGE_ASYNC_STARTED, + }) await recalculateActivityAffiliationsOfOrganizationSynchronous(primaryId, tenantId) await recalculateActivityAffiliationsOfOrganizationSynchronous(secondaryId, tenantId) await syncOrganization(primaryId, secondaryId) await syncOrganization(secondaryId, primaryId) - await setMergeActionState(primaryId, secondaryId, tenantId, 'unmerged' as MergeActionState) + await setMergeAction(primaryId, secondaryId, tenantId, { + state: 'unmerged' as MergeActionState, + step: MergeActionStep.UNMERGE_DONE, + }) await notifyFrontendOrganizationUnmergeSuccessful( primaryId, secondaryId, diff --git a/services/libs/data-access-layer/src/old/apps/entity_merging_worker/index.ts b/services/libs/data-access-layer/src/old/apps/entity_merging_worker/index.ts index 5486f769e4..eddf61eb24 100644 --- a/services/libs/data-access-layer/src/old/apps/entity_merging_worker/index.ts +++ b/services/libs/data-access-layer/src/old/apps/entity_merging_worker/index.ts @@ -1,5 +1,5 @@ import { DbStore } from '@crowd/database' -import { IActivityIdentity, IMemberIdentity, MergeActionState } from '@crowd/types' +import { IActivityIdentity, IMemberIdentity, MergeActionState, MergeActionStep } from '@crowd/types' import { ISegmentIds } from './types' export async function deleteMemberSegments(db: DbStore, memberId: string) { @@ -56,18 +56,30 @@ export async function updateMergeActionState( primaryId: string, secondaryId: string, tenantId: string, - state: MergeActionState, + data: { step?: MergeActionStep; state?: MergeActionState }, ) { + const setClauses = [] + const replacements = [primaryId, secondaryId, tenantId] + + if (data.step) { + setClauses.push(`step = $${replacements.length + 1}`) + replacements.push(data.step) + } + + if (data.state) { + setClauses.push(`state = $${replacements.length + 1}`) + replacements.push(data.state) + } + return db.connection().query( ` - UPDATE "mergeActions" - SET state = $4 - WHERE "tenantId" = $3 - AND "primaryId" = $1 - AND "secondaryId" = $2 - AND state != $4 - `, - [primaryId, secondaryId, tenantId, state], + UPDATE "mergeActions" + SET ${setClauses.join(', ')} + WHERE "primaryId" = $1 + AND "secondaryId" = $2 + AND "tenantId" = $3 + `, + replacements, ) } diff --git a/services/libs/types/src/enums/merging.ts b/services/libs/types/src/enums/merging.ts index 3a63e93113..9ca2460b16 100644 --- a/services/libs/types/src/enums/merging.ts +++ b/services/libs/types/src/enums/merging.ts @@ -12,6 +12,18 @@ export enum MergeActionState { ERROR = 'error', } +export enum MergeActionStep { + MERGE_STARTED = 'merge-started', + MERGE_SYNC_DONE = 'merge-sync-done', + MERGE_ASYNC_STARTED = 'merge-async-started', + MERGE_DONE = 'merge-done', + + UNMERGE_STARTED = 'unmerge-started', + UNMERGE_SYNC_DONE = 'unmerge-sync-done', + UNMERGE_ASYNC_STARTED = 'unmerge-async-started', + UNMERGE_DONE = 'unmerge-done', +} + export enum MemberRoleUnmergeStrategy { SAME_MEMBER = 'same-member', SAME_ORGANIZATION = 'same-organization', diff --git a/services/libs/types/src/merging.ts b/services/libs/types/src/merging.ts index 6a8ad0b7ba..3a974caf75 100644 --- a/services/libs/types/src/merging.ts +++ b/services/libs/types/src/merging.ts @@ -14,6 +14,7 @@ import { ITask, LLMSuggestionVerdictType, MergeActionState, + MergeActionStep, MergeActionType, } from '.' @@ -36,6 +37,7 @@ export interface IMergeAction { secondaryId: string createdAt: string updatedAt: string + step: MergeActionStep state: MergeActionState unmergeBackup: IUnmergeBackup } From 9870b37ba73120b992fc61bc848dc53ac2268d39 Mon Sep 17 00:00:00 2001 From: Yeganathan S Date: Fri, 19 Jul 2024 13:27:40 +0530 Subject: [PATCH 03/16] make prettier happi --- backend/src/bin/scripts/merge-similar-organizations.ts | 4 ++-- backend/src/database/repositories/mergeActionsRepository.ts | 6 +++--- backend/src/services/memberService.ts | 6 +++--- backend/src/services/organizationService.ts | 6 +++--- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/backend/src/bin/scripts/merge-similar-organizations.ts b/backend/src/bin/scripts/merge-similar-organizations.ts index 7fb2dbe746..3fe7e1f0e5 100644 --- a/backend/src/bin/scripts/merge-similar-organizations.ts +++ b/backend/src/bin/scripts/merge-similar-organizations.ts @@ -145,7 +145,7 @@ if (parameters.help || (!parameters.tenant && !parameters.allTenants)) { row.organizationId, row.toMergeId, userContext, - undefined + undefined, ) await orgService.mergeSync(row.organizationId, row.toMergeId, null) } catch (err) { @@ -157,7 +157,7 @@ if (parameters.help || (!parameters.tenant && !parameters.allTenants)) { userContext, { state: MergeActionState.ERROR, - } + }, ) } diff --git a/backend/src/database/repositories/mergeActionsRepository.ts b/backend/src/database/repositories/mergeActionsRepository.ts index 7cb57f37ab..f3e06f757f 100644 --- a/backend/src/database/repositories/mergeActionsRepository.ts +++ b/backend/src/database/repositories/mergeActionsRepository.ts @@ -59,9 +59,9 @@ class MergeActionsRepository { secondaryId: string, options: IRepositoryOptions, data: { - step?: MergeActionStep, - state?: MergeActionState, - } + step?: MergeActionStep + state?: MergeActionState + }, ) { const transaction = SequelizeRepository.getTransaction(options) const tenantId = options.currentTenant.id diff --git a/backend/src/services/memberService.ts b/backend/src/services/memberService.ts index e8076097b9..88948ce9df 100644 --- a/backend/src/services/memberService.ts +++ b/backend/src/services/memberService.ts @@ -706,7 +706,7 @@ export default class MemberService extends LoggerBase { secondaryMember.id, repoOptions, MergeActionStep.UNMERGE_STARTED, - MergeActionState.IN_PROGRESS + MergeActionState.IN_PROGRESS, ) // move affiliations @@ -842,7 +842,7 @@ export default class MemberService extends LoggerBase { repoOptions, { step: MergeActionStep.UNMERGE_SYNC_DONE, - } + }, ) // responsible for moving member's activities, syncing to opensearch afterwards, recalculating activity.organizationIds and notifying frontend via websockets @@ -1395,7 +1395,7 @@ export default class MemberService extends LoggerBase { this.options, { step: MergeActionStep.MERGE_SYNC_DONE, - } + }, ) await this.options.temporal.workflow.start('finishMemberMerging', { diff --git a/backend/src/services/organizationService.ts b/backend/src/services/organizationService.ts index ad335a8be9..d62b188b85 100644 --- a/backend/src/services/organizationService.ts +++ b/backend/src/services/organizationService.ts @@ -310,7 +310,7 @@ export default class OrganizationService extends LoggerBase { this.options, { step: MergeActionStep.UNMERGE_SYNC_DONE, - } + }, ) // responsible for moving organization's activities, syncing to opensearch afterwards, recalculating activity.organizationIds and notifying frontend via websockets @@ -580,7 +580,7 @@ export default class OrganizationService extends LoggerBase { this.options, { step: MergeActionStep.MERGE_SYNC_DONE, - } + }, ) return { original, toMerge } @@ -645,7 +645,7 @@ export default class OrganizationService extends LoggerBase { this.options, { state: MergeActionState.ERROR, - } + }, ) if (tx) { From 0a69bc9297fb30696f9f7ff4b8300be8cc986931 Mon Sep 17 00:00:00 2001 From: Yeganathan S Date: Fri, 19 Jul 2024 13:35:35 +0530 Subject: [PATCH 04/16] fix linter --- backend/src/bin/scripts/merge-similar-organizations.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/src/bin/scripts/merge-similar-organizations.ts b/backend/src/bin/scripts/merge-similar-organizations.ts index 3fe7e1f0e5..adb29ea6db 100644 --- a/backend/src/bin/scripts/merge-similar-organizations.ts +++ b/backend/src/bin/scripts/merge-similar-organizations.ts @@ -150,7 +150,7 @@ if (parameters.help || (!parameters.tenant && !parameters.allTenants)) { await orgService.mergeSync(row.organizationId, row.toMergeId, null) } catch (err) { console.log('Error merging organizations - continuing with the rest', err) - await MergeActionsRepository.update( + await MergeActionsRepository.setMergeAction( MergeActionType.ORG, row.organizationId, row.toMergeId, From 1f8056c2990234c394b0cfa906e04731dd8095dd Mon Sep 17 00:00:00 2001 From: Yeganathan S Date: Fri, 19 Jul 2024 19:09:34 +0530 Subject: [PATCH 05/16] rm setStep method --- .../repositories/mergeActionsRepository.ts | 36 ------------------- 1 file changed, 36 deletions(-) diff --git a/backend/src/database/repositories/mergeActionsRepository.ts b/backend/src/database/repositories/mergeActionsRepository.ts index f3e06f757f..a9922e6003 100644 --- a/backend/src/database/repositories/mergeActionsRepository.ts +++ b/backend/src/database/repositories/mergeActionsRepository.ts @@ -104,42 +104,6 @@ class MergeActionsRepository { return rowCount > 0 } - static async setStep( - type: MergeActionType, - primaryId: string, - secondaryId: string, - step: MergeActionStep, - options: IRepositoryOptions, - ) { - const transaction = SequelizeRepository.getTransaction(options) - const tenantId = options.currentTenant.id - - // eslint-disable-next-line @typescript-eslint/no-unused-vars - const [_, rowCount] = await options.database.sequelize.query( - ` - UPDATE "mergeActions" - SET step = :step - WHERE "tenantId" = :tenantId - AND type = :type - AND "primaryId" = :primaryId - AND "secondaryId" = :secondaryId - `, - { - replacements: { - tenantId, - type, - primaryId, - secondaryId, - step, - }, - type: QueryTypes.UPDATE, - transaction, - }, - ) - - return rowCount > 0 - } - static async findById(id: string, options: IRepositoryOptions): Promise { const transaction = SequelizeRepository.getTransaction(options) From 78c27388ee37a2aef5dc6ea69650cbfe357007ef Mon Sep 17 00:00:00 2001 From: Yeganathan S Date: Wed, 31 Jul 2024 17:47:09 +0530 Subject: [PATCH 06/16] add mergeAction endpoint --- backend/src/api/index.ts | 1 + backend/src/api/mergeAction/index.ts | 5 +++ .../src/api/mergeAction/mergeActionQuery.ts | 11 +++++ .../repositories/mergeActionsRepository.ts | 44 +++++++++++++++++++ backend/src/services/MergeActionsService.ts | 16 +++++++ 5 files changed, 77 insertions(+) create mode 100644 backend/src/api/mergeAction/index.ts create mode 100644 backend/src/api/mergeAction/mergeActionQuery.ts create mode 100644 backend/src/services/MergeActionsService.ts diff --git a/backend/src/api/index.ts b/backend/src/api/index.ts index d8640829d4..1ccedb52b1 100644 --- a/backend/src/api/index.ts +++ b/backend/src/api/index.ts @@ -242,6 +242,7 @@ setImmediate(async () => { require('./eventTracking').default(routes) require('./customViews').default(routes) require('./dashboard').default(routes) + require('./mergeAction').default(routes) // Loads the Tenant if the :tenantId param is passed routes.param('tenantId', tenantMiddleware) routes.param('tenantId', segmentMiddleware) diff --git a/backend/src/api/mergeAction/index.ts b/backend/src/api/mergeAction/index.ts new file mode 100644 index 0000000000..36f43838b2 --- /dev/null +++ b/backend/src/api/mergeAction/index.ts @@ -0,0 +1,5 @@ +import { safeWrap } from '../../middlewares/errorMiddleware' + +export default (app) => { + app.get(`/tenant/:tenantId/mergeActions`, safeWrap(require('./mergeActionQuery').default)) +} diff --git a/backend/src/api/mergeAction/mergeActionQuery.ts b/backend/src/api/mergeAction/mergeActionQuery.ts new file mode 100644 index 0000000000..bf91ed8a99 --- /dev/null +++ b/backend/src/api/mergeAction/mergeActionQuery.ts @@ -0,0 +1,11 @@ +import MergeActionsService from '@/services/MergeActionsService' +import Permissions from '../../security/permissions' +import PermissionChecker from '../../services/user/permissionChecker' + +export default async (req, res) => { + new PermissionChecker(req).validateHas(Permissions.values.noteRead) + + const payload = await new MergeActionsService(req).query(req.body) + + await req.responseHandler.success(req, res, payload) +} diff --git a/backend/src/database/repositories/mergeActionsRepository.ts b/backend/src/database/repositories/mergeActionsRepository.ts index a9922e6003..ca2eeeabdd 100644 --- a/backend/src/database/repositories/mergeActionsRepository.ts +++ b/backend/src/database/repositories/mergeActionsRepository.ts @@ -151,6 +151,50 @@ class MergeActionsRepository { return null } + static async query( + { limit = 20, offset = 0, filter }, + options: IRepositoryOptions, + ): Promise<{ rows: IMergeAction[]; count: number }> { + const transaction = SequelizeRepository.getTransaction(options) + + let where = '' + + if (filter?.entityId) { + where += ` AND (ma."primaryId" = :entityId OR ma."secondaryId" = :entityId)` + } + + if (filter?.type) { + where += ` AND ma.type = :type` + } + + const records = await options.database.sequelize.query( + ` + SELECT + ma."primaryId", + ma."secondaryId", + ma."state", + ma."step", + FROM "mergeActions" ma + WHERE 1 = 1 + ${where} + LIMIT :limit + OFFSET :offset; + `, + { + replacements: { + limit, + offset, + type: filter?.type, + entityId: filter?.entityId, + }, + type: QueryTypes.SELECT, + transaction, + }, + ) + + return records + } + static async findMergeBackup( primaryMemberId: string, type: MergeActionType, diff --git a/backend/src/services/MergeActionsService.ts b/backend/src/services/MergeActionsService.ts new file mode 100644 index 0000000000..f0c45e60e9 --- /dev/null +++ b/backend/src/services/MergeActionsService.ts @@ -0,0 +1,16 @@ +import { LoggerBase } from '@crowd/logging' +import { IServiceOptions } from './IServiceOptions' +import { MergeActionsRepository } from '@/database/repositories/mergeActionsRepository' + +export default class MergeActionsService extends LoggerBase { + options: IServiceOptions + + constructor(options: IServiceOptions) { + super(options.log) + this.options = options + } + + async query(args) { + return MergeActionsRepository.query(args, this.options) + } +} From a6f133ba87188aad0380fdc704e211a1e013b784 Mon Sep 17 00:00:00 2001 From: Yeganathan S Date: Wed, 31 Jul 2024 21:11:31 +0530 Subject: [PATCH 07/16] endpoint response and QA --- .../repositories/mergeActionsRepository.ts | 9 +++++-- backend/src/services/MergeActionsService.ts | 24 ++++++++++++++++++- 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/backend/src/database/repositories/mergeActionsRepository.ts b/backend/src/database/repositories/mergeActionsRepository.ts index ca2eeeabdd..f8bb24aef8 100644 --- a/backend/src/database/repositories/mergeActionsRepository.ts +++ b/backend/src/database/repositories/mergeActionsRepository.ts @@ -154,7 +154,7 @@ class MergeActionsRepository { static async query( { limit = 20, offset = 0, filter }, options: IRepositoryOptions, - ): Promise<{ rows: IMergeAction[]; count: number }> { + ): Promise { const transaction = SequelizeRepository.getTransaction(options) let where = '' @@ -167,13 +167,17 @@ class MergeActionsRepository { where += ` AND ma.type = :type` } + if (filter?.state) { + where += ` AND ma.state IN (:state)` + } + const records = await options.database.sequelize.query( ` SELECT ma."primaryId", ma."secondaryId", ma."state", - ma."step", + ma.step FROM "mergeActions" ma WHERE 1 = 1 ${where} @@ -186,6 +190,7 @@ class MergeActionsRepository { offset, type: filter?.type, entityId: filter?.entityId, + state: filter?.state, }, type: QueryTypes.SELECT, transaction, diff --git a/backend/src/services/MergeActionsService.ts b/backend/src/services/MergeActionsService.ts index f0c45e60e9..18c0da90c1 100644 --- a/backend/src/services/MergeActionsService.ts +++ b/backend/src/services/MergeActionsService.ts @@ -11,6 +11,28 @@ export default class MergeActionsService extends LoggerBase { } async query(args) { - return MergeActionsRepository.query(args, this.options) + // filter merge actions that are in progress or error + args.filter = { + ...args.filter, + state: ['in-progress', 'error'], + } + + const results = await MergeActionsRepository.query(args, this.options) + + return results.map(result => ({ + primaryId: result.primaryId, + secondaryId: result.secondaryId, + state: result.state, + // derive operation type from step and if step is null, default to merge + 'operation-type': result.step ? MergeActionsService.getOperationType(result.step) : 'merge', + })) + } + + static getOperationType(step) { + if (step.startsWith('merge')) { + return 'merge' + } + + return 'unmerge' } } From 6e6fa8d5e11ba3333b0b1b34164ccd6884981f42 Mon Sep 17 00:00:00 2001 From: Yeganathan S Date: Wed, 31 Jul 2024 21:49:49 +0530 Subject: [PATCH 08/16] make linter happy --- backend/src/services/MergeActionsService.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/backend/src/services/MergeActionsService.ts b/backend/src/services/MergeActionsService.ts index 18c0da90c1..e9f3876340 100644 --- a/backend/src/services/MergeActionsService.ts +++ b/backend/src/services/MergeActionsService.ts @@ -19,7 +19,7 @@ export default class MergeActionsService extends LoggerBase { const results = await MergeActionsRepository.query(args, this.options) - return results.map(result => ({ + return results.map((result) => ({ primaryId: result.primaryId, secondaryId: result.secondaryId, state: result.state, @@ -31,7 +31,7 @@ export default class MergeActionsService extends LoggerBase { static getOperationType(step) { if (step.startsWith('merge')) { return 'merge' - } + } return 'unmerge' } From c61f6de71f43b17972499316c31dbde52a510c0a Mon Sep 17 00:00:00 2001 From: Gasper Grom Date: Thu, 1 Aug 2024 11:09:39 +0200 Subject: [PATCH 09/16] Frontend display for syncing activities --- .../contributor-details-activities.vue | 13 +++++++ .../contributor-details-community.vue | 11 +++++- .../shared/contributor-syncing-activities.vue | 36 +++++++++++++++++++ .../pages/contributor-details.page.vue | 4 ++- .../contributor/store/contributor.actions.ts | 17 +++++++++ .../modules/contributor/types/Contributor.ts | 3 +- .../merge/services/merge-actions.service.ts | 23 ++++++++++++ .../modules/merge/types/MemberActions.ts | 12 +++++++ frontend/src/ui-kit/index.scss | 1 + .../src/ui-kit/loading/Loading.stories.ts | 34 ++++++++++++++++++ frontend/src/ui-kit/loading/Loading.vue | 29 +++++++++++++++ frontend/src/ui-kit/loading/loading.scss | 36 +++++++++++++++++++ 12 files changed, 216 insertions(+), 3 deletions(-) create mode 100644 frontend/src/modules/contributor/components/shared/contributor-syncing-activities.vue create mode 100644 frontend/src/shared/modules/merge/services/merge-actions.service.ts create mode 100644 frontend/src/shared/modules/merge/types/MemberActions.ts create mode 100644 frontend/src/ui-kit/loading/Loading.stories.ts create mode 100644 frontend/src/ui-kit/loading/Loading.vue create mode 100644 frontend/src/ui-kit/loading/loading.scss diff --git a/frontend/src/modules/contributor/components/details/contributor-details-activities.vue b/frontend/src/modules/contributor/components/details/contributor-details-activities.vue index 4401cb601f..ede21994c3 100644 --- a/frontend/src/modules/contributor/components/details/contributor-details-activities.vue +++ b/frontend/src/modules/contributor/components/details/contributor-details-activities.vue @@ -1,5 +1,16 @@