feat(bot): ⚡️ Add custom file upload size limit
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import { FormLabel, Stack } from '@chakra-ui/react'
|
||||
import { CodeEditor } from 'components/shared/CodeEditor'
|
||||
import { SmartNumberInput } from 'components/shared/SmartNumberInput'
|
||||
import { SwitchWithLabel } from 'components/shared/SwitchWithLabel'
|
||||
import { Input } from 'components/shared/Textbox'
|
||||
import { VariableSearchInput } from 'components/shared/VariableSearchInput'
|
||||
@@ -20,7 +21,8 @@ export const FileInputSettings = ({ options, onOptionsChange }: Props) => {
|
||||
onOptionsChange({ ...options, isMultipleAllowed })
|
||||
const handleVariableChange = (variable?: Variable) =>
|
||||
onOptionsChange({ ...options, variableId: variable?.id })
|
||||
|
||||
const handleSizeLimitChange = (sizeLimit?: number) =>
|
||||
onOptionsChange({ ...options, sizeLimit })
|
||||
return (
|
||||
<Stack spacing={4}>
|
||||
<SwitchWithLabel
|
||||
@@ -29,6 +31,16 @@ export const FileInputSettings = ({ options, onOptionsChange }: Props) => {
|
||||
initialValue={options.isMultipleAllowed}
|
||||
onCheckChange={handleLongChange}
|
||||
/>
|
||||
<Stack>
|
||||
<FormLabel mb="0" htmlFor="limit">
|
||||
Size limit (MB):
|
||||
</FormLabel>
|
||||
<SmartNumberInput
|
||||
id="limit"
|
||||
value={options.sizeLimit ?? 10}
|
||||
onValueChange={handleSizeLimitChange}
|
||||
/>
|
||||
</Stack>
|
||||
<Stack>
|
||||
<FormLabel mb="0">Placeholder:</FormLabel>
|
||||
<CodeEditor
|
||||
|
||||
@@ -37,6 +37,7 @@ test('options should work', async ({ page }) => {
|
||||
await page.click('text="Allow multiple files?"')
|
||||
await page.fill('div[contenteditable=true]', '<strong>Upload now!!</strong>')
|
||||
await page.fill('[value="Upload"]', 'Go')
|
||||
await page.fill('input[value="10"]', '20')
|
||||
await page.click('text="Restart"')
|
||||
await expect(typebotViewer(page).locator(`text="Upload now!!"`)).toBeVisible()
|
||||
await typebotViewer(page)
|
||||
|
||||
@@ -35,6 +35,7 @@ export const TypebotPage = ({
|
||||
const [variableUpdateQueue, setVariableUpdateQueue] = useState<
|
||||
VariableWithValue[][]
|
||||
>([])
|
||||
const [chatStarted, setChatStarted] = useState(false)
|
||||
|
||||
useEffect(() => {
|
||||
setShowTypebot(true)
|
||||
@@ -94,10 +95,16 @@ export const TypebotPage = ({
|
||||
if (error) setError(error)
|
||||
}
|
||||
|
||||
const handleNewAnswer = async (answer: Answer) => {
|
||||
const handleNewAnswer = async (
|
||||
answer: Answer & { uploadedFiles: boolean }
|
||||
) => {
|
||||
if (!resultId) return setError(new Error('Result was not created'))
|
||||
const { error } = await upsertAnswer({ ...answer, resultId })
|
||||
if (error) setError(error)
|
||||
if (chatStarted) return
|
||||
updateResult(resultId, {
|
||||
hasStarted: true,
|
||||
}).then(({ error }) => (error ? setError(error) : setChatStarted(true)))
|
||||
}
|
||||
|
||||
const handleCompleted = async () => {
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { withSentry } from '@sentry/nextjs'
|
||||
import prisma from 'libs/prisma'
|
||||
import { InputBlockType, PublicTypebot } from 'models'
|
||||
import { NextApiRequest, NextApiResponse } from 'next'
|
||||
import { badRequest, generatePresignedUrl, methodNotAllowed } from 'utils'
|
||||
import { badRequest, generatePresignedUrl, methodNotAllowed, byId } from 'utils'
|
||||
|
||||
const handler = async (
|
||||
req: NextApiRequest,
|
||||
@@ -19,8 +21,25 @@ const handler = async (
|
||||
)
|
||||
const filePath = req.query.filePath as string | undefined
|
||||
const fileType = req.query.fileType as string | undefined
|
||||
const typebotId = req.query.typebotId as string
|
||||
const blockId = req.query.blockId as string
|
||||
if (!filePath || !fileType) return badRequest(res)
|
||||
const presignedUrl = generatePresignedUrl({ fileType, filePath })
|
||||
const typebot = (await prisma.publicTypebot.findFirst({
|
||||
where: { typebotId },
|
||||
})) as unknown as PublicTypebot
|
||||
const fileUploadBlock = typebot.groups
|
||||
.flatMap((g) => g.blocks)
|
||||
.find(byId(blockId))
|
||||
if (fileUploadBlock?.type !== InputBlockType.FILE) return badRequest(res)
|
||||
const sizeLimit = fileUploadBlock.options.sizeLimit
|
||||
? Math.min(fileUploadBlock.options.sizeLimit, 500)
|
||||
: 10
|
||||
|
||||
const presignedUrl = generatePresignedUrl({
|
||||
fileType,
|
||||
filePath,
|
||||
sizeLimit: sizeLimit * 1024 * 1024,
|
||||
})
|
||||
|
||||
return res.status(200).send({ presignedUrl })
|
||||
}
|
||||
@@ -26,7 +26,10 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
|
||||
if (req.method === 'POST') {
|
||||
const typebotId = req.query.typebotId as string
|
||||
const result = await prisma.result.create({
|
||||
data: { typebotId, isCompleted: false },
|
||||
data: {
|
||||
typebotId,
|
||||
isCompleted: false,
|
||||
},
|
||||
})
|
||||
return res.send(result)
|
||||
}
|
||||
|
||||
@@ -1,14 +1,25 @@
|
||||
import { withSentry } from '@sentry/nextjs'
|
||||
import { Answer } from 'db'
|
||||
import { got } from 'got'
|
||||
import prisma from 'libs/prisma'
|
||||
import { NextApiRequest, NextApiResponse } from 'next'
|
||||
import { methodNotAllowed } from 'utils'
|
||||
import { isNotDefined, methodNotAllowed } from 'utils'
|
||||
|
||||
const handler = async (req: NextApiRequest, res: NextApiResponse) => {
|
||||
if (req.method === 'PUT') {
|
||||
const answer = (
|
||||
const { uploadedFiles, ...answer } = (
|
||||
typeof req.body === 'string' ? JSON.parse(req.body) : req.body
|
||||
) as Answer
|
||||
) as Answer & { uploadedFiles?: boolean }
|
||||
let storageUsed = 0
|
||||
if (uploadedFiles && answer.content.includes('http')) {
|
||||
const fileUrls = answer.content.split(', ')
|
||||
for (const url of fileUrls) {
|
||||
const { headers } = await got(url)
|
||||
const size = headers['content-length']
|
||||
if (isNotDefined(size)) return
|
||||
storageUsed += parseInt(size, 10)
|
||||
}
|
||||
}
|
||||
const result = await prisma.answer.upsert({
|
||||
where: {
|
||||
resultId_blockId_groupId: {
|
||||
@@ -17,8 +28,8 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
|
||||
blockId: answer.blockId,
|
||||
},
|
||||
},
|
||||
create: answer,
|
||||
update: answer,
|
||||
create: { ...answer, storageUsed: storageUsed > 0 ? storageUsed : null },
|
||||
update: { ...answer, storageUsed: storageUsed > 0 ? storageUsed : null },
|
||||
})
|
||||
return res.send(result)
|
||||
}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import { Answer } from 'models'
|
||||
import { sendRequest } from 'utils'
|
||||
|
||||
export const upsertAnswer = async (answer: Answer & { resultId: string }) =>
|
||||
export const upsertAnswer = async (
|
||||
answer: Answer & { resultId: string } & { uploadedFiles?: boolean }
|
||||
) =>
|
||||
sendRequest<Answer>({
|
||||
url: `/api/typebots/t/results/r/answers`,
|
||||
method: 'PUT',
|
||||
|
||||
Reference in New Issue
Block a user