💚 Fix checkAndReportChatsUsage script sending multiple emails at once
This commit is contained in:
@@ -1,9 +1,4 @@
|
|||||||
import {
|
import { Plan, PrismaClient, WorkspaceRole } from '@typebot.io/prisma'
|
||||||
MemberInWorkspace,
|
|
||||||
Plan,
|
|
||||||
PrismaClient,
|
|
||||||
WorkspaceRole,
|
|
||||||
} from '@typebot.io/prisma'
|
|
||||||
import { isDefined, isEmpty } from '@typebot.io/lib'
|
import { isDefined, isEmpty } from '@typebot.io/lib'
|
||||||
import { getChatsLimit } from '@typebot.io/lib/billing/getChatsLimit'
|
import { getChatsLimit } from '@typebot.io/lib/billing/getChatsLimit'
|
||||||
import { promptAndSetEnvironment } from './utils'
|
import { promptAndSetEnvironment } from './utils'
|
||||||
@@ -73,24 +68,6 @@ export const checkAndReportChatsUsage = async () => {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
const resultsWithWorkspaces = results
|
|
||||||
.flatMap((result) => {
|
|
||||||
const workspace = workspaces.find((workspace) =>
|
|
||||||
workspace.typebots.some((typebot) => typebot.id === result.typebotId)
|
|
||||||
)
|
|
||||||
if (!workspace) return
|
|
||||||
return workspace.members
|
|
||||||
.filter((member) => member.role !== WorkspaceRole.GUEST)
|
|
||||||
.map((member, memberIndex) => ({
|
|
||||||
userId: member.user.id,
|
|
||||||
workspace: workspace,
|
|
||||||
typebotId: result.typebotId,
|
|
||||||
totalResultsLastHour: result._count._all,
|
|
||||||
isFirstOfKind: memberIndex === 0 ? (true as const) : undefined,
|
|
||||||
}))
|
|
||||||
})
|
|
||||||
.filter(isDefined)
|
|
||||||
|
|
||||||
if (isEmpty(process.env.STRIPE_SECRET_KEY))
|
if (isEmpty(process.env.STRIPE_SECRET_KEY))
|
||||||
throw new Error('Missing STRIPE_SECRET_KEY env variable')
|
throw new Error('Missing STRIPE_SECRET_KEY env variable')
|
||||||
|
|
||||||
@@ -100,14 +77,12 @@ export const checkAndReportChatsUsage = async () => {
|
|||||||
|
|
||||||
const quarantineEvents: TelemetryEvent[] = []
|
const quarantineEvents: TelemetryEvent[] = []
|
||||||
|
|
||||||
for (const result of resultsWithWorkspaces.filter(
|
for (const workspace of workspaces) {
|
||||||
(result) => result.isFirstOfKind
|
if (workspace.isQuarantined) continue
|
||||||
)) {
|
const chatsLimit = getChatsLimit(workspace)
|
||||||
if (result.workspace.isQuarantined) continue
|
const subscription = await getSubscription(workspace, { stripe })
|
||||||
const chatsLimit = getChatsLimit(result.workspace)
|
|
||||||
const subscription = await getSubscription(result.workspace, { stripe })
|
|
||||||
const { totalChatsUsed } = await getUsage(prisma)({
|
const { totalChatsUsed } = await getUsage(prisma)({
|
||||||
workspaceId: result.workspace.id,
|
workspaceId: workspace.id,
|
||||||
subscription,
|
subscription,
|
||||||
})
|
})
|
||||||
if (chatsLimit === 'inf') continue
|
if (chatsLimit === 'inf') continue
|
||||||
@@ -115,9 +90,9 @@ export const checkAndReportChatsUsage = async () => {
|
|||||||
chatsLimit > 0 &&
|
chatsLimit > 0 &&
|
||||||
totalChatsUsed >= chatsLimit * LIMIT_EMAIL_TRIGGER_PERCENT &&
|
totalChatsUsed >= chatsLimit * LIMIT_EMAIL_TRIGGER_PERCENT &&
|
||||||
totalChatsUsed < chatsLimit &&
|
totalChatsUsed < chatsLimit &&
|
||||||
!result.workspace.chatsLimitFirstEmailSentAt
|
!workspace.chatsLimitFirstEmailSentAt
|
||||||
) {
|
) {
|
||||||
const to = result.workspace.members
|
const to = workspace.members
|
||||||
.filter((member) => member.role === WorkspaceRole.ADMIN)
|
.filter((member) => member.role === WorkspaceRole.ADMIN)
|
||||||
.map((member) => member.user.email)
|
.map((member) => member.user.email)
|
||||||
.filter(isDefined)
|
.filter(isDefined)
|
||||||
@@ -129,10 +104,10 @@ export const checkAndReportChatsUsage = async () => {
|
|||||||
to,
|
to,
|
||||||
usagePercent: Math.round((totalChatsUsed / chatsLimit) * 100),
|
usagePercent: Math.round((totalChatsUsed / chatsLimit) * 100),
|
||||||
chatsLimit,
|
chatsLimit,
|
||||||
workspaceName: result.workspace.name,
|
workspaceName: workspace.name,
|
||||||
})
|
})
|
||||||
await prisma.workspace.updateMany({
|
await prisma.workspace.updateMany({
|
||||||
where: { id: result.workspace.id },
|
where: { id: workspace.id },
|
||||||
data: { chatsLimitFirstEmailSentAt: new Date() },
|
data: { chatsLimitFirstEmailSentAt: new Date() },
|
||||||
})
|
})
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
@@ -151,15 +126,15 @@ export const checkAndReportChatsUsage = async () => {
|
|||||||
if (
|
if (
|
||||||
isUsageBasedSubscription &&
|
isUsageBasedSubscription &&
|
||||||
subscription &&
|
subscription &&
|
||||||
(result.workspace.plan === 'STARTER' || result.workspace.plan === 'PRO')
|
(workspace.plan === 'STARTER' || workspace.plan === 'PRO')
|
||||||
) {
|
) {
|
||||||
if (result.workspace.plan === 'STARTER' && totalChatsUsed >= 4000) {
|
if (workspace.plan === 'STARTER' && totalChatsUsed >= 4000) {
|
||||||
console.log(
|
console.log(
|
||||||
'Workspace has more than 4000 chats, automatically upgrading to PRO plan'
|
'Workspace has more than 4000 chats, automatically upgrading to PRO plan'
|
||||||
)
|
)
|
||||||
const newSubscription = await autoUpgradeToPro(subscription, {
|
const newSubscription = await autoUpgradeToPro(subscription, {
|
||||||
stripe,
|
stripe,
|
||||||
workspaceId: result.workspace.id,
|
workspaceId: workspace.id,
|
||||||
})
|
})
|
||||||
await reportUsageToStripe(totalChatsUsed, {
|
await reportUsageToStripe(totalChatsUsed, {
|
||||||
stripe,
|
stripe,
|
||||||
@@ -170,26 +145,21 @@ export const checkAndReportChatsUsage = async () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (totalChatsUsed > chatsLimit * 1.5 && workspace.plan === Plan.FREE) {
|
||||||
totalChatsUsed > chatsLimit * 1.5 &&
|
console.log(`Automatically quarantine workspace ${workspace.id}...`)
|
||||||
result.workspace.plan === Plan.FREE
|
|
||||||
) {
|
|
||||||
console.log(
|
|
||||||
`Automatically quarantine workspace ${result.workspace.id}...`
|
|
||||||
)
|
|
||||||
await prisma.workspace.updateMany({
|
await prisma.workspace.updateMany({
|
||||||
where: { id: result.workspace.id },
|
where: { id: workspace.id },
|
||||||
data: { isQuarantined: true },
|
data: { isQuarantined: true },
|
||||||
})
|
})
|
||||||
quarantineEvents.push(
|
quarantineEvents.push(
|
||||||
...result.workspace.members
|
...workspace.members
|
||||||
.filter((member) => member.role === WorkspaceRole.ADMIN)
|
.filter((member) => member.role === WorkspaceRole.ADMIN)
|
||||||
.map(
|
.map(
|
||||||
(member) =>
|
(member) =>
|
||||||
({
|
({
|
||||||
name: 'Workspace automatically quarantined',
|
name: 'Workspace automatically quarantined',
|
||||||
userId: member.user.id,
|
userId: member.user.id,
|
||||||
workspaceId: result.workspace.id,
|
workspaceId: workspace.id,
|
||||||
data: {
|
data: {
|
||||||
totalChatsUsed,
|
totalChatsUsed,
|
||||||
chatsLimit,
|
chatsLimit,
|
||||||
@@ -200,6 +170,24 @@ export const checkAndReportChatsUsage = async () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const resultsWithWorkspaces = results
|
||||||
|
.flatMap((result) => {
|
||||||
|
const workspace = workspaces.find((workspace) =>
|
||||||
|
workspace.typebots.some((typebot) => typebot.id === result.typebotId)
|
||||||
|
)
|
||||||
|
if (!workspace) return
|
||||||
|
return workspace.members
|
||||||
|
.filter((member) => member.role !== WorkspaceRole.GUEST)
|
||||||
|
.map((member, memberIndex) => ({
|
||||||
|
userId: member.user.id,
|
||||||
|
workspace: workspace,
|
||||||
|
typebotId: result.typebotId,
|
||||||
|
totalResultsLastHour: result._count._all,
|
||||||
|
isFirstOfKind: memberIndex === 0 ? (true as const) : undefined,
|
||||||
|
}))
|
||||||
|
})
|
||||||
|
.filter(isDefined)
|
||||||
|
|
||||||
const newResultsCollectedEvents = resultsWithWorkspaces.map(
|
const newResultsCollectedEvents = resultsWithWorkspaces.map(
|
||||||
(result) =>
|
(result) =>
|
||||||
({
|
({
|
||||||
|
|||||||
Reference in New Issue
Block a user