2
0
Files
bot/packages/scripts/cleanDatabase.ts
Baptiste Arnaud 797751b418 (billing) Automatic usage-based billing (#924)
BREAKING CHANGE: Stripe environment variables simplified. Check out the
new configs to adapt your existing system.

Closes #906





<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
### Summary by CodeRabbit

**New Features:**
- Introduced a usage-based billing system, providing more flexibility
and options for users.
- Integrated with Stripe for a smoother and more secure payment process.
- Enhanced the user interface with improvements to the billing,
workspace, and pricing pages for a more intuitive experience.

**Improvements:**
- Simplified the billing logic, removing additional chats and yearly
billing for a more streamlined user experience.
- Updated email notifications to keep users informed about their usage
and limits.
- Improved pricing and currency formatting for better clarity and
understanding.

**Testing:**
- Updated tests and specifications to ensure the reliability of new
features and improvements.

**Note:** These changes aim to provide a more flexible and user-friendly
billing system, with clearer pricing and improved notifications. Users
should find the new system more intuitive and easier to navigate.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2023-10-17 08:03:30 +02:00

230 lines
5.9 KiB
TypeScript

import { PrismaClient } from '@typebot.io/prisma'
import { promptAndSetEnvironment } from './utils'
import { archiveResults } from '@typebot.io/lib/api/helpers/archiveResults'
import { Typebot } from '@typebot.io/schemas'
const prisma = new PrismaClient()
export const cleanDatabase = async () => {
await promptAndSetEnvironment('production')
console.log('Starting database cleanup...')
await deleteOldChatSessions()
await deleteExpiredAppSessions()
await deleteExpiredVerificationTokens()
const isFirstOfMonth = new Date().getDate() === 1
if (isFirstOfMonth) {
await deleteArchivedResults()
await deleteArchivedTypebots()
await resetBillingProps()
}
console.log('Database cleaned!')
}
const deleteArchivedTypebots = async () => {
const lastDayTwoMonthsAgo = new Date()
lastDayTwoMonthsAgo.setMonth(lastDayTwoMonthsAgo.getMonth() - 1)
lastDayTwoMonthsAgo.setDate(0)
const typebots = await prisma.typebot.findMany({
where: {
updatedAt: {
lte: lastDayTwoMonthsAgo,
},
isArchived: true,
},
select: { id: true },
})
console.log(`Deleting ${typebots.length} archived typebots...`)
const chunkSize = 1000
for (let i = 0; i < typebots.length; i += chunkSize) {
const chunk = typebots.slice(i, i + chunkSize)
await deleteResultsFromArchivedTypebotsIfAny(chunk)
await prisma.typebot.deleteMany({
where: {
id: {
in: chunk.map((typebot) => typebot.id),
},
},
})
}
console.log('Done!')
}
const deleteArchivedResults = async () => {
const lastDayTwoMonthsAgo = new Date()
lastDayTwoMonthsAgo.setMonth(lastDayTwoMonthsAgo.getMonth() - 1)
lastDayTwoMonthsAgo.setDate(0)
let totalResults
do {
const results = await prisma.result.findMany({
where: {
createdAt: {
lte: lastDayTwoMonthsAgo,
},
isArchived: true,
},
select: { id: true },
take: 80000,
})
totalResults = results.length
console.log(`Deleting ${results.length} archived results...`)
const chunkSize = 1000
for (let i = 0; i < results.length; i += chunkSize) {
const chunk = results.slice(i, i + chunkSize)
await prisma.result.deleteMany({
where: {
id: {
in: chunk.map((result) => result.id),
},
},
})
}
} while (totalResults === 80000)
console.log('Done!')
}
const deleteOldChatSessions = async () => {
const twoDaysAgo = new Date()
twoDaysAgo.setDate(twoDaysAgo.getDate() - 2)
let totalChatSessions
do {
const chatSessions = await prisma.chatSession.findMany({
where: {
updatedAt: {
lte: twoDaysAgo,
},
},
select: {
id: true,
},
take: 80000,
})
totalChatSessions = chatSessions.length
console.log(`Deleting ${chatSessions.length} old chat sessions...`)
const chunkSize = 1000
for (let i = 0; i < chatSessions.length; i += chunkSize) {
const chunk = chatSessions.slice(i, i + chunkSize)
await prisma.chatSession.deleteMany({
where: {
id: {
in: chunk.map((chatSession) => chatSession.id),
},
},
})
}
} while (totalChatSessions === 80000)
}
const deleteExpiredAppSessions = async () => {
const threeDaysAgo = new Date()
threeDaysAgo.setDate(threeDaysAgo.getDate() - 3)
const { count } = await prisma.session.deleteMany({
where: {
expires: {
lte: threeDaysAgo,
},
},
})
console.log(`Deleted ${count} expired user sessions.`)
}
const deleteExpiredVerificationTokens = async () => {
const threeDaysAgo = new Date()
threeDaysAgo.setDate(threeDaysAgo.getDate() - 3)
let totalVerificationTokens
do {
const verificationTokens = await prisma.verificationToken.findMany({
where: {
expires: {
lte: threeDaysAgo,
},
},
select: {
token: true,
},
take: 80000,
})
totalVerificationTokens = verificationTokens.length
console.log(`Deleting ${verificationTokens.length} expired tokens...`)
const chunkSize = 1000
for (let i = 0; i < verificationTokens.length; i += chunkSize) {
const chunk = verificationTokens.slice(i, i + chunkSize)
await prisma.verificationToken.deleteMany({
where: {
token: {
in: chunk.map((verificationToken) => verificationToken.token),
},
},
})
}
} while (totalVerificationTokens === 80000)
console.log('Done!')
}
const resetBillingProps = async () => {
console.log('Resetting billing props...')
const { count } = await prisma.workspace.updateMany({
where: {
OR: [
{
isQuarantined: true,
},
{
chatsLimitFirstEmailSentAt: { not: null },
},
],
},
data: {
isQuarantined: false,
chatsLimitFirstEmailSentAt: null,
chatsLimitSecondEmailSentAt: null,
},
})
console.log(`Resetted ${count} workspaces.`)
}
const deleteResultsFromArchivedTypebotsIfAny = async (
typebotIds: { id: string }[]
) => {
console.log('Checking for archived typebots with non-archived results...')
const archivedTypebotsWithResults = (await prisma.typebot.findMany({
where: {
id: {
in: typebotIds.map((typebot) => typebot.id),
},
isArchived: true,
results: {
some: {},
},
},
select: {
id: true,
groups: true,
},
})) as Pick<Typebot, 'groups' | 'id'>[]
if (archivedTypebotsWithResults.length === 0) return
console.log(
`Found ${archivedTypebotsWithResults.length} archived typebots with non-archived results.`
)
for (const archivedTypebot of archivedTypebotsWithResults) {
await archiveResults(prisma)({
typebot: archivedTypebot,
resultsFilter: {
typebotId: archivedTypebot.id,
},
})
}
console.log('Delete archived results...')
await deleteArchivedResults()
}
cleanDatabase().then()