Skip to content

Commit 414abe1

Browse files
authored
chore: add script to fix-members-activities-after-unaffilation (#3247)
1 parent 8e7834a commit 414abe1

3 files changed

Lines changed: 143 additions & 1 deletion

File tree

backend/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,8 @@
3434
"script:fix-missing-org-displayName": "SERVICE=script TS_NODE_TRANSPILE_ONLY=true tsx src/bin/scripts/fix-missing-org-displayName.ts",
3535
"script:syncActivities": "SERVICE=script TS_NODE_TRANSPILE_ONLY=true tsx src/bin/scripts/syncActivities.ts",
3636
"script:refreshGithubRepoSettings": "SERVICE=script TS_NODE_TRANSPILE_ONLY=true tsx src/bin/scripts/refresh-github-repo-settings.ts",
37-
"script:fix-duplicate-members": "SERVICE=script TS_NODE_TRANSPILE_ONLY=true tsx src/bin/scripts/fix-duplicate-members.ts"
37+
"script:fix-duplicate-members": "SERVICE=script TS_NODE_TRANSPILE_ONLY=true tsx src/bin/scripts/fix-duplicate-members.ts",
38+
"script:fix-members-activities-after-unaffilation": "SERVICE=script TS_NODE_TRANSPILE_ONLY=true tsx src/bin/scripts/fix-members-activities-after-unaffilation.ts"
3839
},
3940
"lint-staged": {
4041
"**/*.ts": [
Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
import commandLineArgs from 'command-line-args'
2+
import { randomUUID } from 'crypto'
3+
4+
import { getDbConnection } from '@crowd/data-access-layer/src/database'
5+
import { getServiceLogger } from '@crowd/logging'
6+
import { getTemporalClient } from '@crowd/temporal'
7+
8+
import { DB_CONFIG, TEMPORAL_CONFIG } from '@/conf'
9+
10+
const log = getServiceLogger()
11+
12+
const options = [
13+
{
14+
name: 'organizationId',
15+
alias: 'o',
16+
typeLabel: '{underline organizationId}',
17+
type: String,
18+
description: 'The organization ID to process members for.',
19+
},
20+
{
21+
name: 'dryRun',
22+
alias: 'd',
23+
type: Boolean,
24+
description: 'Run in dry-run mode (show what would be processed).',
25+
},
26+
{
27+
name: 'help',
28+
alias: 'h',
29+
type: Boolean,
30+
description: 'Print this usage guide.',
31+
},
32+
]
33+
34+
const parameters = commandLineArgs(options)
35+
36+
setImmediate(async () => {
37+
const organizationId = parameters.organizationId
38+
const dryRun = parameters.dryRun ?? false
39+
40+
log.info({ organizationId, dryRun }, 'Running script with the following parameters!')
41+
42+
const db = await getDbConnection({
43+
host: DB_CONFIG.readHost,
44+
port: DB_CONFIG.port,
45+
database: DB_CONFIG.database,
46+
user: DB_CONFIG.username,
47+
password: DB_CONFIG.password,
48+
})
49+
const temporal = await getTemporalClient(TEMPORAL_CONFIG)
50+
51+
try {
52+
const memberIds = await db.any(
53+
`
54+
SELECT DISTINCT ar."memberId" AS id
55+
FROM "activityRelations" ar
56+
JOIN "memberOrganizations" mo
57+
ON ar."memberId" = mo."memberId"
58+
AND ar."organizationId" = mo."organizationId"
59+
LEFT JOIN "memberOrganizationAffiliationOverrides" moao
60+
ON mo."id" = moao."memberOrganizationId"
61+
WHERE ar."organizationId" = $1
62+
AND (
63+
(
64+
mo."deletedAt" IS NOT NULL
65+
AND NOT EXISTS (
66+
SELECT 1
67+
FROM "memberOrganizations" mo2
68+
WHERE mo2."memberId" = mo."memberId"
69+
AND mo2."organizationId" = mo."organizationId"
70+
AND mo2."deletedAt" IS NULL
71+
)
72+
)
73+
OR (
74+
mo."deletedAt" IS NULL
75+
AND moao."allowAffiliation" = false
76+
)
77+
);
78+
`,
79+
[organizationId],
80+
)
81+
82+
log.info(`Found ${memberIds.length} members to process`)
83+
84+
if (memberIds.length === 0) {
85+
log.info('No members found. Implement the query to get actual memberIds.')
86+
return
87+
}
88+
89+
if (dryRun) {
90+
log.info('DRY RUN - Would update affiliations for the following members:')
91+
memberIds.forEach((member: { id: string }) => {
92+
log.info(` - Member ID: ${member.id}`)
93+
})
94+
return
95+
}
96+
97+
let processedCount = 0
98+
for (const member of memberIds) {
99+
try {
100+
log.info(`Processing member: ${member.id}`)
101+
102+
const uuid = randomUUID()
103+
104+
await temporal.workflow.start('memberUpdate', {
105+
taskQueue: 'profiles',
106+
workflowId: `member-update-fix-unaffiliation/${organizationId}/${member.id}/${uuid}`,
107+
retry: {
108+
maximumAttempts: 10,
109+
},
110+
args: [
111+
{
112+
member: {
113+
id: member.id,
114+
},
115+
memberOrganizationIds: [organizationId],
116+
syncToOpensearch: false,
117+
},
118+
],
119+
searchAttributes: {
120+
TenantId: ['875c38bd-2b1b-4e91-ad07-0cfbabb4c49f'], // default tenantId
121+
},
122+
})
123+
124+
processedCount++
125+
log.info(`Successfully triggered workflow for member: ${member.id}`)
126+
} catch (error) {
127+
log.error(`Failed to process member ${member.id}:`, error)
128+
}
129+
}
130+
131+
log.info(`Script completed. Processed ${processedCount}/${memberIds.length} members.`)
132+
} catch (error) {
133+
log.error('Script failed:', error)
134+
throw error
135+
}
136+
137+
process.exit(0)
138+
})

services/libs/data-access-layer/src/old/apps/profiles_worker/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -349,8 +349,11 @@ export async function runMemberAffiliationsUpdate(
349349
qx,
350350
memberId,
351351
)
352+
logger.info(`orgCase for member ${memberId}: ${orgCases}`)
353+
logger.info(`fullCase for member ${memberId}: ${fullCase}`)
352354

353355
const { minTimestamp, maxTimestamp } = await getMemberActivityTimestampRanges(qDb, memberId)
356+
logger.info(`MemberActivityTimestampRanges ${minTimestamp} ${maxTimestamp}`)
354357

355358
const { processed, duration } = await updateActivities(
356359
qDb,

0 commit comments

Comments
 (0)