2
0

🔧 Enable usage limits on viewer

This commit is contained in:
Baptiste Arnaud
2022-12-05 13:53:20 +01:00
parent 4b2f42b40d
commit cfcecaaa17
4 changed files with 334 additions and 263 deletions

View File

@ -3,9 +3,14 @@ import prisma from '@/lib/prisma'
import { InputBlockType, PublicTypebot } from 'models'
import { NextApiRequest, NextApiResponse } from 'next'
import { badRequest, generatePresignedUrl, methodNotAllowed } from 'utils/api'
import { byId } from 'utils'
import { byId, env, getStorageLimit, isDefined } from 'utils'
import {
sendAlmostReachedStorageLimitEmail,
sendReachedStorageLimitEmail,
} from 'emails'
import { WorkspaceRole } from 'db'
// const LIMIT_EMAIL_TRIGGER_PERCENT = 0.8
const LIMIT_EMAIL_TRIGGER_PERCENT = 0.8
const handler = async (
req: NextApiRequest,
@ -27,7 +32,7 @@ const handler = async (
const typebotId = req.query.typebotId as string
const blockId = req.query.blockId as string
if (!filePath) return badRequest(res, 'Missing filePath or fileType')
// const hasReachedStorageLimit = await checkStorageLimit(typebotId)
const hasReachedStorageLimit = await checkStorageLimit(typebotId)
const typebot = (await prisma.publicTypebot.findFirst({
where: { typebotId },
})) as unknown as PublicTypebot
@ -46,117 +51,119 @@ const handler = async (
sizeLimit: sizeLimit * 1024 * 1024,
})
// TODO: enable storage limit on 1st of November 2022
return res.status(200).send({ presignedUrl, hasReachedStorageLimit: false })
return res.status(200).send({
presignedUrl,
hasReachedStorageLimit,
})
}
return methodNotAllowed(res)
}
// const checkStorageLimit = async (typebotId: string) => {
// const typebot = await prisma.typebot.findFirst({
// where: { id: typebotId },
// include: {
// workspace: {
// select: {
// id: true,
// additionalStorageIndex: true,
// plan: true,
// storageLimitFirstEmailSentAt: true,
// storageLimitSecondEmailSentAt: true,
// customStorageLimit: true,
// },
// },
// },
// })
// if (!typebot?.workspace) throw new Error('Workspace not found')
// const { workspace } = typebot
// const {
// _sum: { storageUsed: totalStorageUsed },
// } = await prisma.answer.aggregate({
// where: {
// storageUsed: { gt: 0 },
// result: {
// typebot: {
// workspace: {
// id: typebot?.workspaceId,
// },
// },
// },
// },
// _sum: { storageUsed: true },
// })
// if (!totalStorageUsed) return false
// const hasSentFirstEmail = workspace.storageLimitFirstEmailSentAt !== null
// const hasSentSecondEmail = workspace.storageLimitSecondEmailSentAt !== null
// const storageLimit = getStorageLimit(typebot.workspace)
// const storageLimitBytes = storageLimit * 1024 * 1024 * 1024
// if (
// totalStorageUsed >= storageLimitBytes * LIMIT_EMAIL_TRIGGER_PERCENT &&
// !hasSentFirstEmail &&
// env('E2E_TEST') !== 'true'
// )
// await sendAlmostReachStorageLimitNotification({
// workspaceId: workspace.id,
// storageLimit,
// })
// if (
// totalStorageUsed >= storageLimitBytes &&
// !hasSentSecondEmail &&
// env('E2E_TEST') !== 'true'
// )
// await sendReachStorageLimitNotification({
// workspaceId: workspace.id,
// storageLimit,
// })
// return totalStorageUsed >= storageLimitBytes
// }
const checkStorageLimit = async (typebotId: string): Promise<boolean> => {
const typebot = await prisma.typebot.findFirst({
where: { id: typebotId },
include: {
workspace: {
select: {
id: true,
additionalStorageIndex: true,
plan: true,
storageLimitFirstEmailSentAt: true,
storageLimitSecondEmailSentAt: true,
customStorageLimit: true,
},
},
},
})
if (!typebot?.workspace) throw new Error('Workspace not found')
const { workspace } = typebot
const {
_sum: { storageUsed: totalStorageUsed },
} = await prisma.answer.aggregate({
where: {
storageUsed: { gt: 0 },
result: {
typebot: {
workspace: {
id: typebot?.workspaceId,
},
},
},
},
_sum: { storageUsed: true },
})
if (!totalStorageUsed) return false
const hasSentFirstEmail = workspace.storageLimitFirstEmailSentAt !== null
const hasSentSecondEmail = workspace.storageLimitSecondEmailSentAt !== null
const storageLimit = getStorageLimit(typebot.workspace)
const storageLimitBytes = storageLimit * 1024 * 1024 * 1024
if (
totalStorageUsed >= storageLimitBytes * LIMIT_EMAIL_TRIGGER_PERCENT &&
!hasSentFirstEmail &&
env('E2E_TEST') !== 'true'
)
await sendAlmostReachStorageLimitNotification({
workspaceId: workspace.id,
storageLimit,
})
if (
totalStorageUsed >= storageLimitBytes &&
!hasSentSecondEmail &&
env('E2E_TEST') !== 'true'
)
await sendReachStorageLimitNotification({
workspaceId: workspace.id,
storageLimit,
})
return totalStorageUsed >= storageLimitBytes
}
// const sendAlmostReachStorageLimitNotification = async ({
// workspaceId,
// storageLimit,
// }: {
// workspaceId: string
// storageLimit: number
// }) => {
// const members = await prisma.memberInWorkspace.findMany({
// where: { role: WorkspaceRole.ADMIN, workspaceId },
// include: { user: { select: { email: true } } },
// })
const sendAlmostReachStorageLimitNotification = async ({
workspaceId,
storageLimit,
}: {
workspaceId: string
storageLimit: number
}) => {
const members = await prisma.memberInWorkspace.findMany({
where: { role: WorkspaceRole.ADMIN, workspaceId },
include: { user: { select: { email: true } } },
})
// await sendAlmostReachedStorageLimitEmail({
// to: members.map((member) => member.user.email).filter(isDefined),
// storageLimit,
// url: `${process.env.NEXTAUTH_URL}/typebots?workspaceId=${workspaceId}`,
// })
await sendAlmostReachedStorageLimitEmail({
to: members.map((member) => member.user.email).filter(isDefined),
storageLimit,
url: `${process.env.NEXTAUTH_URL}/typebots?workspaceId=${workspaceId}`,
})
// await prisma.workspace.update({
// where: { id: workspaceId },
// data: { storageLimitFirstEmailSentAt: new Date() },
// })
// }
await prisma.workspace.update({
where: { id: workspaceId },
data: { storageLimitFirstEmailSentAt: new Date() },
})
}
// const sendReachStorageLimitNotification = async ({
// workspaceId,
// storageLimit,
// }: {
// workspaceId: string
// storageLimit: number
// }) => {
// const members = await prisma.memberInWorkspace.findMany({
// where: { role: WorkspaceRole.ADMIN, workspaceId },
// include: { user: { select: { email: true } } },
// })
const sendReachStorageLimitNotification = async ({
workspaceId,
storageLimit,
}: {
workspaceId: string
storageLimit: number
}) => {
const members = await prisma.memberInWorkspace.findMany({
where: { role: WorkspaceRole.ADMIN, workspaceId },
include: { user: { select: { email: true } } },
})
// await sendReachedStorageLimitEmail({
// to: members.map((member) => member.user.email).filter(isDefined),
// storageLimit,
// url: `${process.env.NEXTAUTH_URL}/typebots?workspaceId=${workspaceId}`,
// })
await sendReachedStorageLimitEmail({
to: members.map((member) => member.user.email).filter(isDefined),
storageLimit,
url: `${process.env.NEXTAUTH_URL}/typebots?workspaceId=${workspaceId}`,
})
// await prisma.workspace.update({
// where: { id: workspaceId },
// data: { storageLimitSecondEmailSentAt: new Date() },
// })
// }
await prisma.workspace.update({
where: { id: workspaceId },
data: { storageLimitSecondEmailSentAt: new Date() },
})
}
export default withSentry(handler)

