⚗️ Implement chat API
This commit is contained in:
@@ -0,0 +1 @@
|
||||
export * from './utils'
|
||||
@@ -0,0 +1,30 @@
|
||||
import { ExecuteIntegrationResponse } from '@/features/chat'
|
||||
import { GoogleSheetsBlock, GoogleSheetsAction, SessionState } from 'models'
|
||||
import { getRow } from './getRow'
|
||||
import { insertRow } from './insertRow'
|
||||
import { updateRow } from './updateRow'
|
||||
|
||||
export const executeGoogleSheetBlock = async (
|
||||
state: SessionState,
|
||||
block: GoogleSheetsBlock
|
||||
): Promise<ExecuteIntegrationResponse> => {
|
||||
if (!('action' in block.options))
|
||||
return { outgoingEdgeId: block.outgoingEdgeId }
|
||||
switch (block.options.action) {
|
||||
case GoogleSheetsAction.INSERT_ROW:
|
||||
return insertRow(state, {
|
||||
options: block.options,
|
||||
outgoingEdgeId: block.outgoingEdgeId,
|
||||
})
|
||||
case GoogleSheetsAction.UPDATE_ROW:
|
||||
return updateRow(state, {
|
||||
options: block.options,
|
||||
outgoingEdgeId: block.outgoingEdgeId,
|
||||
})
|
||||
case GoogleSheetsAction.GET:
|
||||
return getRow(state, {
|
||||
options: block.options,
|
||||
outgoingEdgeId: block.outgoingEdgeId,
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
import { SessionState, GoogleSheetsGetOptions, VariableWithValue } from 'models'
|
||||
import { saveErrorLog, saveSuccessLog } from '@/features/logs/api'
|
||||
import { getAuthenticatedGoogleDoc } from './helpers'
|
||||
import { parseVariables, updateVariables } from '@/features/variables'
|
||||
import { isNotEmpty, byId } from 'utils'
|
||||
import { ExecuteIntegrationResponse } from '@/features/chat'
|
||||
|
||||
export const getRow = async (
|
||||
state: SessionState,
|
||||
{
|
||||
outgoingEdgeId,
|
||||
options,
|
||||
}: { outgoingEdgeId?: string; options: GoogleSheetsGetOptions }
|
||||
): Promise<ExecuteIntegrationResponse> => {
|
||||
const { sheetId, cellsToExtract, referenceCell } = options
|
||||
if (!cellsToExtract || !sheetId || !referenceCell) return { outgoingEdgeId }
|
||||
|
||||
const variables = state.typebot.variables
|
||||
const resultId = state.result.id
|
||||
|
||||
const doc = await getAuthenticatedGoogleDoc({
|
||||
credentialsId: options.credentialsId,
|
||||
spreadsheetId: options.spreadsheetId,
|
||||
})
|
||||
|
||||
const parsedReferenceCell = {
|
||||
column: referenceCell.column,
|
||||
value: parseVariables(variables)(referenceCell.value),
|
||||
}
|
||||
|
||||
const extractingColumns = cellsToExtract
|
||||
.map((cell) => cell.column)
|
||||
.filter(isNotEmpty)
|
||||
|
||||
try {
|
||||
await doc.loadInfo()
|
||||
const sheet = doc.sheetsById[sheetId]
|
||||
const rows = await sheet.getRows()
|
||||
const row = rows.find(
|
||||
(row) =>
|
||||
row[parsedReferenceCell.column as string] === parsedReferenceCell.value
|
||||
)
|
||||
if (!row) {
|
||||
await saveErrorLog({
|
||||
resultId,
|
||||
message: "Couldn't find reference cell",
|
||||
})
|
||||
return { outgoingEdgeId }
|
||||
}
|
||||
const data: { [key: string]: string } = {
|
||||
...extractingColumns.reduce(
|
||||
(obj, column) => ({ ...obj, [column]: row[column] }),
|
||||
{}
|
||||
),
|
||||
}
|
||||
await saveSuccessLog({
|
||||
resultId,
|
||||
message: 'Succesfully fetched spreadsheet data',
|
||||
})
|
||||
|
||||
const newVariables = options.cellsToExtract.reduce<VariableWithValue[]>(
|
||||
(newVariables, cell) => {
|
||||
const existingVariable = variables.find(byId(cell.variableId))
|
||||
const value = data[cell.column ?? ''] ?? null
|
||||
if (!existingVariable) return newVariables
|
||||
return [
|
||||
...newVariables,
|
||||
{
|
||||
...existingVariable,
|
||||
value,
|
||||
},
|
||||
]
|
||||
},
|
||||
[]
|
||||
)
|
||||
const newSessionState = await updateVariables(state)(newVariables)
|
||||
return {
|
||||
outgoingEdgeId,
|
||||
newSessionState,
|
||||
}
|
||||
} catch (err) {
|
||||
await saveErrorLog({
|
||||
resultId,
|
||||
message: "Couldn't fetch spreadsheet data",
|
||||
details: err,
|
||||
})
|
||||
}
|
||||
return { outgoingEdgeId }
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
import { parseVariables } from '@/features/variables'
|
||||
import { getAuthenticatedGoogleClient } from '@/lib/google-sheets'
|
||||
import { TRPCError } from '@trpc/server'
|
||||
import { GoogleSpreadsheet } from 'google-spreadsheet'
|
||||
import { Variable, Cell } from 'models'
|
||||
|
||||
export const parseCellValues =
|
||||
(variables: Variable[]) =>
|
||||
(cells: Cell[]): { [key: string]: string } =>
|
||||
cells.reduce((row, cell) => {
|
||||
return !cell.column || !cell.value
|
||||
? row
|
||||
: {
|
||||
...row,
|
||||
[cell.column]: parseVariables(variables)(cell.value),
|
||||
}
|
||||
}, {})
|
||||
|
||||
export const getAuthenticatedGoogleDoc = async ({
|
||||
credentialsId,
|
||||
spreadsheetId,
|
||||
}: {
|
||||
credentialsId?: string
|
||||
spreadsheetId?: string
|
||||
}) => {
|
||||
if (!credentialsId)
|
||||
throw new TRPCError({
|
||||
code: 'BAD_REQUEST',
|
||||
message: 'Missing credentialsId or sheetId',
|
||||
})
|
||||
const doc = new GoogleSpreadsheet(spreadsheetId)
|
||||
const auth = await getAuthenticatedGoogleClient(credentialsId)
|
||||
if (!auth)
|
||||
throw new TRPCError({
|
||||
code: 'NOT_FOUND',
|
||||
message: "Couldn't find credentials in database",
|
||||
})
|
||||
doc.useOAuth2Client(auth)
|
||||
return doc
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
export * from './executeGoogleSheetBlock'
|
||||
@@ -0,0 +1,38 @@
|
||||
import { SessionState, GoogleSheetsInsertRowOptions } from 'models'
|
||||
import { saveErrorLog, saveSuccessLog } from '@/features/logs/api'
|
||||
import { getAuthenticatedGoogleDoc, parseCellValues } from './helpers'
|
||||
import { ExecuteIntegrationResponse } from '@/features/chat'
|
||||
|
||||
export const insertRow = async (
|
||||
{ result, typebot: { variables } }: SessionState,
|
||||
{
|
||||
outgoingEdgeId,
|
||||
options,
|
||||
}: { outgoingEdgeId?: string; options: GoogleSheetsInsertRowOptions }
|
||||
): Promise<ExecuteIntegrationResponse> => {
|
||||
if (!options.cellsToInsert || !options.sheetId) return { outgoingEdgeId }
|
||||
|
||||
const doc = await getAuthenticatedGoogleDoc({
|
||||
credentialsId: options.credentialsId,
|
||||
spreadsheetId: options.spreadsheetId,
|
||||
})
|
||||
|
||||
const parsedValues = parseCellValues(variables)(options.cellsToInsert)
|
||||
|
||||
try {
|
||||
await doc.loadInfo()
|
||||
const sheet = doc.sheetsById[options.sheetId]
|
||||
await sheet.addRow(parsedValues)
|
||||
await saveSuccessLog({
|
||||
resultId: result.id,
|
||||
message: 'Succesfully inserted row',
|
||||
})
|
||||
} catch (err) {
|
||||
await saveErrorLog({
|
||||
resultId: result.id,
|
||||
message: "Couldn't fetch spreadsheet data",
|
||||
details: err,
|
||||
})
|
||||
}
|
||||
return { outgoingEdgeId }
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
import { SessionState, GoogleSheetsUpdateRowOptions } from 'models'
|
||||
import { saveErrorLog, saveSuccessLog } from '@/features/logs/api'
|
||||
import { getAuthenticatedGoogleDoc, parseCellValues } from './helpers'
|
||||
import { TRPCError } from '@trpc/server'
|
||||
import { parseVariables } from '@/features/variables'
|
||||
import { ExecuteIntegrationResponse } from '@/features/chat'
|
||||
|
||||
export const updateRow = async (
|
||||
{ result, typebot: { variables } }: SessionState,
|
||||
{
|
||||
outgoingEdgeId,
|
||||
options,
|
||||
}: { outgoingEdgeId?: string; options: GoogleSheetsUpdateRowOptions }
|
||||
): Promise<ExecuteIntegrationResponse> => {
|
||||
const { sheetId, referenceCell } = options
|
||||
if (!options.cellsToUpsert || !sheetId || !referenceCell)
|
||||
return { outgoingEdgeId }
|
||||
|
||||
const doc = await getAuthenticatedGoogleDoc({
|
||||
credentialsId: options.credentialsId,
|
||||
spreadsheetId: options.spreadsheetId,
|
||||
})
|
||||
|
||||
const parsedReferenceCell = {
|
||||
column: referenceCell.column,
|
||||
value: parseVariables(variables)(referenceCell.value),
|
||||
}
|
||||
const parsedValues = parseCellValues(variables)(options.cellsToUpsert)
|
||||
|
||||
try {
|
||||
await doc.loadInfo()
|
||||
const sheet = doc.sheetsById[sheetId]
|
||||
const rows = await sheet.getRows()
|
||||
const updatingRowIndex = rows.findIndex(
|
||||
(row) =>
|
||||
row[parsedReferenceCell.column as string] === parsedReferenceCell.value
|
||||
)
|
||||
if (updatingRowIndex === -1) {
|
||||
new TRPCError({
|
||||
code: 'NOT_FOUND',
|
||||
message: "Couldn't find row to update",
|
||||
})
|
||||
}
|
||||
for (const key in parsedValues) {
|
||||
rows[updatingRowIndex][key] = parsedValues[key]
|
||||
}
|
||||
await rows[updatingRowIndex].save()
|
||||
await saveSuccessLog({
|
||||
resultId: result.id,
|
||||
message: 'Succesfully updated row',
|
||||
})
|
||||
} catch (err) {
|
||||
await saveErrorLog({
|
||||
resultId: result.id,
|
||||
message: "Couldn't fetch spreadsheet data",
|
||||
details: err,
|
||||
})
|
||||
}
|
||||
return { outgoingEdgeId }
|
||||
}
|
||||
Reference in New Issue
Block a user