2
0

🧐 Add updateUserEmail script

This commit is contained in:
Baptiste Arnaud
2024-01-12 10:45:48 +01:00
parent 69b113fc85
commit 409aeb12d3
5 changed files with 170 additions and 144 deletions

View File

@ -1,80 +1,9 @@
import { PrismaClient } from '@typebot.io/prisma' import { destroyUser } from './helpers/destroyUser'
import * as p from '@clack/prompts'
import { promptAndSetEnvironment } from './utils' import { promptAndSetEnvironment } from './utils'
const destroyUser = async () => { const runDestroyUser = async () => {
await promptAndSetEnvironment('production') await promptAndSetEnvironment('production')
return destroyUser()
const prisma = new PrismaClient({
log: [{ emit: 'event', level: 'query' }, 'info', 'warn', 'error'],
})
prisma.$on('query', (e) => {
console.log(e.query)
console.log(e.params)
console.log(e.duration, 'ms')
})
const email = (await p.text({
message: 'User email?',
})) as string
if (!email || typeof email !== 'string') {
console.log('No email provided')
return
}
const workspaces = await prisma.workspace.findMany({
where: {
members: { every: { user: { email } } },
},
include: {
members: { select: { user: { select: { email: true } }, role: true } },
typebots: {
select: {
results: {
select: { id: true },
},
},
},
},
})
console.log(`Found ${workspaces.length} workspaces`)
const proceed = await p.confirm({ message: 'Proceed?' })
if (!proceed || typeof proceed !== 'boolean') {
console.log('Aborting')
return
}
for (const workspace of workspaces) {
const hasResults = workspace.typebots.some((t) => t.results.length > 0)
if (hasResults) {
console.log(
`Workspace ${workspace.name} has results. Deleting results first...`,
workspace.typebots.filter((t) => t.results.length > 0)
)
console.log(JSON.stringify({ members: workspace.members }, null, 2))
const proceed = await p.confirm({ message: 'Proceed?' })
if (!proceed || typeof proceed !== 'boolean') {
console.log('Aborting')
return
}
}
for (const typebot of workspace.typebots.filter(
(t) => t.results.length > 0
)) {
for (const result of typebot.results) {
await prisma.result.deleteMany({ where: { id: result.id } })
}
}
await prisma.workspace.delete({ where: { id: workspace.id } })
}
const user = await prisma.user.delete({ where: { email } })
console.log(`Deleted user ${JSON.stringify(user, null, 2)}`)
} }
destroyUser() runDestroyUser()

View File

@ -0,0 +1,98 @@
import { isCancel, text, confirm } from '@clack/prompts'
import { Plan, PrismaClient } from '@typebot.io/prisma'
import { writeFileSync } from 'fs'
export const destroyUser = async (userEmail?: string) => {
const prisma = new PrismaClient()
const email =
userEmail ??
(await text({
message: 'User email?',
}))
if (!email || isCancel(email)) {
console.log('No email provided')
return
}
const workspaces = await prisma.workspace.findMany({
where: {
members: { every: { user: { email } } },
},
include: {
members: { select: { user: { select: { email: true } }, role: true } },
typebots: {
select: {
results: {
select: { id: true },
},
},
},
},
})
console.log(`Found ${workspaces.length} workspaces`)
if (workspaces.some((w) => w.plan !== Plan.FREE)) {
console.log(
`Some workspaces have a plan other than FREE. Something is wrong. Logging and exiting...`
)
writeFileSync(
'logs/workspaces-issue.json',
JSON.stringify(workspaces, null, 2)
)
return
}
if (
workspaces.some((w) =>
w.members.some((m) => m.user.email && m.user.email !== email)
)
) {
console.log(
`Some workspaces have other members. Something is wrong. Logging and exiting...`
)
writeFileSync(
'logs/workspaces-issue.json',
JSON.stringify(workspaces, null, 2)
)
return
}
console.log('All workspaces have a FREE plan')
const proceed = await confirm({ message: 'Proceed?' })
if (!proceed || typeof proceed !== 'boolean') {
console.log('Aborting')
return
}
for (const workspace of workspaces) {
const hasResults = workspace.typebots.some((t) => t.results.length > 0)
if (hasResults) {
console.log(
`Workspace ${workspace.name} has results. Deleting results first...`,
workspace.typebots.filter((t) => t.results.length > 0)
)
console.log(JSON.stringify({ members: workspace.members }, null, 2))
const proceed = await confirm({ message: 'Proceed?' })
if (!proceed || typeof proceed !== 'boolean') {
console.log('Aborting')
return
}
}
for (const typebot of workspace.typebots.filter(
(t) => t.results.length > 0
)) {
for (const result of typebot.results) {
await prisma.result.deleteMany({ where: { id: result.id } })
}
}
await prisma.workspace.delete({ where: { id: workspace.id } })
}
const user = await prisma.user.delete({ where: { email } })
console.log(`Deleted user ${JSON.stringify(user, null, 2)}`)
}

View File