View File

@ -1,10 +1,16 @@
import { authenticateUser } from '@/features/auth/api'
import prisma from '@/lib/prisma'
import { ResultWithAnswers } from 'models'
import { WorkspaceRole } from 'db'
import {
sendAlmostReachedChatsLimitEmail,
sendReachedChatsLimitEmail,
} from 'emails'
import { ResultWithAnswers, Workspace } from 'models'
import { NextApiRequest, NextApiResponse } from 'next'
import { env, getChatsLimit, isDefined } from 'utils'
import { methodNotAllowed } from 'utils/api'
// const LIMIT_EMAIL_TRIGGER_PERCENT = 0.8
const LIMIT_EMAIL_TRIGGER_PERCENT = 0.8
const handler = async (req: NextApiRequest, res: NextApiResponse) => {
if (req.method === 'GET') {
@ -49,113 +55,112 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
},
},
})
// TODO: enable storage limit on 1st of November 2022
// const hasReachedLimit = await checkChatsUsage(result.typebot.workspace)
res.send({ result, hasReachedLimit: false })
const hasReachedLimit = await checkChatsUsage(result.typebot.workspace)
res.send({ result, hasReachedLimit })
return
}
methodNotAllowed(res)
}
// const checkChatsUsage = async (
// workspace: Pick<
// Workspace,
// | 'id'
// | 'plan'
// | 'additionalChatsIndex'
// | 'chatsLimitFirstEmailSentAt'
// | 'chatsLimitSecondEmailSentAt'
// | 'customChatsLimit'
// >
// ) => {
// const chatsLimit = getChatsLimit(workspace)
// if (chatsLimit === -1) return
// const now = new Date()
// const firstDayOfMonth = new Date(now.getFullYear(), now.getMonth(), 1)
// const lastDayOfMonth = new Date(now.getFullYear(), now.getMonth() + 1, 0)
// const firstDayOfNextMonth = new Date(now.getFullYear(), now.getMonth() + 1, 1)
// const chatsCount = await prisma.result.count({
// where: {
// typebot: { workspaceId: workspace.id },
// hasStarted: true,
// createdAt: { gte: firstDayOfMonth, lte: lastDayOfMonth },
// },
// })
// const hasSentFirstEmail =
// workspace.chatsLimitFirstEmailSentAt !== null &&
// workspace.chatsLimitFirstEmailSentAt < firstDayOfNextMonth &&
// workspace.chatsLimitFirstEmailSentAt > firstDayOfMonth
// const hasSentSecondEmail =
// workspace.chatsLimitSecondEmailSentAt !== null &&
// workspace.chatsLimitSecondEmailSentAt < firstDayOfNextMonth &&
// workspace.chatsLimitSecondEmailSentAt > firstDayOfMonth
// if (
// chatsCount >= chatsLimit * LIMIT_EMAIL_TRIGGER_PERCENT &&
// !hasSentFirstEmail &&
// env('E2E_TEST') !== 'true'
// )
// await sendAlmostReachChatsLimitNotification({
// workspaceId: workspace.id,
// chatsLimit,
// })
// if (
// chatsCount >= chatsLimit &&
// !hasSentSecondEmail &&
// env('E2E_TEST') !== 'true'
// )
// await sendReachedAlertNotification({
// workspaceId: workspace.id,
// chatsLimit,
// })
// return chatsCount >= chatsLimit
// }
const checkChatsUsage = async (
workspace: Pick<
Workspace,
| 'id'
| 'plan'
| 'additionalChatsIndex'
| 'chatsLimitFirstEmailSentAt'
| 'chatsLimitSecondEmailSentAt'
| 'customChatsLimit'
>
) => {
const chatsLimit = getChatsLimit(workspace)
if (chatsLimit === -1) return
const now = new Date()
const firstDayOfMonth = new Date(now.getFullYear(), now.getMonth(), 1)
const lastDayOfMonth = new Date(now.getFullYear(), now.getMonth() + 1, 0)
const firstDayOfNextMonth = new Date(now.getFullYear(), now.getMonth() + 1, 1)
const chatsCount = await prisma.result.count({
where: {
typebot: { workspaceId: workspace.id },
hasStarted: true,
createdAt: { gte: firstDayOfMonth, lte: lastDayOfMonth },
},
})
const hasSentFirstEmail =
workspace.chatsLimitFirstEmailSentAt !== null &&
workspace.chatsLimitFirstEmailSentAt < firstDayOfNextMonth &&
workspace.chatsLimitFirstEmailSentAt > firstDayOfMonth
const hasSentSecondEmail =
workspace.chatsLimitSecondEmailSentAt !== null &&
workspace.chatsLimitSecondEmailSentAt < firstDayOfNextMonth &&
workspace.chatsLimitSecondEmailSentAt > firstDayOfMonth
if (
chatsCount >= chatsLimit * LIMIT_EMAIL_TRIGGER_PERCENT &&
!hasSentFirstEmail &&
env('E2E_TEST') !== 'true'
)
await sendAlmostReachChatsLimitNotification({
workspaceId: workspace.id,
chatsLimit,
})
if (
chatsCount >= chatsLimit &&
!hasSentSecondEmail &&
env('E2E_TEST') !== 'true'
)
await sendReachedAlertNotification({
workspaceId: workspace.id,
chatsLimit,
})
return chatsCount >= chatsLimit
}
// const sendAlmostReachChatsLimitNotification = async ({
// workspaceId,
// chatsLimit,
// }: {
// workspaceId: string
// chatsLimit: number
// }) => {
// const members = await prisma.memberInWorkspace.findMany({
// where: { role: WorkspaceRole.ADMIN, workspaceId },
// include: { user: { select: { email: true } } },
// })
const sendAlmostReachChatsLimitNotification = async ({
workspaceId,
chatsLimit,
}: {
workspaceId: string
chatsLimit: number
}) => {
const members = await prisma.memberInWorkspace.findMany({
where: { role: WorkspaceRole.ADMIN, workspaceId },
include: { user: { select: { email: true } } },
})
// await sendAlmostReachedChatsLimitEmail({
// to: members.map((member) => member.user.email).filter(isDefined),
// chatsLimit,
// url: `${process.env.NEXTAUTH_URL}/typebots?workspaceId=${workspaceId}`,
// })
await sendAlmostReachedChatsLimitEmail({
to: members.map((member) => member.user.email).filter(isDefined),
chatsLimit,
url: `${process.env.NEXTAUTH_URL}/typebots?workspaceId=${workspaceId}`,
})
// await prisma.workspace.update({
// where: { id: workspaceId },
// data: { chatsLimitFirstEmailSentAt: new Date() },
// })
// }
await prisma.workspace.update({
where: { id: workspaceId },
data: { chatsLimitFirstEmailSentAt: new Date() },
})
}
// const sendReachedAlertNotification = async ({
// workspaceId,
// chatsLimit,
// }: {
// workspaceId: string
// chatsLimit: number
// }) => {
// const members = await prisma.memberInWorkspace.findMany({
// where: { role: WorkspaceRole.ADMIN, workspaceId },
// include: { user: { select: { email: true } } },
// })
const sendReachedAlertNotification = async ({
workspaceId,
chatsLimit,
}: {
workspaceId: string
chatsLimit: number
}) => {
const members = await prisma.memberInWorkspace.findMany({
where: { role: WorkspaceRole.ADMIN, workspaceId },
include: { user: { select: { email: true } } },
})
// await sendReachedChatsLimitEmail({
// to: members.map((member) => member.user.email).filter(isDefined),
// chatsLimit,
// url: `${process.env.NEXTAUTH_URL}/typebots?workspaceId=${workspaceId}`,
// })
await sendReachedChatsLimitEmail({
to: members.map((member) => member.user.email).filter(isDefined),
chatsLimit,
url: `${process.env.NEXTAUTH_URL}/typebots?workspaceId=${workspaceId}`,
})
// await prisma.workspace.update({
// where: { id: workspaceId },
// data: { chatsLimitSecondEmailSentAt: new Date() },
// })
// }
await prisma.workspace.update({
where: { id: workspaceId },
data: { chatsLimitSecondEmailSentAt: new Date() },
})
}
export default handler