🐛 (editor) Fix typebot update permissions
This commit is contained in:
@ -1,13 +1,12 @@
|
|||||||
import { CollaborationType, Prisma } from 'db'
|
import { CollaborationType, CollaboratorsOnTypebots, Prisma, User } from 'db'
|
||||||
import prisma from '@/lib/prisma'
|
import prisma from '@/lib/prisma'
|
||||||
import { NextApiRequest, NextApiResponse } from 'next'
|
import { NextApiRequest, NextApiResponse } from 'next'
|
||||||
import { canReadTypebots, canWriteTypebots } from '@/utils/api/dbRules'
|
|
||||||
import { methodNotAllowed, notAuthenticated } from 'utils/api'
|
import { methodNotAllowed, notAuthenticated } from 'utils/api'
|
||||||
import { getAuthenticatedUser } from '@/features/auth/api'
|
import { getAuthenticatedUser } from '@/features/auth/api'
|
||||||
import { archiveResults } from '@/features/results/api'
|
import { archiveResults } from '@/features/results/api'
|
||||||
import { typebotSchema } from 'models'
|
import { Typebot, typebotSchema } from 'models'
|
||||||
import { captureEvent } from '@sentry/nextjs'
|
import { captureEvent } from '@sentry/nextjs'
|
||||||
import { omit } from 'utils'
|
import { isDefined, omit } from 'utils'
|
||||||
|
|
||||||
const handler = async (req: NextApiRequest, res: NextApiResponse) => {
|
const handler = async (req: NextApiRequest, res: NextApiResponse) => {
|
||||||
const user = await getAuthenticatedUser(req)
|
const user = await getAuthenticatedUser(req)
|
||||||
@ -26,15 +25,8 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
|
|||||||
webhooks: true,
|
webhooks: true,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
if (!typebot) return res.send({ typebot: null })
|
if (!typebot || !(await canReadTypebots(typebot, user)))
|
||||||
const memberInWorkspace = await prisma.memberInWorkspace.findFirst({
|
return res.status(404).send({ typebot: null })
|
||||||
where: {
|
|
||||||
workspaceId: typebot.workspaceId,
|
|
||||||
userId: user.id,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
if (process.env.ADMIN_EMAIL !== user.email && !memberInWorkspace)
|
|
||||||
return res.send({ typebot: null })
|
|
||||||
|
|
||||||
const { publishedTypebot, collaborators, webhooks, ...restOfTypebot } =
|
const { publishedTypebot, collaborators, webhooks, ...restOfTypebot } =
|
||||||
typebot
|
typebot
|
||||||
@ -50,6 +42,15 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (req.method === 'DELETE') {
|
if (req.method === 'DELETE') {
|
||||||
|
const typebot = await prisma.typebot.findFirst({
|
||||||
|
where: { id: typebotId },
|
||||||
|
select: {
|
||||||
|
workspaceId: true,
|
||||||
|
collaborators: { select: { userId: true, type: true } },
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if (!typebot || !(await canWriteTypebots(typebot, user)))
|
||||||
|
return res.status(404).send({ typebot: null })
|
||||||
const { success } = await archiveResults({
|
const { success } = await archiveResults({
|
||||||
typebotId,
|
typebotId,
|
||||||
user,
|
user,
|
||||||
@ -57,14 +58,15 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
|
|||||||
})
|
})
|
||||||
if (!success) return res.status(500).send({ success: false })
|
if (!success) return res.status(500).send({ success: false })
|
||||||
await prisma.publicTypebot.deleteMany({
|
await prisma.publicTypebot.deleteMany({
|
||||||
where: { typebot: canWriteTypebots(typebotId, user) },
|
where: { typebotId },
|
||||||
})
|
})
|
||||||
const typebots = await prisma.typebot.updateMany({
|
const typebots = await prisma.typebot.updateMany({
|
||||||
where: canWriteTypebots(typebotId, user),
|
where: { id: typebotId },
|
||||||
data: { isArchived: true, publicId: null },
|
data: { isArchived: true, publicId: null },
|
||||||
})
|
})
|
||||||
return res.send({ typebots })
|
return res.send({ typebots })
|
||||||
}
|
}
|
||||||
|
|
||||||
if (req.method === 'PUT') {
|
if (req.method === 'PUT') {
|
||||||
const data = typeof req.body === 'string' ? JSON.parse(req.body) : req.body
|
const data = typeof req.body === 'string' ? JSON.parse(req.body) : req.body
|
||||||
const parser = typebotSchema.safeParse({
|
const parser = typebotSchema.safeParse({
|
||||||
@ -81,17 +83,22 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
const existingTypebot = await prisma.typebot.findFirst({
|
|
||||||
where: canReadTypebots(typebotId, user),
|
const typebot = await prisma.typebot.findFirst({
|
||||||
select: { updatedAt: true },
|
where: { id: typebotId },
|
||||||
|
select: {
|
||||||
|
updatedAt: true,
|
||||||
|
workspaceId: true,
|
||||||
|
collaborators: { select: { userId: true, type: true } },
|
||||||
|
},
|
||||||
})
|
})
|
||||||
if (
|
if (!typebot || !(await canWriteTypebots(typebot, user)))
|
||||||
existingTypebot &&
|
return res.status(404).send({ message: 'Typebot not found' })
|
||||||
existingTypebot?.updatedAt > new Date(data.updatedAt)
|
|
||||||
)
|
if (typebot.updatedAt > new Date(data.updatedAt))
|
||||||
return res.send({ message: 'Found newer version of typebot in database' })
|
return res.send({ message: 'Found newer version of typebot in database' })
|
||||||
const typebots = await prisma.typebot.updateMany({
|
const typebots = await prisma.typebot.updateMany({
|
||||||
where: canWriteTypebots(typebotId, user),
|
where: { id: typebotId },
|
||||||
data: removeOldProperties({
|
data: removeOldProperties({
|
||||||
...data,
|
...data,
|
||||||
theme: data.theme ?? undefined,
|
theme: data.theme ?? undefined,
|
||||||
@ -101,10 +108,21 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
|
|||||||
})
|
})
|
||||||
return res.send({ typebots })
|
return res.send({ typebots })
|
||||||
}
|
}
|
||||||
|
|
||||||
if (req.method === 'PATCH') {
|
if (req.method === 'PATCH') {
|
||||||
|
const typebot = await prisma.typebot.findFirst({
|
||||||
|
where: { id: typebotId },
|
||||||
|
select: {
|
||||||
|
updatedAt: true,
|
||||||
|
workspaceId: true,
|
||||||
|
collaborators: { select: { userId: true, type: true } },
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if (!typebot || !(await canWriteTypebots(typebot, user)))
|
||||||
|
return res.status(404).send({ message: 'Typebot not found' })
|
||||||
const data = typeof req.body === 'string' ? JSON.parse(req.body) : req.body
|
const data = typeof req.body === 'string' ? JSON.parse(req.body) : req.body
|
||||||
const typebots = await prisma.typebot.updateMany({
|
const typebots = await prisma.typebot.updateMany({
|
||||||
where: canWriteTypebots(typebotId, user),
|
where: { id: typebotId },
|
||||||
data,
|
data,
|
||||||
})
|
})
|
||||||
return res.send({ typebots })
|
return res.send({ typebots })
|
||||||
@ -112,6 +130,50 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
|
|||||||
return methodNotAllowed(res)
|
return methodNotAllowed(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const canReadTypebots = async (
|
||||||
|
typebot: Pick<Typebot, 'workspaceId'> & {
|
||||||
|
collaborators: Pick<CollaboratorsOnTypebots, 'userId' | 'type'>[]
|
||||||
|
},
|
||||||
|
user: Pick<User, 'email' | 'id'>
|
||||||
|
) => {
|
||||||
|
if (
|
||||||
|
process.env.ADMIN_EMAIL === user.email ||
|
||||||
|
typebot.collaborators.find(
|
||||||
|
(collaborator) => collaborator.userId === user.id
|
||||||
|
)
|
||||||
|
)
|
||||||
|
return true
|
||||||
|
const memberInWorkspace = await prisma.memberInWorkspace.findFirst({
|
||||||
|
where: {
|
||||||
|
workspaceId: typebot.workspaceId,
|
||||||
|
userId: user.id,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
return isDefined(memberInWorkspace)
|
||||||
|
}
|
||||||
|
|
||||||
|
const canWriteTypebots = async (
|
||||||
|
typebot: Pick<Typebot, 'workspaceId'> & {
|
||||||
|
collaborators: Pick<CollaboratorsOnTypebots, 'userId' | 'type'>[]
|
||||||
|
},
|
||||||
|
user: Pick<User, 'email' | 'id'>
|
||||||
|
) => {
|
||||||
|
if (
|
||||||
|
process.env.ADMIN_EMAIL === user.email ||
|
||||||
|
typebot.collaborators.find(
|
||||||
|
(collaborator) => collaborator.userId === user.id
|
||||||
|
)?.type === CollaborationType.WRITE
|
||||||
|
)
|
||||||
|
return true
|
||||||
|
const memberInWorkspace = await prisma.memberInWorkspace.findFirst({
|
||||||
|
where: {
|
||||||
|
workspaceId: typebot.workspaceId,
|
||||||
|
userId: user.id,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
return memberInWorkspace && memberInWorkspace?.role !== 'GUEST'
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: Remove in a month
|
// TODO: Remove in a month
|
||||||
const removeOldProperties = (data: unknown) => {
|
const removeOldProperties = (data: unknown) => {
|
||||||
if (data && typeof data === 'object' && 'publishedTypebotId' in data) {
|
if (data && typeof data === 'object' && 'publishedTypebotId' in data) {
|
||||||
|
Reference in New Issue
Block a user