Skip to content

Commit

Permalink
🐛 (js) Fix upload file in linked typebot
Browse files Browse the repository at this point in the history
  • Loading branch information
baptisteArno committed Mar 21, 2023
1 parent 4109a84 commit b4536ab
Show file tree
Hide file tree
Showing 4 changed files with 103 additions and 43 deletions.
10 changes: 10 additions & 0 deletions apps/viewer/next.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand Down
Original file line number Diff line number Diff line change
@@ -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 { TRPCError } from '@trpc/server'
import { getStorageLimit } from '@typebot.io/lib/pricing'
import {
badRequest,
generatePresignedUrl,
methodNotAllowed,
} from '@typebot.io/lib/api'
FileInputBlock,
InputBlockType,
LogicBlockType,
PublicTypebot,
TypebotLinkBlock,
} from '@typebot.io/schemas'
import { byId, env, isDefined } from '@typebot.io/lib'
import { getStorageLimit } from '@typebot.io/lib/pricing'
import { z } from 'zod'
import { generatePresignedUrl } from '@typebot.io/lib/api/storage'
import {
sendAlmostReachedStorageLimitEmail,
sendReachedStorageLimitEmail,
Expand All @@ -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
Expand All @@ -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 (
Expand Down Expand Up @@ -170,5 +226,3 @@ const sendReachStorageLimitNotification = async ({
data: { storageLimitSecondEmailSentAt: new Date() },
})
}

export default handler
6 changes: 0 additions & 6 deletions apps/viewer/src/features/chat/api/router.ts

This file was deleted.

6 changes: 4 additions & 2 deletions apps/viewer/src/helpers/server/routers/v1/_app.ts
Original file line number Diff line number Diff line change
@@ -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

4 comments on commit b4536ab

@vercel
Copy link

@vercel vercel bot commented on b4536ab Mar 21, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

docs – ./apps/docs

docs.typebot.io
docs-typebot-io.vercel.app
docs-git-main-typebot-io.vercel.app

@vercel
Copy link

@vercel vercel bot commented on b4536ab Mar 21, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

viewer-v2 – ./apps/viewer

botc.ceox.com.br
clo.closeer.work
cockroach.cr8.ai
faqs.nigerias.io
feedback.ofx.one
form.syncwin.com
haymanevents.com
kw.wpwakanda.com
myrentalhost.com
stan.vselise.com
start.taxtree.io
typebot.aloe.bot
voicehelp.cr8.ai
zap.fundviser.in
app.bouclidom.com
app.chatforms.net
bot.hostnation.de
bot.maitempah.com
bot.phuonghub.com
bot.reviewzer.com
bot.rihabilita.it
cares.urlabout.me
chat.gaswadern.de
fmm.wpwakanda.com
gentleman-shop.fr
k1.kandabrand.com
kp.pedroknoll.com
lb.ticketfute.com
ov1.wpwakanda.com
ov2.wpwakanda.com
ov3.wpwakanda.com
support.triplo.ai
viewer.typebot.io
welcome.triplo.ai
1988.bouclidom.com
andreimayer.com.br
bot.danyservice.it
bot.iconicbrows.it
bot.lucide.contact
bot.megafox.com.br
bot.neferlopez.com
bots.robomotion.io
cadu.uninta.edu.br
dicanatural.online
digitalhelp.com.au
abg-assistent.m-vogel.de
ai.chromebookstoreph.com
contextone.wpwakanda.com
form.sergiolimajr.com.br
hunterbot.saleshunter.ai
invite.bridesquadapp.com
link.cascadigital.com.br
onboarding.growthside.io
reward.onlinebotdemo.xyz
stap.venturemarketing.in
type.opaulovieira.com.br
aibot.angrybranding.co.uk
bot.aidigitalmarketing.kr
bot.amicidisanfaustino.it
bot.polychromes-project.com
bot.seidinembroseanchetu.it
chat.semanalimpanome.com.br
chatbot.berbelanjabiz.trade
designguide.techyscouts.com
liveconvert2.kandalearn.com
presente.empresarias.com.mx
sell.sellthemotorhome.co.uk
anamnese.odontopavani.com.br
austin.channelautomation.com
bot.marketingplusmindset.com
bot.seidibergamoseanchetu.it
desabafe.sergiolimajr.com.br
download.venturemarketing.in
piazzatorre.barrettamario.it
type.cookieacademyonline.com
upload.atlasoutfittersk9.com
bot.brigadeirosemdrama.com.br
forms.escoladeautomacao.com.br
onboarding.libertydreamcare.ie
type.talitasouzamarques.com.br
agendamento.sergiolimajr.com.br
anamnese.clinicamegasjdr.com.br
bookings.littlepartymonkeys.com
bot.comercializadoraomicron.com
elevateyourmind.groovepages.com
viewer-v2-typebot-io.vercel.app
yourfeedback.comebackreward.com
bot.cabin-rentals-of-georgia.net
gerador.verificadordehospedes.com
personal-trainer.barrettamario.it
preagendamento.sergiolimajr.com.br
studiotecnicoimmobiliaremerelli.it
download.thailandmicespecialist.com
register.thailandmicespecialist.com
bot.studiotecnicoimmobiliaremerelli.it
pesquisa.escolamodacomproposito.com.br
anamnese.clinicaramosodontologia.com.br
chrome-os-inquiry-system.itschromeos.com
viewer-v2-git-main-typebot-io.vercel.app
main-menu-for-itschromeos.itschromeos.com

@vercel
Copy link

@vercel vercel bot commented on b4536ab Mar 21, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

builder-v2 – ./apps/builder

builder-v2-typebot-io.vercel.app
app.typebot.io
builder-v2-git-main-typebot-io.vercel.app

@vercel
Copy link

@vercel vercel bot commented on b4536ab Mar 21, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.