From 9f929f02906aa3aa8648e86a6ac77d13eb0c42d5 Mon Sep 17 00:00:00 2001 From: Andrey Sobolev Date: Wed, 27 Mar 2024 13:46:34 +0700 Subject: [PATCH] UBERF-6194: CLI for rename account (#5067) Signed-off-by: Andrey Sobolev --- dev/tool/src/__start.ts | 2 +- dev/tool/src/index.ts | 35 ++++++- dev/tool/src/renameAccount.ts | 91 +++++++++++++++++++ .../src/components/ChannelEditor.svelte | 37 +++++++- .../src/components/ChannelsDropdown.svelte | 7 +- .../view-resources/src/components/Menu.svelte | 6 +- server/account/src/index.ts | 9 +- 7 files changed, 175 insertions(+), 12 deletions(-) create mode 100644 dev/tool/src/renameAccount.ts diff --git a/dev/tool/src/__start.ts b/dev/tool/src/__start.ts index 4195073509..dc09df83f7 100644 --- a/dev/tool/src/__start.ts +++ b/dev/tool/src/__start.ts @@ -82,4 +82,4 @@ function prepareTools (): { console.log(`tools git_version: ${process.env.GIT_REVISION ?? ''} model_version: ${process.env.MODEL_VERSION ?? ''}`) -devTool(prepareTools, '') +devTool(prepareTools, process.env.PRODUCT_ID ?? '') diff --git a/dev/tool/src/index.ts b/dev/tool/src/index.ts index 83ba420f95..616f59cbac 100644 --- a/dev/tool/src/index.ts +++ b/dev/tool/src/index.ts @@ -79,6 +79,7 @@ import { checkOrphanWorkspaces } from './cleanOrphan' import { changeConfiguration } from './configuration' import { fixMixinForeignAttributes, showMixinForeignAttributes } from './mixin' import { openAIConfig } from './openai' +import { fixAccountEmails, renameAccount } from './renameAccount' /** * @public @@ -162,6 +163,28 @@ export function devTool ( }) }) + program + .command('reset-email ') + .description('rename account in accounts and all workspaces') + .action(async (email: string, newEmail: string, cmd) => { + const { mongodbUri } = prepareTools() + await withDatabase(mongodbUri, async (db) => { + console.log(`update account ${email} to ${newEmail}`) + await renameAccount(toolCtx, db, productId, transactorUrl, email, newEmail) + }) + }) + + program + .command('fix-email ') + .description('fix email in all workspaces to be proper one') + .action(async (email: string, newEmail: string, cmd) => { + const { mongodbUri } = prepareTools() + await withDatabase(mongodbUri, async (db) => { + console.log(`update account ${email} to ${newEmail}`) + await fixAccountEmails(toolCtx, db, productId, transactorUrl, email, newEmail) + }) + }) + program .command('assign-workspace ') .description('assign workspace') @@ -433,8 +456,16 @@ export function devTool ( .action(async () => { const { mongodbUri } = prepareTools() await withDatabase(mongodbUri, async (db) => { - const accountsJSON = JSON.stringify(await listAccounts(db), null, 2) - console.info(accountsJSON) + const workspaces = await listWorkspacesPure(db, productId) + const accounts = await listAccounts(db) + for (const a of accounts) { + const wss = a.workspaces.map((it) => it.toString()) + console.info( + a.email, + a.confirmed, + workspaces.filter((it) => wss.includes(it._id.toString())).map((it) => it.workspaceUrl ?? it.workspace) + ) + } }) }) diff --git a/dev/tool/src/renameAccount.ts b/dev/tool/src/renameAccount.ts new file mode 100644 index 0000000000..24b5df535d --- /dev/null +++ b/dev/tool/src/renameAccount.ts @@ -0,0 +1,91 @@ +import { type Account, changeEmail, getAccount, listWorkspacesPure, type Workspace } from '@hcengineering/account' +import core, { type MeasureContext, TxOperations } from '@hcengineering/core' +import contact from '@hcengineering/model-contact' +import { connect } from '@hcengineering/server-tool' +import { type Db } from 'mongodb' + +export async function renameAccount ( + ctx: MeasureContext, + db: Db, + productId: string, + transactorUrl: string, + oldEmail: string, + newEmail: string +): Promise { + const account = await getAccount(db, oldEmail) + if (account == null) { + throw new Error("Account does'n exists") + } + + const newAccount = await getAccount(db, newEmail) + if (newAccount != null) { + throw new Error('New Account email already exists:' + newAccount?.email + ' ' + newAccount?._id?.toString()) + } + + await changeEmail(ctx, db, account, newEmail) + + await fixWorkspaceEmails(account, db, productId, transactorUrl, oldEmail, newEmail) +} + +export async function fixAccountEmails ( + ctx: MeasureContext, + db: Db, + productId: string, + transactorUrl: string, + oldEmail: string, + newEmail: string +): Promise { + const account = await getAccount(db, newEmail) + if (account == null) { + throw new Error("Account does'n exists") + } + + await fixWorkspaceEmails(account, db, productId, transactorUrl, oldEmail, newEmail) +} +async function fixWorkspaceEmails ( + account: Account, + db: Db, + productId: string, + transactorUrl: string, + oldEmail: string, + newEmail: string +): Promise { + const accountWorkspaces = account.workspaces.map((it) => it.toString()) + // We need to update all workspaces + const workspaces = await listWorkspacesPure(db, productId) + for (const ws of workspaces) { + if (!accountWorkspaces.includes(ws._id.toString())) { + continue + } + console.log('checking workspace', ws.workspaceName, ws.workspace) + + // Let's connect and update account information. + await fixEmailInWorkspace(transactorUrl, ws, oldEmail, newEmail) + } +} + +async function fixEmailInWorkspace ( + transactorUrl: string, + ws: Workspace, + oldEmail: string, + newEmail: string +): Promise { + const connection = await connect(transactorUrl, { name: ws.workspace, productId: ws.productId }, undefined, { + mode: 'backup', + model: 'upgrade', // Required for force all clients reload after operation will be complete. + admin: 'true' + }) + try { + const personAccount = await connection.findOne(contact.class.PersonAccount, { email: oldEmail }) + + if (personAccount !== undefined) { + console.log('update account in ', ws.workspace) + const ops = new TxOperations(connection, core.account.ConfigUser) + await ops.update(personAccount, { email: newEmail }) + } + } catch (err: any) { + console.error(err) + } finally { + await connection.close() + } +} diff --git a/plugins/contact-resources/src/components/ChannelEditor.svelte b/plugins/contact-resources/src/components/ChannelEditor.svelte index fa7b0e115c..5c2cd074d2 100644 --- a/plugins/contact-resources/src/components/ChannelEditor.svelte +++ b/plugins/contact-resources/src/components/ChannelEditor.svelte @@ -13,29 +13,36 @@ // limitations under the License. -->