2
0

🐛 (js) Fix upload file in linked typebot

This commit is contained in:
Baptiste Arnaud
2023-03-21 09:11:36 +01:00
parent 4109a8489c
commit b4536abc2f
4 changed files with 104 additions and 44 deletions

View File

@ -13,6 +13,16 @@ const nextConfig = {
experimental: {
outputFileTracingRoot: path.join(__dirname, '../../'),
},
async redirects() {
return [
{
source: '/api/typebots/:typebotId/blocks/:blockId/storage/upload-url',
destination:
'/api/v1/typebots/:typebotId/blocks/:blockId/storage/upload-url',
permanent: true,
},
]
},
}
const sentryWebpackPluginOptions = {

View File

@ -1,13 +1,17 @@
import { publicProcedure } from '@/helpers/server/trpc'
import prisma from '@/lib/prisma'
import { InputBlockType, PublicTypebot } from '@typebot.io/schemas'
import { NextApiRequest, NextApiResponse } from 'next'
import {
badRequest,
generatePresignedUrl,
methodNotAllowed,
} from '@typebot.io/lib/api'
import { byId, env, isDefined } from '@typebot.io/lib'
import { TRPCError } from '@trpc/server'
import { getStorageLimit } from '@typebot.io/lib/pricing'
import {
FileInputBlock,
InputBlockType,
LogicBlockType,
PublicTypebot,
TypebotLinkBlock,
} from '@typebot.io/schemas'
import { byId, env, isDefined } from '@typebot.io/lib'
import { z } from 'zod'
import { generatePresignedUrl } from '@typebot.io/lib/api/storage'
import {
sendAlmostReachedStorageLimitEmail,
sendReachedStorageLimitEmail,
@ -16,35 +20,61 @@ import { WorkspaceRole } from '@typebot.io/prisma'
const LIMIT_EMAIL_TRIGGER_PERCENT = 0.8
const handler = async (
req: NextApiRequest,
res: NextApiResponse
): Promise<void> => {
res.setHeader('Access-Control-Allow-Origin', '*')
if (req.method === 'GET') {
export const getUploadUrl = publicProcedure
.meta({
openapi: {
method: 'GET',
path: '/typebots/{typebotId}/blocks/{blockId}/storage/upload-url',
summary: 'Get upload URL for a file',
description: 'Used for the web client to get the bucket upload file.',
},
})
.input(
z.object({
typebotId: z.string(),
blockId: z.string(),
filePath: z.string(),
fileType: z.string(),
})
)
.output(
z.object({
presignedUrl: z.object({
url: z.string(),
fields: z.any(),
}),
hasReachedStorageLimit: z.boolean(),
})
)
.query(async ({ input: { typebotId, blockId, filePath, fileType } }) => {
if (
!process.env.S3_ENDPOINT ||
!process.env.S3_ACCESS_KEY ||
!process.env.S3_SECRET_KEY
)
return badRequest(
res,
'S3 not properly configured. Missing one of those variables: S3_ENDPOINT, S3_ACCESS_KEY, S3_SECRET_KEY'
)
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) return badRequest(res, 'Missing filePath or fileType')
throw new TRPCError({
code: 'INTERNAL_SERVER_ERROR',
message:
'S3 not properly configured. Missing one of those variables: S3_ENDPOINT, S3_ACCESS_KEY, S3_SECRET_KEY',
})
const hasReachedStorageLimit = await checkIfStorageLimitReached(typebotId)
const typebot = (await prisma.publicTypebot.findFirst({
const publicTypebot = (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, 'Not a file upload block')
select: {
groups: true,
typebotId: true,
},
})) as Pick<PublicTypebot, 'groups' | 'typebotId'>
const fileUploadBlock = await getFileUploadBlock(publicTypebot, blockId)
if (!fileUploadBlock)
throw new TRPCError({
code: 'BAD_REQUEST',
message: 'File upload block not found',
})
const sizeLimit = fileUploadBlock.options.sizeLimit
? Math.min(fileUploadBlock.options.sizeLimit, 500)
: 10
@ -55,12 +85,38 @@ const handler = async (
sizeLimit: sizeLimit * 1024 * 1024,
})
return res.status(200).send({
return {
presignedUrl,
hasReachedStorageLimit,
})
}
return methodNotAllowed(res)
}
})
const getFileUploadBlock = async (
publicTypebot: Pick<PublicTypebot, 'groups' | 'typebotId'>,
blockId: string
): Promise<FileInputBlock | null> => {
const fileUploadBlock = publicTypebot.groups
.flatMap((group) => group.blocks)
.find(byId(blockId))
if (fileUploadBlock?.type === InputBlockType.FILE) return fileUploadBlock
const linkedTypebotIds = publicTypebot.groups
.flatMap((group) => group.blocks)
.filter((block) => block.type === LogicBlockType.TYPEBOT_LINK)
.flatMap((block) => (block as TypebotLinkBlock).options.typebotId)
.filter(isDefined)
const linkedTypebots = (await prisma.publicTypebot.findMany({
where: { typebotId: { in: linkedTypebotIds } },
select: {
groups: true,
},
})) as Pick<PublicTypebot, 'groups'>[]
const fileUploadBlockFromLinkedTypebots = linkedTypebots
.flatMap((typebot) => typebot.groups)
.flatMap((group) => group.blocks)
.find(byId(blockId))
if (fileUploadBlockFromLinkedTypebots?.type === InputBlockType.FILE)
return fileUploadBlockFromLinkedTypebots
return null
}
const checkIfStorageLimitReached = async (
@ -170,5 +226,3 @@ const sendReachStorageLimitNotification = async ({
data: { storageLimitSecondEmailSentAt: new Date() },
})
}
export default handler

View File

@ -1,6 +0,0 @@
import { router } from '@/helpers/server/trpc'
import { sendMessage } from './sendMessage'
export const chatRouter = router({
sendMessage,
})

View File

@ -1,8 +1,10 @@
import { chatRouter } from '@/features/chat/api/router'
import { getUploadUrl } from '@/features/blocks/inputs/fileUpload/api/getUploadUrl'
import { sendMessage } from '@/features/chat/api/sendMessage'
import { router } from '../../trpc'
export const appRouter = router({
chat: chatRouter,
sendMessage,
getUploadUrl,
})
export type AppRouter = typeof appRouter