🐛 Remove publicId and customDomain duplication on imported bots
This commit is contained in:
@@ -2,6 +2,7 @@ import prisma from '@/lib/prisma'
|
|||||||
import { authenticatedProcedure } from '@/helpers/server/trpc'
|
import { authenticatedProcedure } from '@/helpers/server/trpc'
|
||||||
import { TRPCError } from '@trpc/server'
|
import { TRPCError } from '@trpc/server'
|
||||||
import { z } from 'zod'
|
import { z } from 'zod'
|
||||||
|
import { isReadWorkspaceFobidden } from '@/features/workspace/helpers/isReadWorkspaceFobidden'
|
||||||
|
|
||||||
export const getUsage = authenticatedProcedure
|
export const getUsage = authenticatedProcedure
|
||||||
.meta({
|
.meta({
|
||||||
@@ -25,10 +26,19 @@ export const getUsage = authenticatedProcedure
|
|||||||
const workspace = await prisma.workspace.findFirst({
|
const workspace = await prisma.workspace.findFirst({
|
||||||
where: {
|
where: {
|
||||||
id: workspaceId,
|
id: workspaceId,
|
||||||
members: { some: { userId: user.id } },
|
},
|
||||||
|
select: {
|
||||||
|
members: {
|
||||||
|
select: {
|
||||||
|
userId: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
typebots: {
|
||||||
|
select: { id: true, results: { select: { id: true } } },
|
||||||
|
},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
if (!workspace)
|
if (!workspace || isReadWorkspaceFobidden(workspace, user))
|
||||||
throw new TRPCError({
|
throw new TRPCError({
|
||||||
code: 'NOT_FOUND',
|
code: 'NOT_FOUND',
|
||||||
message: 'Workspace not found',
|
message: 'Workspace not found',
|
||||||
@@ -36,40 +46,25 @@ export const getUsage = authenticatedProcedure
|
|||||||
|
|
||||||
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 [
|
const totalChatsUsed = await prisma.result.count({
|
||||||
totalChatsUsed,
|
where: {
|
||||||
{
|
typebotId: { in: workspace.typebots.map((typebot) => typebot.id) },
|
||||||
_sum: { storageUsed: totalStorageUsed },
|
hasStarted: true,
|
||||||
},
|
createdAt: {
|
||||||
] = await prisma.$transaction(async (tx) => {
|
gte: firstDayOfMonth,
|
||||||
const typebots = await tx.typebot.findMany({
|
|
||||||
where: {
|
|
||||||
workspace: {
|
|
||||||
id: workspaceId,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
})
|
},
|
||||||
|
})
|
||||||
return Promise.all([
|
const {
|
||||||
prisma.result.count({
|
_sum: { storageUsed: totalStorageUsed },
|
||||||
where: {
|
} = await prisma.answer.aggregate({
|
||||||
typebotId: { in: typebots.map((typebot) => typebot.id) },
|
where: {
|
||||||
hasStarted: true,
|
storageUsed: { gt: 0 },
|
||||||
createdAt: {
|
result: {
|
||||||
gte: firstDayOfMonth,
|
typebotId: { in: workspace.typebots.map((typebot) => typebot.id) },
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}),
|
_sum: { storageUsed: true },
|
||||||
prisma.answer.aggregate({
|
|
||||||
where: {
|
|
||||||
storageUsed: { gt: 0 },
|
|
||||||
result: {
|
|
||||||
typebotId: { in: typebots.map((typebot) => typebot.id) },
|
|
||||||
},
|
|
||||||
},
|
|
||||||
_sum: { storageUsed: true },
|
|
||||||
}),
|
|
||||||
])
|
|
||||||
})
|
})
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ export const createCredentials = authenticatedProcedure
|
|||||||
},
|
},
|
||||||
select: { id: true, members: true },
|
select: { id: true, members: true },
|
||||||
})
|
})
|
||||||
if (!workspace || (await isWriteWorkspaceForbidden(workspace, user)))
|
if (!workspace || isWriteWorkspaceForbidden(workspace, user))
|
||||||
throw new TRPCError({ code: 'NOT_FOUND', message: 'Workspace not found' })
|
throw new TRPCError({ code: 'NOT_FOUND', message: 'Workspace not found' })
|
||||||
|
|
||||||
const { encryptedData, iv } = await encrypt(credentials.data)
|
const { encryptedData, iv } = await encrypt(credentials.data)
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ export const deleteCredentials = authenticatedProcedure
|
|||||||
},
|
},
|
||||||
select: { id: true, members: true },
|
select: { id: true, members: true },
|
||||||
})
|
})
|
||||||
if (!workspace || (await isWriteWorkspaceForbidden(workspace, user)))
|
if (!workspace || isWriteWorkspaceForbidden(workspace, user))
|
||||||
throw new TRPCError({
|
throw new TRPCError({
|
||||||
code: 'NOT_FOUND',
|
code: 'NOT_FOUND',
|
||||||
message: 'Workspace not found',
|
message: 'Workspace not found',
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ export const listCredentials = authenticatedProcedure
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
if (!workspace || (await isReadWorkspaceFobidden(workspace, user)))
|
if (!workspace || isReadWorkspaceFobidden(workspace, user))
|
||||||
throw new TRPCError({ code: 'NOT_FOUND', message: 'Workspace not found' })
|
throw new TRPCError({ code: 'NOT_FOUND', message: 'Workspace not found' })
|
||||||
|
|
||||||
return { credentials: workspace.credentials }
|
return { credentials: workspace.credentials }
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import { useScopedI18n } from '@/locales'
|
|||||||
import { TypebotInDashboard } from '@/features/dashboard/types'
|
import { TypebotInDashboard } from '@/features/dashboard/types'
|
||||||
import { isMobile } from '@/helpers/isMobile'
|
import { isMobile } from '@/helpers/isMobile'
|
||||||
import { trpc, trpcVanilla } from '@/lib/trpc'
|
import { trpc, trpcVanilla } from '@/lib/trpc'
|
||||||
|
import { duplicateName } from '@/features/typebot/helpers/duplicateName'
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
typebot: TypebotInDashboard
|
typebot: TypebotInDashboard
|
||||||
@@ -221,10 +222,3 @@ export const TypebotButton = ({
|
|||||||
</Button>
|
</Button>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const duplicateName = (name: string | `${string} (${number})`) => {
|
|
||||||
const match = name.match(/^(.*) \((\d+)\)$/)
|
|
||||||
if (!match) return `${name} (1)`
|
|
||||||
const [, nameWithoutNumber, number] = match
|
|
||||||
return `${nameWithoutNumber} (${Number(number) + 1})`
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -56,7 +56,13 @@ export const CreateNewTypebotButtons = () => {
|
|||||||
mutate({
|
mutate({
|
||||||
workspaceId: workspace.id,
|
workspaceId: workspace.id,
|
||||||
typebot: {
|
typebot: {
|
||||||
...(typebot ? { ...typebot } : {}),
|
...(typebot
|
||||||
|
? {
|
||||||
|
...typebot,
|
||||||
|
publicId: undefined,
|
||||||
|
customDomain: undefined,
|
||||||
|
}
|
||||||
|
: {}),
|
||||||
folderId,
|
folderId,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -19,13 +19,12 @@ export const ImportTypebotFromFileButton = ({
|
|||||||
const file = e.target.files[0]
|
const file = e.target.files[0]
|
||||||
const fileContent = await readFile(file)
|
const fileContent = await readFile(file)
|
||||||
try {
|
try {
|
||||||
const typebot = parseInvalidTypebot(JSON.parse(fileContent))
|
const typebot = typebotSchema
|
||||||
typebotSchema
|
|
||||||
.omit({
|
.omit({
|
||||||
createdAt: true,
|
createdAt: true,
|
||||||
updatedAt: true,
|
updatedAt: true,
|
||||||
})
|
})
|
||||||
.parse(typebot)
|
.parse(parseInvalidTypebot(JSON.parse(fileContent)))
|
||||||
onNewTypebot(typebot as Typebot)
|
onNewTypebot(typebot as Typebot)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(err)
|
console.error(err)
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
export const duplicateName = (name: string | `${string} (${number})`) => {
|
||||||
|
const match = name.match(/^(.*) \((\d+)\)$/)
|
||||||
|
if (!match) return `${name} (1)`
|
||||||
|
const [, nameWithoutNumber, number] = match
|
||||||
|
return `${nameWithoutNumber} (${Number(number) + 1})`
|
||||||
|
}
|
||||||
@@ -30,7 +30,7 @@ export const deleteWorkspace = authenticatedProcedure
|
|||||||
include: { members: true },
|
include: { members: true },
|
||||||
})
|
})
|
||||||
|
|
||||||
if (!workspace || (await isAdminWriteWorkspaceForbidden(workspace, user)))
|
if (!workspace || isAdminWriteWorkspaceForbidden(workspace, user))
|
||||||
throw new TRPCError({ code: 'NOT_FOUND', message: 'No workspaces found' })
|
throw new TRPCError({ code: 'NOT_FOUND', message: 'No workspaces found' })
|
||||||
|
|
||||||
await prisma.workspace.deleteMany({
|
await prisma.workspace.deleteMany({
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ export const getWorkspace = authenticatedProcedure
|
|||||||
include: { members: true },
|
include: { members: true },
|
||||||
})
|
})
|
||||||
|
|
||||||
if (!workspace || (await isReadWorkspaceFobidden(workspace, user)))
|
if (!workspace || isReadWorkspaceFobidden(workspace, user))
|
||||||
throw new TRPCError({ code: 'NOT_FOUND', message: 'No workspaces found' })
|
throw new TRPCError({ code: 'NOT_FOUND', message: 'No workspaces found' })
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ export const listInvitationsInWorkspace = authenticatedProcedure
|
|||||||
include: { members: true, invitations: true },
|
include: { members: true, invitations: true },
|
||||||
})
|
})
|
||||||
|
|
||||||
if (!workspace || (await isReadWorkspaceFobidden(workspace, user)))
|
if (!workspace || isReadWorkspaceFobidden(workspace, user))
|
||||||
throw new TRPCError({ code: 'NOT_FOUND', message: 'No workspaces found' })
|
throw new TRPCError({ code: 'NOT_FOUND', message: 'No workspaces found' })
|
||||||
|
|
||||||
return { invitations: workspace.invitations }
|
return { invitations: workspace.invitations }
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ export const listMembersInWorkspace = authenticatedProcedure
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
if (!workspace || (await isReadWorkspaceFobidden(workspace, user)))
|
if (!workspace || isReadWorkspaceFobidden(workspace, user))
|
||||||
throw new TRPCError({ code: 'NOT_FOUND', message: 'No workspaces found' })
|
throw new TRPCError({ code: 'NOT_FOUND', message: 'No workspaces found' })
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ export const updateWorkspace = authenticatedProcedure
|
|||||||
if (!workspace)
|
if (!workspace)
|
||||||
throw new TRPCError({ code: 'NOT_FOUND', message: 'Workspace not found' })
|
throw new TRPCError({ code: 'NOT_FOUND', message: 'Workspace not found' })
|
||||||
|
|
||||||
if (await isAdminWriteWorkspaceForbidden(workspace, user))
|
if (isAdminWriteWorkspaceForbidden(workspace, user))
|
||||||
throw new TRPCError({
|
throw new TRPCError({
|
||||||
code: 'FORBIDDEN',
|
code: 'FORBIDDEN',
|
||||||
message: 'You are not allowed to update this workspace',
|
message: 'You are not allowed to update this workspace',
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { MemberInWorkspace, User } from '@typebot.io/prisma'
|
import { MemberInWorkspace, User } from '@typebot.io/prisma'
|
||||||
|
|
||||||
export const isAdminWriteWorkspaceForbidden = async (
|
export const isAdminWriteWorkspaceForbidden = (
|
||||||
workspace: {
|
workspace: {
|
||||||
members: MemberInWorkspace[]
|
members: MemberInWorkspace[]
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import { MemberInWorkspace, User } from '@typebot.io/prisma'
|
import { MemberInWorkspace, User } from '@typebot.io/prisma'
|
||||||
|
|
||||||
export const isReadWorkspaceFobidden = async (
|
export const isReadWorkspaceFobidden = (
|
||||||
workspace: {
|
workspace: {
|
||||||
members: MemberInWorkspace[]
|
members: Pick<MemberInWorkspace, 'userId'>[]
|
||||||
},
|
},
|
||||||
user: Pick<User, 'email' | 'id'>
|
user: Pick<User, 'email' | 'id'>
|
||||||
) => {
|
) => {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { MemberInWorkspace, User } from '@typebot.io/prisma'
|
import { MemberInWorkspace, User } from '@typebot.io/prisma'
|
||||||
|
|
||||||
export const isWriteWorkspaceForbidden = async (
|
export const isWriteWorkspaceForbidden = (
|
||||||
workspace: {
|
workspace: {
|
||||||
members: MemberInWorkspace[]
|
members: MemberInWorkspace[]
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -426,7 +426,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"/linkedTypebots": {
|
"/typebots/{typebotId}/linkedTypebots": {
|
||||||
"get": {
|
"get": {
|
||||||
"operationId": "getLinkedTypebots",
|
"operationId": "getLinkedTypebots",
|
||||||
"summary": "Get linked typebots",
|
"summary": "Get linked typebots",
|
||||||
@@ -440,21 +440,12 @@
|
|||||||
],
|
],
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
"name": "workspaceId",
|
"name": "typebotId",
|
||||||
"in": "query",
|
"in": "path",
|
||||||
"required": true,
|
"required": true,
|
||||||
"schema": {
|
"schema": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
}
|
}
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "typebotIds",
|
|
||||||
"in": "query",
|
|
||||||
"required": true,
|
|
||||||
"schema": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"description": "Comma separated list of typebot ids"
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"responses": {
|
"responses": {
|
||||||
|
|||||||
Reference in New Issue
Block a user