🗃️ Write faster prisma queries
This commit is contained in:
@ -1,6 +1,6 @@
|
|||||||
import { getLinkedTypebots } from '@/features/blocks/logic/typebotLink/api'
|
import { getLinkedTypebots } from '@/features/blocks/logic/typebotLink/api'
|
||||||
import prisma from '@/lib/prisma'
|
import prisma from '@/lib/prisma'
|
||||||
import { canReadTypebot } from '@/utils/api/dbRules'
|
import { canReadTypebots } from '@/utils/api/dbRules'
|
||||||
import { authenticatedProcedure } from '@/utils/server/trpc'
|
import { authenticatedProcedure } from '@/utils/server/trpc'
|
||||||
import { TRPCError } from '@trpc/server'
|
import { TRPCError } from '@trpc/server'
|
||||||
import { Typebot, Webhook } from 'models'
|
import { Typebot, Webhook } from 'models'
|
||||||
@ -40,7 +40,7 @@ export const getResultExampleProcedure = authenticatedProcedure
|
|||||||
)
|
)
|
||||||
.query(async ({ input: { typebotId, blockId }, ctx: { user } }) => {
|
.query(async ({ input: { typebotId, blockId }, ctx: { user } }) => {
|
||||||
const typebot = (await prisma.typebot.findFirst({
|
const typebot = (await prisma.typebot.findFirst({
|
||||||
where: canReadTypebot(typebotId, user),
|
where: canReadTypebots(typebotId, user),
|
||||||
select: {
|
select: {
|
||||||
groups: true,
|
groups: true,
|
||||||
edges: true,
|
edges: true,
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import prisma from '@/lib/prisma'
|
import prisma from '@/lib/prisma'
|
||||||
import { canReadTypebot } from '@/utils/api/dbRules'
|
import { canReadTypebots } from '@/utils/api/dbRules'
|
||||||
import { authenticatedProcedure } from '@/utils/server/trpc'
|
import { authenticatedProcedure } from '@/utils/server/trpc'
|
||||||
import { TRPCError } from '@trpc/server'
|
import { TRPCError } from '@trpc/server'
|
||||||
import { Group, Typebot, Webhook, WebhookBlock } from 'models'
|
import { Group, Typebot, Webhook, WebhookBlock } from 'models'
|
||||||
@ -36,7 +36,7 @@ export const listWebhookBlocksProcedure = authenticatedProcedure
|
|||||||
)
|
)
|
||||||
.query(async ({ input: { typebotId }, ctx: { user } }) => {
|
.query(async ({ input: { typebotId }, ctx: { user } }) => {
|
||||||
const typebot = (await prisma.typebot.findFirst({
|
const typebot = (await prisma.typebot.findFirst({
|
||||||
where: canReadTypebot(typebotId, user),
|
where: canReadTypebots(typebotId, user),
|
||||||
select: {
|
select: {
|
||||||
groups: true,
|
groups: true,
|
||||||
webhooks: true,
|
webhooks: true,
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import prisma from '@/lib/prisma'
|
import prisma from '@/lib/prisma'
|
||||||
import { canWriteTypebot } from '@/utils/api/dbRules'
|
import { canWriteTypebots } from '@/utils/api/dbRules'
|
||||||
import { authenticatedProcedure } from '@/utils/server/trpc'
|
import { authenticatedProcedure } from '@/utils/server/trpc'
|
||||||
import { TRPCError } from '@trpc/server'
|
import { TRPCError } from '@trpc/server'
|
||||||
import { Typebot, Webhook, WebhookBlock } from 'models'
|
import { Typebot, Webhook, WebhookBlock } from 'models'
|
||||||
@ -31,7 +31,7 @@ export const subscribeWebhookProcedure = authenticatedProcedure
|
|||||||
)
|
)
|
||||||
.query(async ({ input: { typebotId, blockId, url }, ctx: { user } }) => {
|
.query(async ({ input: { typebotId, blockId, url }, ctx: { user } }) => {
|
||||||
const typebot = (await prisma.typebot.findFirst({
|
const typebot = (await prisma.typebot.findFirst({
|
||||||
where: canWriteTypebot(typebotId, user),
|
where: canWriteTypebots(typebotId, user),
|
||||||
select: {
|
select: {
|
||||||
groups: true,
|
groups: true,
|
||||||
webhooks: true,
|
webhooks: true,
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import prisma from '@/lib/prisma'
|
import prisma from '@/lib/prisma'
|
||||||
import { canWriteTypebot } from '@/utils/api/dbRules'
|
import { canWriteTypebots } from '@/utils/api/dbRules'
|
||||||
import { authenticatedProcedure } from '@/utils/server/trpc'
|
import { authenticatedProcedure } from '@/utils/server/trpc'
|
||||||
import { TRPCError } from '@trpc/server'
|
import { TRPCError } from '@trpc/server'
|
||||||
import { Typebot, Webhook, WebhookBlock } from 'models'
|
import { Typebot, Webhook, WebhookBlock } from 'models'
|
||||||
@ -30,7 +30,7 @@ export const unsubscribeWebhookProcedure = authenticatedProcedure
|
|||||||
)
|
)
|
||||||
.query(async ({ input: { typebotId, blockId }, ctx: { user } }) => {
|
.query(async ({ input: { typebotId, blockId }, ctx: { user } }) => {
|
||||||
const typebot = (await prisma.typebot.findFirst({
|
const typebot = (await prisma.typebot.findFirst({
|
||||||
where: canWriteTypebot(typebotId, user),
|
where: canWriteTypebots(typebotId, user),
|
||||||
select: {
|
select: {
|
||||||
groups: true,
|
groups: true,
|
||||||
webhooks: true,
|
webhooks: true,
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import prisma from '@/lib/prisma'
|
import prisma from '@/lib/prisma'
|
||||||
import { canWriteTypebot } from '@/utils/api/dbRules'
|
import { canWriteTypebots } from '@/utils/api/dbRules'
|
||||||
import { deleteFiles } from '@/utils/api/storage'
|
import { deleteFiles } from '@/utils/api/storage'
|
||||||
import { User, Prisma } from 'db'
|
import { User, Prisma } from 'db'
|
||||||
import { InputBlockType, Typebot } from 'models'
|
import { InputBlockType, Typebot } from 'models'
|
||||||
@ -14,7 +14,7 @@ export const archiveResults = async ({
|
|||||||
resultsFilter?: Prisma.ResultWhereInput
|
resultsFilter?: Prisma.ResultWhereInput
|
||||||
}) => {
|
}) => {
|
||||||
const typebot = await prisma.typebot.findFirst({
|
const typebot = await prisma.typebot.findFirst({
|
||||||
where: canWriteTypebot(typebotId, user),
|
where: canWriteTypebots(typebotId, user),
|
||||||
select: { groups: true },
|
select: { groups: true },
|
||||||
})
|
})
|
||||||
if (!typebot) return { success: false }
|
if (!typebot) return { success: false }
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { canWriteTypebot } from '@/utils/api/dbRules'
|
import { canWriteTypebots } from '@/utils/api/dbRules'
|
||||||
import { authenticatedProcedure } from '@/utils/server/trpc'
|
import { authenticatedProcedure } from '@/utils/server/trpc'
|
||||||
import { TRPCError } from '@trpc/server'
|
import { TRPCError } from '@trpc/server'
|
||||||
import { z } from 'zod'
|
import { z } from 'zod'
|
||||||
@ -34,7 +34,7 @@ export const deleteResultsProcedure = authenticatedProcedure
|
|||||||
user,
|
user,
|
||||||
resultsFilter: {
|
resultsFilter: {
|
||||||
id: (idsArray?.length ?? 0) > 0 ? { in: idsArray } : undefined,
|
id: (idsArray?.length ?? 0) > 0 ? { in: idsArray } : undefined,
|
||||||
typebot: canWriteTypebot(typebotId, user),
|
typebot: canWriteTypebots(typebotId, user),
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import prisma from '@/lib/prisma'
|
import prisma from '@/lib/prisma'
|
||||||
import { canReadTypebot } from '@/utils/api/dbRules'
|
import { canReadTypebots } from '@/utils/api/dbRules'
|
||||||
import { authenticatedProcedure } from '@/utils/server/trpc'
|
import { authenticatedProcedure } from '@/utils/server/trpc'
|
||||||
import { logSchema } from 'models'
|
import { logSchema } from 'models'
|
||||||
import { z } from 'zod'
|
import { z } from 'zod'
|
||||||
@ -22,9 +22,14 @@ export const getResultLogsProcedure = authenticatedProcedure
|
|||||||
)
|
)
|
||||||
.output(z.object({ logs: z.array(logSchema) }))
|
.output(z.object({ logs: z.array(logSchema) }))
|
||||||
.query(async ({ input: { typebotId, resultId }, ctx: { user } }) => {
|
.query(async ({ input: { typebotId, resultId }, ctx: { user } }) => {
|
||||||
|
const typebot = await prisma.typebot.findFirst({
|
||||||
|
where: canReadTypebots(typebotId, user),
|
||||||
|
select: { id: true },
|
||||||
|
})
|
||||||
|
if (!typebot) throw new Error('Typebot not found')
|
||||||
const logs = await prisma.log.findMany({
|
const logs = await prisma.log.findMany({
|
||||||
where: {
|
where: {
|
||||||
result: { id: resultId, typebot: canReadTypebot(typebotId, user) },
|
result: { id: resultId, typebotId: typebot.id },
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import prisma from '@/lib/prisma'
|
import prisma from '@/lib/prisma'
|
||||||
import { canReadTypebot } from '@/utils/api/dbRules'
|
import { canReadTypebots } from '@/utils/api/dbRules'
|
||||||
import { authenticatedProcedure } from '@/utils/server/trpc'
|
import { authenticatedProcedure } from '@/utils/server/trpc'
|
||||||
import { TRPCError } from '@trpc/server'
|
import { TRPCError } from '@trpc/server'
|
||||||
import { ResultWithAnswers, resultWithAnswersSchema } from 'models'
|
import { ResultWithAnswers, resultWithAnswersSchema } from 'models'
|
||||||
@ -38,11 +38,17 @@ export const getResultsProcedure = authenticatedProcedure
|
|||||||
message: 'limit must be between 1 and 200',
|
message: 'limit must be between 1 and 200',
|
||||||
})
|
})
|
||||||
const { cursor } = input
|
const { cursor } = input
|
||||||
|
const typebot = await prisma.typebot.findFirst({
|
||||||
|
where: canReadTypebots(input.typebotId, user),
|
||||||
|
select: { id: true },
|
||||||
|
})
|
||||||
|
if (!typebot)
|
||||||
|
throw new TRPCError({ code: 'NOT_FOUND', message: 'Typebot not found' })
|
||||||
const results = (await prisma.result.findMany({
|
const results = (await prisma.result.findMany({
|
||||||
take: limit + 1,
|
take: limit + 1,
|
||||||
cursor: cursor ? { id: cursor } : undefined,
|
cursor: cursor ? { id: cursor } : undefined,
|
||||||
where: {
|
where: {
|
||||||
typebot: canReadTypebot(input.typebotId, user),
|
typebotId: typebot.id,
|
||||||
answers: { some: {} },
|
answers: { some: {} },
|
||||||
},
|
},
|
||||||
orderBy: {
|
orderBy: {
|
||||||
|
@ -2,7 +2,7 @@ import { withSentry } from '@sentry/nextjs'
|
|||||||
import prisma from '@/lib/prisma'
|
import prisma from '@/lib/prisma'
|
||||||
import { InputBlockType, PublicTypebot } from 'models'
|
import { InputBlockType, PublicTypebot } from 'models'
|
||||||
import { NextApiRequest, NextApiResponse } from 'next'
|
import { NextApiRequest, NextApiResponse } from 'next'
|
||||||
import { canPublishFileInput, canWriteTypebot } from '@/utils/api/dbRules'
|
import { canPublishFileInput, canWriteTypebots } from '@/utils/api/dbRules'
|
||||||
import { getAuthenticatedUser } from '@/features/auth/api'
|
import { getAuthenticatedUser } from '@/features/auth/api'
|
||||||
import { badRequest, methodNotAllowed, notAuthenticated } from 'utils/api'
|
import { badRequest, methodNotAllowed, notAuthenticated } from 'utils/api'
|
||||||
|
|
||||||
@ -39,7 +39,7 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
|
|||||||
await prisma.publicTypebot.deleteMany({
|
await prisma.publicTypebot.deleteMany({
|
||||||
where: {
|
where: {
|
||||||
id: publishedTypebotId,
|
id: publishedTypebotId,
|
||||||
typebot: canWriteTypebot(typebotId, user),
|
typebot: canWriteTypebots(typebotId, user),
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
return res.send({ success: true })
|
return res.send({ success: true })
|
||||||
|
@ -2,7 +2,7 @@ import { withSentry } from '@sentry/nextjs'
|
|||||||
import { CollaborationType } from 'db'
|
import { CollaborationType } from 'db'
|
||||||
import prisma from '@/lib/prisma'
|
import prisma from '@/lib/prisma'
|
||||||
import { NextApiRequest, NextApiResponse } from 'next'
|
import { NextApiRequest, NextApiResponse } from 'next'
|
||||||
import { canReadTypebot, canWriteTypebot } from '@/utils/api/dbRules'
|
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'
|
||||||
@ -15,7 +15,7 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
|
|||||||
if (req.method === 'GET') {
|
if (req.method === 'GET') {
|
||||||
const typebot = await prisma.typebot.findFirst({
|
const typebot = await prisma.typebot.findFirst({
|
||||||
where: {
|
where: {
|
||||||
...canReadTypebot(typebotId, user),
|
...canReadTypebots(typebotId, user),
|
||||||
isArchived: { not: true },
|
isArchived: { not: true },
|
||||||
},
|
},
|
||||||
include: {
|
include: {
|
||||||
@ -46,10 +46,10 @@ 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: canWriteTypebot(typebotId, user) },
|
where: { typebot: canWriteTypebots(typebotId, user) },
|
||||||
})
|
})
|
||||||
const typebots = await prisma.typebot.updateMany({
|
const typebots = await prisma.typebot.updateMany({
|
||||||
where: canWriteTypebot(typebotId, user),
|
where: canWriteTypebots(typebotId, user),
|
||||||
data: { isArchived: true },
|
data: { isArchived: true },
|
||||||
})
|
})
|
||||||
return res.send({ typebots })
|
return res.send({ typebots })
|
||||||
@ -57,7 +57,8 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
|
|||||||
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 existingTypebot = await prisma.typebot.findFirst({
|
const existingTypebot = await prisma.typebot.findFirst({
|
||||||
where: canReadTypebot(typebotId, user),
|
where: canReadTypebots(typebotId, user),
|
||||||
|
select: { updatedAt: true },
|
||||||
})
|
})
|
||||||
if (
|
if (
|
||||||
existingTypebot &&
|
existingTypebot &&
|
||||||
@ -65,7 +66,7 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
|
|||||||
)
|
)
|
||||||
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: canWriteTypebot(typebotId, user),
|
where: canWriteTypebots(typebotId, user),
|
||||||
data: {
|
data: {
|
||||||
...data,
|
...data,
|
||||||
theme: data.theme ?? undefined,
|
theme: data.theme ?? undefined,
|
||||||
@ -78,7 +79,7 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
|
|||||||
if (req.method === 'PATCH') {
|
if (req.method === 'PATCH') {
|
||||||
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: canWriteTypebot(typebotId, user),
|
where: canWriteTypebots(typebotId, user),
|
||||||
data,
|
data,
|
||||||
})
|
})
|
||||||
return res.send({ typebots })
|
return res.send({ typebots })
|
||||||
|
@ -4,7 +4,7 @@ import { NextApiRequest, NextApiResponse } from 'next'
|
|||||||
import { methodNotAllowed, notAuthenticated } from 'utils/api'
|
import { methodNotAllowed, notAuthenticated } from 'utils/api'
|
||||||
import { withSentry } from '@sentry/nextjs'
|
import { withSentry } from '@sentry/nextjs'
|
||||||
import { getAuthenticatedUser } from '@/features/auth/api'
|
import { getAuthenticatedUser } from '@/features/auth/api'
|
||||||
import { canReadTypebot } from '@/utils/api/dbRules'
|
import { canReadTypebots } from '@/utils/api/dbRules'
|
||||||
|
|
||||||
const handler = async (req: NextApiRequest, res: NextApiResponse) => {
|
const handler = async (req: NextApiRequest, res: NextApiResponse) => {
|
||||||
const user = await getAuthenticatedUser(req)
|
const user = await getAuthenticatedUser(req)
|
||||||
@ -12,8 +12,8 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
|
|||||||
if (req.method === 'GET') {
|
if (req.method === 'GET') {
|
||||||
const typebotId = req.query.typebotId as string
|
const typebotId = req.query.typebotId as string
|
||||||
const typebot = await prisma.typebot.findFirst({
|
const typebot = await prisma.typebot.findFirst({
|
||||||
where: canReadTypebot(typebotId, user),
|
where: canReadTypebots(typebotId, user),
|
||||||
include: { publishedTypebot: true },
|
select: { publishedTypebot: true },
|
||||||
})
|
})
|
||||||
const publishedTypebot =
|
const publishedTypebot =
|
||||||
typebot?.publishedTypebot as unknown as PublicTypebot
|
typebot?.publishedTypebot as unknown as PublicTypebot
|
||||||
|
@ -2,7 +2,7 @@ import { withSentry } from '@sentry/nextjs'
|
|||||||
import prisma from '@/lib/prisma'
|
import prisma from '@/lib/prisma'
|
||||||
import { Stats } from 'models'
|
import { Stats } from 'models'
|
||||||
import { NextApiRequest, NextApiResponse } from 'next'
|
import { NextApiRequest, NextApiResponse } from 'next'
|
||||||
import { canReadTypebot } from '@/utils/api/dbRules'
|
import { canReadTypebots } from '@/utils/api/dbRules'
|
||||||
import { getAuthenticatedUser } from '@/features/auth/api'
|
import { getAuthenticatedUser } from '@/features/auth/api'
|
||||||
import { methodNotAllowed, notAuthenticated } from 'utils/api'
|
import { methodNotAllowed, notAuthenticated } from 'utils/api'
|
||||||
|
|
||||||
@ -12,23 +12,27 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
|
|||||||
if (req.method === 'GET') {
|
if (req.method === 'GET') {
|
||||||
const typebotId = req.query.typebotId as string
|
const typebotId = req.query.typebotId as string
|
||||||
|
|
||||||
|
const typebot = await prisma.typebot.findFirst({
|
||||||
|
where: canReadTypebots(typebotId, user),
|
||||||
|
select: { id: true },
|
||||||
|
})
|
||||||
|
|
||||||
|
if (!typebot) return res.status(404).send({ message: 'Typebot not found' })
|
||||||
|
|
||||||
const totalViews = await prisma.result.count({
|
const totalViews = await prisma.result.count({
|
||||||
where: {
|
where: {
|
||||||
typebotId,
|
typebotId: typebot.id,
|
||||||
typebot: canReadTypebot(typebotId, user),
|
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
const totalStarts = await prisma.result.count({
|
const totalStarts = await prisma.result.count({
|
||||||
where: {
|
where: {
|
||||||
typebotId,
|
typebotId: typebot.id,
|
||||||
typebot: canReadTypebot(typebotId, user),
|
|
||||||
answers: { some: {} },
|
answers: { some: {} },
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
const totalCompleted = await prisma.result.count({
|
const totalCompleted = await prisma.result.count({
|
||||||
where: {
|
where: {
|
||||||
typebotId,
|
typebotId: typebot.id,
|
||||||
typebot: canReadTypebot(typebotId, user),
|
|
||||||
isCompleted: true,
|
isCompleted: true,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { withSentry } from '@sentry/nextjs'
|
import { withSentry } from '@sentry/nextjs'
|
||||||
import prisma from '@/lib/prisma'
|
import prisma from '@/lib/prisma'
|
||||||
import { NextApiRequest, NextApiResponse } from 'next'
|
import { NextApiRequest, NextApiResponse } from 'next'
|
||||||
import { canReadTypebot } from '@/utils/api/dbRules'
|
import { canReadTypebots } from '@/utils/api/dbRules'
|
||||||
import { getAuthenticatedUser } from '@/features/auth/api'
|
import { getAuthenticatedUser } from '@/features/auth/api'
|
||||||
import { methodNotAllowed, notAuthenticated, notFound } from 'utils/api'
|
import { methodNotAllowed, notAuthenticated, notFound } from 'utils/api'
|
||||||
|
|
||||||
@ -11,7 +11,8 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
|
|||||||
if (req.method === 'GET') {
|
if (req.method === 'GET') {
|
||||||
const typebotId = req.query.typebotId as string
|
const typebotId = req.query.typebotId as string
|
||||||
const typebot = await prisma.typebot.findFirst({
|
const typebot = await prisma.typebot.findFirst({
|
||||||
where: canReadTypebot(typebotId, user),
|
where: canReadTypebots(typebotId, user),
|
||||||
|
select: { groups: true },
|
||||||
})
|
})
|
||||||
if (!typebot) return notFound(res)
|
if (!typebot) return notFound(res)
|
||||||
return res.send({ groups: typebot.groups })
|
return res.send({ groups: typebot.groups })
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { withSentry } from '@sentry/nextjs'
|
import { withSentry } from '@sentry/nextjs'
|
||||||
import prisma from '@/lib/prisma'
|
import prisma from '@/lib/prisma'
|
||||||
import { NextApiRequest, NextApiResponse } from 'next'
|
import { NextApiRequest, NextApiResponse } from 'next'
|
||||||
import { canReadTypebot } from '@/utils/api/dbRules'
|
import { canReadTypebots } from '@/utils/api/dbRules'
|
||||||
import { getAuthenticatedUser } from '@/features/auth/api'
|
import { getAuthenticatedUser } from '@/features/auth/api'
|
||||||
import { methodNotAllowed, notAuthenticated } from 'utils/api'
|
import { methodNotAllowed, notAuthenticated } from 'utils/api'
|
||||||
|
|
||||||
@ -11,7 +11,7 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
|
|||||||
const typebotId = req.query.typebotId as string
|
const typebotId = req.query.typebotId as string
|
||||||
if (req.method === 'GET') {
|
if (req.method === 'GET') {
|
||||||
const collaborators = await prisma.collaboratorsOnTypebots.findMany({
|
const collaborators = await prisma.collaboratorsOnTypebots.findMany({
|
||||||
where: { typebot: canReadTypebot(typebotId, user) },
|
where: { typebot: canReadTypebots(typebotId, user) },
|
||||||
include: { user: { select: { name: true, image: true, email: true } } },
|
include: { user: { select: { name: true, image: true, email: true } } },
|
||||||
})
|
})
|
||||||
return res.send({
|
return res.send({
|
||||||
|
@ -2,7 +2,7 @@ import { withSentry } from '@sentry/nextjs'
|
|||||||
import { CollaborationType, WorkspaceRole } from 'db'
|
import { CollaborationType, WorkspaceRole } from 'db'
|
||||||
import prisma from '@/lib/prisma'
|
import prisma from '@/lib/prisma'
|
||||||
import { NextApiRequest, NextApiResponse } from 'next'
|
import { NextApiRequest, NextApiResponse } from 'next'
|
||||||
import { canReadTypebot, canWriteTypebot } from '@/utils/api/dbRules'
|
import { canReadTypebots, canWriteTypebots } from '@/utils/api/dbRules'
|
||||||
import {
|
import {
|
||||||
badRequest,
|
badRequest,
|
||||||
forbidden,
|
forbidden,
|
||||||
@ -19,7 +19,7 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
|
|||||||
const typebotId = req.query.typebotId as string
|
const typebotId = req.query.typebotId as string
|
||||||
if (req.method === 'GET') {
|
if (req.method === 'GET') {
|
||||||
const invitations = await prisma.invitation.findMany({
|
const invitations = await prisma.invitation.findMany({
|
||||||
where: { typebotId, typebot: canReadTypebot(typebotId, user) },
|
where: { typebotId, typebot: canReadTypebots(typebotId, user) },
|
||||||
})
|
})
|
||||||
return res.send({
|
return res.send({
|
||||||
invitations,
|
invitations,
|
||||||
@ -27,7 +27,7 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
|
|||||||
}
|
}
|
||||||
if (req.method === 'POST') {
|
if (req.method === 'POST') {
|
||||||
const typebot = await prisma.typebot.findFirst({
|
const typebot = await prisma.typebot.findFirst({
|
||||||
where: canWriteTypebot(typebotId, user),
|
where: canWriteTypebots(typebotId, user),
|
||||||
include: { workspace: { select: { name: true } } },
|
include: { workspace: { select: { name: true } } },
|
||||||
})
|
})
|
||||||
if (!typebot || !typebot.workspaceId) return forbidden(res)
|
if (!typebot || !typebot.workspaceId) return forbidden(res)
|
||||||
|
@ -2,7 +2,7 @@ import { withSentry } from '@sentry/nextjs'
|
|||||||
import prisma from '@/lib/prisma'
|
import prisma from '@/lib/prisma'
|
||||||
import { defaultWebhookAttributes } from 'models'
|
import { defaultWebhookAttributes } from 'models'
|
||||||
import { NextApiRequest, NextApiResponse } from 'next'
|
import { NextApiRequest, NextApiResponse } from 'next'
|
||||||
import { canWriteTypebot } from '@/utils/api/dbRules'
|
import { canWriteTypebots } from '@/utils/api/dbRules'
|
||||||
import { getAuthenticatedUser } from '@/features/auth/api'
|
import { getAuthenticatedUser } from '@/features/auth/api'
|
||||||
import { forbidden, methodNotAllowed, notAuthenticated } from 'utils/api'
|
import { forbidden, methodNotAllowed, notAuthenticated } from 'utils/api'
|
||||||
|
|
||||||
@ -12,7 +12,8 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
|
|||||||
if (req.method === 'POST') {
|
if (req.method === 'POST') {
|
||||||
const typebotId = req.query.typebotId as string
|
const typebotId = req.query.typebotId as string
|
||||||
const typebot = await prisma.typebot.findFirst({
|
const typebot = await prisma.typebot.findFirst({
|
||||||
where: canWriteTypebot(typebotId, user),
|
where: canWriteTypebots(typebotId, user),
|
||||||
|
select: { id: true },
|
||||||
})
|
})
|
||||||
if (!typebot) return forbidden(res)
|
if (!typebot) return forbidden(res)
|
||||||
const webhook = await prisma.webhook.create({
|
const webhook = await prisma.webhook.create({
|
||||||
|
@ -11,21 +11,30 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
|
|||||||
const workspaceId = req.query.workspaceId as string
|
const workspaceId = req.query.workspaceId as string
|
||||||
const now = new Date()
|
const now = new Date()
|
||||||
const firstDayOfMonth = new Date(now.getFullYear(), now.getMonth(), 1)
|
const firstDayOfMonth = new Date(now.getFullYear(), now.getMonth(), 1)
|
||||||
const lastDayOfMonth = new Date(now.getFullYear(), now.getMonth() + 1, 1)
|
const firstDayOfNextMonth = new Date(
|
||||||
const totalChatsUsed = await prisma.result.count({
|
now.getFullYear(),
|
||||||
where: {
|
now.getMonth() + 1,
|
||||||
typebot: {
|
1
|
||||||
|
)
|
||||||
|
const totalChatsUsed = await prisma.$transaction(async (tx) => {
|
||||||
|
const typebots = await tx.typebot.findMany({
|
||||||
|
where: {
|
||||||
workspace: {
|
workspace: {
|
||||||
id: workspaceId,
|
id: workspaceId,
|
||||||
members: { some: { userId: user.id } },
|
members: { some: { userId: user.id } },
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
hasStarted: true,
|
})
|
||||||
createdAt: {
|
return tx.result.count({
|
||||||
gte: firstDayOfMonth,
|
where: {
|
||||||
lte: lastDayOfMonth,
|
typebotId: { in: typebots.map((typebot) => typebot.id) },
|
||||||
|
hasStarted: true,
|
||||||
|
createdAt: {
|
||||||
|
gte: firstDayOfMonth,
|
||||||
|
lt: firstDayOfNextMonth,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
})
|
||||||
})
|
})
|
||||||
const {
|
const {
|
||||||
_sum: { storageUsed: totalStorageUsed },
|
_sum: { storageUsed: totalStorageUsed },
|
||||||
|
@ -1,50 +1,37 @@
|
|||||||
import { CollaborationType, Plan, Prisma, User, WorkspaceRole } from 'db'
|
import { Plan, Prisma, User, WorkspaceRole } from 'db'
|
||||||
import prisma from '@/lib/prisma'
|
import prisma from '@/lib/prisma'
|
||||||
import { NextApiResponse } from 'next'
|
import { NextApiResponse } from 'next'
|
||||||
import { env, isNotEmpty } from 'utils'
|
import { env, isNotEmpty } from 'utils'
|
||||||
import { forbidden } from 'utils/api'
|
import { forbidden } from 'utils/api'
|
||||||
|
|
||||||
const parseWhereFilter = (
|
export const canWriteTypebots = (
|
||||||
typebotIds: string[] | string,
|
typebotIds: string[] | string,
|
||||||
user: User,
|
user: Pick<User, 'email' | 'id'>
|
||||||
type: 'read' | 'write'
|
|
||||||
): Prisma.TypebotWhereInput => ({
|
): Prisma.TypebotWhereInput => ({
|
||||||
OR: [
|
id: typeof typebotIds === 'string' ? typebotIds : { in: typebotIds },
|
||||||
{
|
workspace: isNotEmpty(env('E2E_TEST'))
|
||||||
id: typeof typebotIds === 'string' ? typebotIds : { in: typebotIds },
|
? undefined
|
||||||
collaborators: {
|
: {
|
||||||
some: {
|
members: {
|
||||||
userId: user.id,
|
some: { userId: user.id, role: { not: WorkspaceRole.GUEST } },
|
||||||
type: type === 'write' ? CollaborationType.WRITE : undefined,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
|
||||||
{
|
|
||||||
id: typeof typebotIds === 'string' ? typebotIds : { in: typebotIds },
|
|
||||||
workspace:
|
|
||||||
(type === 'read' && user.email === process.env.ADMIN_EMAIL) ||
|
|
||||||
isNotEmpty(env('E2E_TEST'))
|
|
||||||
? undefined
|
|
||||||
: {
|
|
||||||
members: {
|
|
||||||
some: { userId: user.id, role: { not: WorkspaceRole.GUEST } },
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
})
|
})
|
||||||
|
|
||||||
export const canReadTypebot = (typebotId: string, user: User) =>
|
export const canReadTypebots = (
|
||||||
parseWhereFilter(typebotId, user, 'read')
|
typebotIds: string | string[],
|
||||||
|
user: Pick<User, 'email' | 'id'>
|
||||||
export const canWriteTypebot = (typebotId: string, user: User) =>
|
) => ({
|
||||||
parseWhereFilter(typebotId, user, 'write')
|
id: typeof typebotIds === 'string' ? typebotIds : { in: typebotIds },
|
||||||
|
workspace:
|
||||||
export const canReadTypebots = (typebotIds: string[], user: User) =>
|
user.email === process.env.ADMIN_EMAIL || isNotEmpty(env('E2E_TEST'))
|
||||||
parseWhereFilter(typebotIds, user, 'read')
|
? undefined
|
||||||
|
: {
|
||||||
export const canWriteTypebots = (typebotIds: string[], user: User) =>
|
members: {
|
||||||
parseWhereFilter(typebotIds, user, 'write')
|
some: { userId: user.id },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
export const canEditGuests = (user: User, typebotId: string) => ({
|
export const canEditGuests = (user: User, typebotId: string) => ({
|
||||||
id: typebotId,
|
id: typebotId,
|
||||||
|
@ -32,7 +32,7 @@ const handler = async (
|
|||||||
const typebotId = req.query.typebotId as string
|
const typebotId = req.query.typebotId as string
|
||||||
const blockId = req.query.blockId as string
|
const blockId = req.query.blockId as string
|
||||||
if (!filePath) return badRequest(res, 'Missing filePath or fileType')
|
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({
|
const typebot = (await prisma.publicTypebot.findFirst({
|
||||||
where: { typebotId },
|
where: { typebotId },
|
||||||
})) as unknown as PublicTypebot
|
})) as unknown as PublicTypebot
|
||||||
@ -53,14 +53,14 @@ const handler = async (
|
|||||||
|
|
||||||
return res.status(200).send({
|
return res.status(200).send({
|
||||||
presignedUrl,
|
presignedUrl,
|
||||||
hasReachedStorageLimit: false,
|
hasReachedStorageLimit,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return methodNotAllowed(res)
|
return methodNotAllowed(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
const checkStorageLimit = async (typebotId: string): Promise<boolean> => {
|
const checkStorageLimit = async (typebotId: string): Promise<boolean> => {
|
||||||
const typebot = await prisma.typebot.findFirst({
|
const typebot = await prisma.typebot.findUnique({
|
||||||
where: { id: typebotId },
|
where: { id: typebotId },
|
||||||
include: {
|
include: {
|
||||||
workspace: {
|
workspace: {
|
||||||
@ -84,9 +84,7 @@ const checkStorageLimit = async (typebotId: string): Promise<boolean> => {
|
|||||||
storageUsed: { gt: 0 },
|
storageUsed: { gt: 0 },
|
||||||
result: {
|
result: {
|
||||||
typebot: {
|
typebot: {
|
||||||
workspace: {
|
workspaceId: typebot.workspaceId,
|
||||||
id: typebot?.workspaceId,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -5,7 +5,7 @@ import {
|
|||||||
sendAlmostReachedChatsLimitEmail,
|
sendAlmostReachedChatsLimitEmail,
|
||||||
sendReachedChatsLimitEmail,
|
sendReachedChatsLimitEmail,
|
||||||
} from 'emails'
|
} from 'emails'
|
||||||
import { ResultWithAnswers, Workspace } from 'models'
|
import { ResultWithAnswers } from 'models'
|
||||||
import { NextApiRequest, NextApiResponse } from 'next'
|
import { NextApiRequest, NextApiResponse } from 'next'
|
||||||
import { env, getChatsLimit, isDefined } from 'utils'
|
import { env, getChatsLimit, isDefined } from 'utils'
|
||||||
import { methodNotAllowed } from 'utils/api'
|
import { methodNotAllowed } from 'utils/api'
|
||||||
@ -33,58 +33,63 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
|
|||||||
}
|
}
|
||||||
if (req.method === 'POST') {
|
if (req.method === 'POST') {
|
||||||
const typebotId = req.query.typebotId as string
|
const typebotId = req.query.typebotId as string
|
||||||
|
const hasReachedLimit = await checkChatsUsage(typebotId)
|
||||||
|
if (hasReachedLimit) return res.send({ result: null, hasReachedLimit })
|
||||||
const result = await prisma.result.create({
|
const result = await prisma.result.create({
|
||||||
data: {
|
data: {
|
||||||
typebotId,
|
typebotId,
|
||||||
isCompleted: false,
|
isCompleted: false,
|
||||||
},
|
},
|
||||||
include: {
|
|
||||||
typebot: {
|
|
||||||
include: {
|
|
||||||
workspace: {
|
|
||||||
select: {
|
|
||||||
id: true,
|
|
||||||
plan: true,
|
|
||||||
additionalChatsIndex: true,
|
|
||||||
chatsLimitFirstEmailSentAt: true,
|
|
||||||
chatsLimitSecondEmailSentAt: true,
|
|
||||||
customChatsLimit: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
// const hasReachedLimit = await checkChatsUsage(result.typebot.workspace)
|
res.send({ result })
|
||||||
res.send({ result, hasReachedLimit: false })
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
methodNotAllowed(res)
|
methodNotAllowed(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
const checkChatsUsage = async (
|
const checkChatsUsage = async (typebotId: string) => {
|
||||||
workspace: Pick<
|
const typebot = await prisma.typebot.findUnique({
|
||||||
Workspace,
|
where: {
|
||||||
| 'id'
|
id: typebotId,
|
||||||
| 'plan'
|
},
|
||||||
| 'additionalChatsIndex'
|
include: {
|
||||||
| 'chatsLimitFirstEmailSentAt'
|
workspace: {
|
||||||
| 'chatsLimitSecondEmailSentAt'
|
select: {
|
||||||
| 'customChatsLimit'
|
id: true,
|
||||||
>
|
plan: true,
|
||||||
) => {
|
additionalChatsIndex: true,
|
||||||
|
chatsLimitFirstEmailSentAt: true,
|
||||||
|
chatsLimitSecondEmailSentAt: true,
|
||||||
|
customChatsLimit: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const workspace = typebot?.workspace
|
||||||
|
|
||||||
|
if (!workspace) return false
|
||||||
|
|
||||||
const chatsLimit = getChatsLimit(workspace)
|
const chatsLimit = getChatsLimit(workspace)
|
||||||
if (chatsLimit === -1) return
|
if (chatsLimit === -1) return
|
||||||
const now = new Date()
|
const now = new Date()
|
||||||
const firstDayOfMonth = new Date(now.getFullYear(), now.getMonth(), 1)
|
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 firstDayOfNextMonth = new Date(now.getFullYear(), now.getMonth() + 1, 1)
|
||||||
const chatsCount = await prisma.result.count({
|
const chatsCount = await prisma.$transaction(async (tx) => {
|
||||||
where: {
|
const typebotIds = await tx.typebot.findMany({
|
||||||
typebot: { workspaceId: workspace.id },
|
where: {
|
||||||
hasStarted: true,
|
workspaceId: workspace.id,
|
||||||
createdAt: { gte: firstDayOfMonth, lte: lastDayOfMonth },
|
},
|
||||||
},
|
select: { id: true },
|
||||||
|
})
|
||||||
|
|
||||||
|
return tx.result.count({
|
||||||
|
where: {
|
||||||
|
typebotId: { in: typebotIds.map((typebot) => typebot.id) },
|
||||||
|
hasStarted: true,
|
||||||
|
createdAt: { gte: firstDayOfMonth, lte: firstDayOfNextMonth },
|
||||||
|
},
|
||||||
|
})
|
||||||
})
|
})
|
||||||
const hasSentFirstEmail =
|
const hasSentFirstEmail =
|
||||||
workspace.chatsLimitFirstEmailSentAt !== null &&
|
workspace.chatsLimitFirstEmailSentAt !== null &&
|
||||||
|
@ -0,0 +1,2 @@
|
|||||||
|
-- CreateIndex
|
||||||
|
CREATE INDEX IF NOT EXISTS "Result_typebotId_idx" ON "Result"("typebotId");
|
@ -224,6 +224,7 @@ model Result {
|
|||||||
answers Answer[]
|
answers Answer[]
|
||||||
logs Log[]
|
logs Log[]
|
||||||
|
|
||||||
|
@@index([typebotId])
|
||||||
@@index([typebotId, createdAt])
|
@@index([typebotId, createdAt])
|
||||||
@@index([createdAt, typebotId])
|
@@index([createdAt, typebotId])
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,90 @@
|
|||||||
import { PrismaClient } from 'db'
|
import { Prisma, PrismaClient, User, WorkspaceRole } from 'db'
|
||||||
|
import { env, isNotEmpty } from 'utils'
|
||||||
import { promptAndSetEnvironment } from './utils'
|
import { promptAndSetEnvironment } from './utils'
|
||||||
|
|
||||||
const executePlayground = async () => {
|
const executePlayground = async () => {
|
||||||
await promptAndSetEnvironment()
|
await promptAndSetEnvironment()
|
||||||
const prisma = new PrismaClient({ log: ['query', 'info', 'warn', 'error'] })
|
const prisma = new PrismaClient({
|
||||||
|
log: [{ emit: 'event', level: 'query' }, 'info', 'warn', 'error'],
|
||||||
|
})
|
||||||
|
|
||||||
|
prisma.$on('query', (e) => {
|
||||||
|
console.log(e.query)
|
||||||
|
console.log(e.params)
|
||||||
|
console.log(e.duration, 'ms')
|
||||||
|
})
|
||||||
|
const now = new Date()
|
||||||
|
|
||||||
|
const typebot = await prisma.typebot.findFirst({
|
||||||
|
where: parseReadFilter('6rw8KvRZe7UbHcJrs8Ui4S', {
|
||||||
|
email: '',
|
||||||
|
id: 'ckzmhmiey001009mnzt5nkxu8',
|
||||||
|
}),
|
||||||
|
select: { id: true },
|
||||||
|
})
|
||||||
|
|
||||||
|
if (!typebot) return
|
||||||
|
|
||||||
|
const totalViews = await prisma.result.count({
|
||||||
|
where: {
|
||||||
|
typebotId: {
|
||||||
|
in: await filterAuthorizedTypebotIds(
|
||||||
|
prisma,
|
||||||
|
{
|
||||||
|
typebotIds: '6rw8KvRZe7UbHcJrs8Ui4S',
|
||||||
|
user: { email: '', id: 'ckzmhmiey001009mnzt5nkxu8' },
|
||||||
|
},
|
||||||
|
'read'
|
||||||
|
),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
const totalStarts = await prisma.result.count({
|
||||||
|
where: {
|
||||||
|
typebot: { id: typebot.id },
|
||||||
|
answers: { some: {} },
|
||||||
|
},
|
||||||
|
})
|
||||||
|
const totalCompleted = await prisma.result.count({
|
||||||
|
where: {
|
||||||
|
typebot: { id: typebot.id },
|
||||||
|
isCompleted: true,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const filterAuthorizedTypebotIds = async (
|
||||||
|
prisma: PrismaClient,
|
||||||
|
{
|
||||||
|
typebotIds,
|
||||||
|
user,
|
||||||
|
}: {
|
||||||
|
typebotIds: string | string[]
|
||||||
|
user: Pick<User, 'id' | 'email'>
|
||||||
|
},
|
||||||
|
role: 'read' | 'write'
|
||||||
|
) => {
|
||||||
|
const typebots = await prisma.typebot.findMany({
|
||||||
|
where: {
|
||||||
|
id: { in: typebotIds },
|
||||||
|
workspace:
|
||||||
|
(role === 'read' && user.email === process.env.ADMIN_EMAIL) ||
|
||||||
|
isNotEmpty(env('E2E_TEST'))
|
||||||
|
? undefined
|
||||||
|
: {
|
||||||
|
members: {
|
||||||
|
some: {
|
||||||
|
userId: user.id,
|
||||||
|
role:
|
||||||
|
role === 'write' ? { not: WorkspaceRole.GUEST } : undefined,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
select: { id: true },
|
||||||
|
})
|
||||||
|
|
||||||
|
return typebots.map((typebot) => typebot.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
executePlayground()
|
executePlayground()
|
||||||
|
Reference in New Issue
Block a user