♻️ (results) Introduce tRPC and use it for the results

This commit is contained in:
Baptiste Arnaud
2022-11-18 18:21:40 +01:00
parent c9cc82cc08
commit d58f9bd3a1
58 changed files with 750 additions and 421 deletions

View File

@@ -3,53 +3,51 @@ import { canWriteTypebot } from '@/utils/api/dbRules'
import { deleteFiles } from '@/utils/api/storage'
import { User, Prisma } from 'db'
import { InputBlockType, Typebot } from 'models'
import { NextApiResponse } from 'next'
import { forbidden } from 'utils/api'
export const archiveResults =
(res: NextApiResponse) =>
async ({
typebotId,
user,
resultsFilter,
}: {
typebotId: string
user: User
resultsFilter?: Prisma.ResultWhereInput
}) => {
const typebot = await prisma.typebot.findFirst({
where: canWriteTypebot(typebotId, user),
select: { groups: true },
export const archiveResults = async ({
typebotId,
user,
resultsFilter,
}: {
typebotId: string
user: User
resultsFilter?: Prisma.ResultWhereInput
}) => {
const typebot = await prisma.typebot.findFirst({
where: canWriteTypebot(typebotId, user),
select: { groups: true },
})
if (!typebot) return { success: false }
const fileUploadBlockIds = (typebot as Typebot).groups
.flatMap((g) => g.blocks)
.filter((b) => b.type === InputBlockType.FILE)
.map((b) => b.id)
if (fileUploadBlockIds.length > 0) {
const filesToDelete = await prisma.answer.findMany({
where: { result: resultsFilter, blockId: { in: fileUploadBlockIds } },
})
if (!typebot) return forbidden(res)
const fileUploadBlockIds = (typebot as Typebot).groups
.flatMap((g) => g.blocks)
.filter((b) => b.type === InputBlockType.FILE)
.map((b) => b.id)
if (fileUploadBlockIds.length > 0) {
const filesToDelete = await prisma.answer.findMany({
where: { result: resultsFilter, blockId: { in: fileUploadBlockIds } },
if (filesToDelete.length > 0)
await deleteFiles({
urls: filesToDelete.flatMap((a) => a.content.split(', ')),
})
if (filesToDelete.length > 0)
await deleteFiles({
urls: filesToDelete.flatMap((a) => a.content.split(', ')),
})
}
await prisma.log.deleteMany({
where: {
result: resultsFilter,
},
})
await prisma.answer.deleteMany({
where: {
result: resultsFilter,
},
})
await prisma.result.updateMany({
where: resultsFilter,
data: {
isArchived: true,
variables: [],
},
})
}
await prisma.log.deleteMany({
where: {
result: resultsFilter,
},
})
await prisma.answer.deleteMany({
where: {
result: resultsFilter,
},
})
await prisma.result.updateMany({
where: resultsFilter,
data: {
isArchived: true,
variables: [],
},
})
return { success: true }
}

View File

@@ -1 +1,2 @@
export * from './archiveResults'
export * from './router'

View File

@@ -0,0 +1,39 @@
import { canWriteTypebot } from '@/utils/api/dbRules'
import { authenticatedProcedure } from '@/utils/server/trpc'
import { TRPCError } from '@trpc/server'
import { z } from 'zod'
import { archiveResults } from '../archiveResults'
export const deleteResultsProcedure = authenticatedProcedure
.meta({
openapi: {
method: 'DELETE',
path: '/typebots/{typebotId}/results',
protect: true,
},
})
.input(
z.object({
typebotId: z.string(),
ids: z.string().optional(),
})
)
.output(z.void())
.mutation(async ({ input, ctx: { user } }) => {
const idsArray = input.ids?.split(',')
const { typebotId } = input
const { success } = await archiveResults({
typebotId,
user,
resultsFilter: {
id: (idsArray?.length ?? 0) > 0 ? { in: idsArray } : undefined,
typebot: canWriteTypebot(typebotId, user),
},
})
if (!success)
throw new TRPCError({
code: 'NOT_FOUND',
message: 'Typebot not found',
})
})

View File

@@ -0,0 +1,30 @@
import prisma from '@/lib/prisma'
import { canReadTypebot } from '@/utils/api/dbRules'
import { authenticatedProcedure } from '@/utils/server/trpc'
import { logSchema } from 'models'
import { z } from 'zod'
export const getResultLogsProcedure = authenticatedProcedure
.meta({
openapi: {
method: 'GET',
path: '/typebots/{typebotId}/results/{resultId}/logs',
protect: true,
},
})
.input(
z.object({
typebotId: z.string(),
resultId: z.string(),
})
)
.output(z.object({ logs: z.array(logSchema) }))
.query(async ({ input: { typebotId, resultId }, ctx: { user } }) => {
const logs = await prisma.log.findMany({
where: {
result: { id: resultId, typebot: canReadTypebot(typebotId, user) },
},
})
return { logs }
})

View File

@@ -0,0 +1,59 @@
import prisma from '@/lib/prisma'
import { canReadTypebot } from '@/utils/api/dbRules'
import { authenticatedProcedure } from '@/utils/server/trpc'
import { TRPCError } from '@trpc/server'
import { ResultWithAnswers, resultWithAnswersSchema } from 'models'
import { z } from 'zod'
const maxLimit = 200
export const getResultsProcedure = authenticatedProcedure
.meta({
openapi: {
method: 'GET',
path: '/typebots/{typebotId}/results',
protect: true,
},
})
.input(
z.object({
typebotId: z.string(),
limit: z.string().regex(/^[0-9]{1,3}$/),
cursor: z.string().optional(),
})
)
.output(
z.object({
results: z.array(resultWithAnswersSchema),
nextCursor: z.string().nullish(),
})
)
.query(async ({ input, ctx: { user } }) => {
const limit = Number(input.limit)
if (limit < 1 || limit > maxLimit)
throw new TRPCError({
code: 'BAD_REQUEST',
message: 'limit must be between 1 and 200',
})
const { cursor } = input
const results = (await prisma.result.findMany({
take: limit + 1,
cursor: cursor ? { id: cursor } : undefined,
where: {
typebot: canReadTypebot(input.typebotId, user),
answers: { some: {} },
},
orderBy: {
createdAt: 'desc',
},
include: { answers: true },
})) as ResultWithAnswers[]
let nextCursor: typeof cursor | undefined
if (results.length > limit) {
const nextResult = results.pop()
nextCursor = nextResult?.id
}
return { results, nextCursor }
})

View File

@@ -0,0 +1,3 @@
export * from './deleteResultsProcedure'
export * from './getResultLogsProcedure'
export * from './getResultsProcedure'

View File

@@ -0,0 +1,12 @@
import { router } from '@/utils/server/trpc'
import {
deleteResultsProcedure,
getResultLogsProcedure,
getResultsProcedure,
} from './procedures'
export const resultsRouter = router({
getResults: getResultsProcedure,
deleteResults: deleteResultsProcedure,
getResultLogs: getResultLogsProcedure,
})