@ -1,24 +1,20 @@
import { PrismaClient } from '@typebot.io/prisma' import { PrismaClient } from '@typebot.io/prisma'
import { promptAndSetEnvironment } from './utils' import { promptAndSetEnvironment } from './utils'
import prompts from 'prompts' import { isCancel, text } from '@clack/prompts'
import { isEmpty } from '@typebot.io/lib'
const inspectUser = async () => { const inspectUser = async () => {
await promptAndSetEnvironment('production') await promptAndSetEnvironment('production')
const response = await prompts({ const email = await text({
type: 'text',
name: 'email',
message: 'User email', message: 'User email',
}) })
if (isEmpty(response.email)) process.exit() if (!email || isCancel(email)) process.exit()
const prisma = new PrismaClient({
log: [{ emit: 'event', level: 'query' }, 'info', 'warn', 'error'], const prisma = new PrismaClient()
})
const user = await prisma.user.findFirst({ const user = await prisma.user.findFirst({
where: { where: {
email: response.email, email,
}, },
select: { select: {
name: true, name: true,
@ -37,7 +33,7 @@ const inspectUser = async () => {
plan: true, plan: true,
members: { members: {
where: { where: {
user: { email: { not: response.email } }, user: { email: { not: email } },
}, },
}, },
additionalStorageIndex: true, additionalStorageIndex: true,
@ -67,63 +63,7 @@ const inspectUser = async () => {
}, },
}) })
if (!user) { console.log(JSON.stringify(user, null, 2))
console.log('User not found')
process.exit()
}
console.log('Name:', user.name)
console.log('Last activity:', user.lastActivityAt.toLocaleDateString())
console.log('Company:', user.company)
console.log('Onboarding categories:', user.onboardingCategories)
console.log('Total workspaces:', user.workspaces.length)
console.log('Workspaces:')
for (const workspace of user.workspaces) {
console.log(' - ID:', workspace.workspace.id)
console.log(' Name:', workspace.workspace.name)
console.log(' Plan:', workspace.workspace.plan)
console.log(' Members:', workspace.workspace.members.length + 1)
console.log(
' Additional storage:',
workspace.workspace.additionalStorageIndex
)
console.log(' Typebots:', workspace.workspace.typebots.length)
for (const typebot of workspace.workspace.typebots) {
console.log(' - Name:', typebot.name)
console.log(' Created:', typebot.createdAt.toLocaleDateString())
console.log(
' Last updated:',
typebot.updatedAt.toLocaleDateString()
)
console.log(' Risk level:', typebot.riskLevel)
console.log(
' Public ID:',
typebot.publishedTypebot?.typebot.publicId
)
console.log(
' URL:',
`https://app.typebot.io/typebots/${typebot.id}/edit`
)
if (!typebot.publishedTypebot) continue
const totalTraffic = await prisma.result.count({
where: {
typebotId: typebot.id,
isArchived: false,
},
select: {
_all: true,
hasStarted: true,
},
})
console.log(' Total traffic:', totalTraffic._all)
console.log(' Started:', totalTraffic.hasStarted)
}
}
} }
inspectUser() inspectUser()

View File

@ -26,7 +26,8 @@
"inspectTypebot": "tsx inspectTypebot.ts", "inspectTypebot": "tsx inspectTypebot.ts",
"inspectWorkspace": "tsx inspectWorkspace.ts", "inspectWorkspace": "tsx inspectWorkspace.ts",
"getCoupon": "tsx getCoupon.ts", "getCoupon": "tsx getCoupon.ts",
"exportResults": "tsx exportResults.ts" "exportResults": "tsx exportResults.ts",
"updateUserEmail": "tsx updateUserEmail.ts"
}, },
"devDependencies": { "devDependencies": {
"@typebot.io/emails": "workspace:*", "@typebot.io/emails": "workspace:*",

View File

@ -0,0 +1,58 @@
import { PrismaClient } from '@typebot.io/prisma'
import { promptAndSetEnvironment } from './utils'
import { text, isCancel, confirm } from '@clack/prompts'
import { destroyUser } from './helpers/destroyUser'
const updateUserEmail = async () => {
await promptAndSetEnvironment('production')
const prisma = new PrismaClient()
const currentUserEmail = await text({
message: 'Current email?',
})
const newEmail = await text({
message: 'New email?',
})
if (
!currentUserEmail ||
!newEmail ||
isCancel(currentUserEmail) ||
isCancel(newEmail)
)
throw new Error('Invalid emails')
const existingUserWithNewEmail = await prisma.user.findUnique({
where: {
email: newEmail,
},
})
if (existingUserWithNewEmail) {
console.log(`User with email ${newEmail} already exists`)
console.log(JSON.stringify(existingUserWithNewEmail, null, 2))
const isDestroying = await confirm({
message: 'Would you like to destroy it and update the current user?',
})
if (!isDestroying || isCancel(isDestroying)) return
await destroyUser(newEmail)
}
const user = await prisma.user.update({
where: {
email: currentUserEmail,
},
data: {
email: newEmail,
},
})
console.log(JSON.stringify(user, null, 2))
}
updateUserEmail()