Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Full stack/refactor internal session vars - adapt backend code to botState data model #1966

20 changes: 10 additions & 10 deletions packages/botonic-api/src/rest/routes/events.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { BotonicEvent, MessageEventAck } from '@botonic/core'
import { BotonicEvent, MessageEventAck, PROVIDER } from '@botonic/core'
import { dataProviderFactory } from '@botonic/core/lib/esm/data-provider'
import { Router } from 'express'
import jwt from 'express-jwt'
Expand Down Expand Up @@ -76,25 +76,25 @@ export default function eventsRouter(args: any): Router {
const { userId } = req.user
const { message, sender } = req.body
let user = await dp.getUser(userId)
user = await dp.updateUser({
...user,
session: JSON.stringify({ user: sender }),
})
// TODO: Next iterations: We should receive an event with userId and eventId from frontend
const updatedUser = { ...user, ...sender }
user = await dp.updateUser(updatedUser)
// TODO: Only update ack for webchat
// TODO: Specific logic for webchat, move to webchat-events?
const webchatMsgId = message.id
await handlers.run('sender', {
events: [
{
action: 'update_message_info',
message: { id: webchatMsgId, ack: MessageEventAck.RECEIVED },
id: webchatMsgId,
ack: MessageEventAck.RECEIVED,
},
],
websocketId: user.websocketId,
})
await handlers.run('botExecutor', {
input: message,
session: JSON.parse(user.session),
lastRoutePath: user.route,
input: { ...message, userId }, // To identify user executing the input
session: user.session,
botState: user.botState,
websocketId: user.websocketId,
})
} catch (e) {
Expand Down
59 changes: 39 additions & 20 deletions packages/botonic-core/src/core-bot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
BotonicEvent,
BotRequest,
BotResponse,
BotState,
Locales,
MessageEventAck,
MessageEventFrom,
Expand Down Expand Up @@ -81,26 +82,30 @@ export class CoreBot {
)
}

getString(id: string, session: Session): string {
// @ts-ignore
return getString(this.locales, session.__locale, id)
getString(id: string, botState: BotState): string {
if (!botState.locale) {
console.error('Locale is not defined')
return ''
}
return getString(this.locales, botState.locale, id)
}

setLocale(locale: string, session: Session): void {
session.__locale = locale
setLocale(locale: string, botState: BotState): void {
botState.locale = locale
}

async input({
input,
session,
lastRoutePath,
botState,
dataProvider,
}: BotRequest): Promise<BotResponse> {
session = session || {}
if (!session.__locale) session.__locale = 'en'
if (!botState.locale) botState.locale = 'en'
// @ts-ignore
const userId = input.userId

const parsedUserEvent = this.botonicOutputParser.inputToBotonicEvent(input)

const parsedUserEvent = this.botonicOutputParser.parseFromUserInput(input)
const userId = session.user.id
if (dataProvider) {
// TODO: Next iterations. Review cycle of commited events to DB when messages change their ACK
// @ts-ignore
Expand All @@ -120,7 +125,7 @@ export class CoreBot {
'pre',
input,
session,
lastRoutePath,
botState,
undefined,
undefined,
dataProvider
Expand All @@ -133,7 +138,7 @@ export class CoreBot {
...(await getComputedRoutes(this.routes, {
input,
session,
lastRoutePath,
botState,
})),
...this.defaultRoutes,
],
Expand All @@ -144,18 +149,19 @@ export class CoreBot {
const output = (this.router as Router).processInput(
input,
session,
lastRoutePath
botState
)

const request = {
getString: stringId => this.getString(stringId, session),
setLocale: locale => this.setLocale(locale, session),
getString: stringId => this.getString(stringId, botState),
setLocale: locale => this.setLocale(locale, botState),
session: session || {},
params: output.params || {},
input: input,
plugins: this.plugins,
defaultTyping: this.defaultTyping,
defaultDelay: this.defaultDelay,
lastRoutePath,
botState,
dataProvider,
}

Expand All @@ -171,14 +177,15 @@ export class CoreBot {
// console.error(e)
}

lastRoutePath = output.lastRoutePath
botState.lastRoutePath = output.botState.lastRoutePath

if (this.plugins) {
await runPlugins(
this.plugins,
'post',
input,
session,
lastRoutePath,
botState,
response,
messageEvents,
dataProvider
Expand All @@ -200,13 +207,25 @@ export class CoreBot {
}
}

session.is_first_interaction = false
botState.isFirstInteraction = false

if (dataProvider) {
const user = await dataProvider.getUser(userId)
if (!user) {
// throw error
} else {
const updatedUser = { ...user, session, botState }
// @ts-ignore
await dataProvider.updateUser(updatedUser)
}
}
// TODO: return also updatedUser?
return {
input,
response,
messageEvents,
session,
lastRoutePath,
botState,
dataProvider,
}
}
Expand Down
8 changes: 7 additions & 1 deletion packages/botonic-core/src/data-provider/dynamodb-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,15 @@ export function getUserEntity(table: Table): Entity<any> {
},
userId: [SORT_KEY_NAME, 0],
websocketId: 'string',
name: 'string',
userName: 'string',
channel: 'string',
idFromChannel: 'string',
isOnline: 'boolean',
route: 'string',
session: 'string',
session: 'map',
botState: 'map',
details: 'map',
},
table,
})
Expand Down
24 changes: 13 additions & 11 deletions packages/botonic-core/src/handoff.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import axios from 'axios'

import { PATH_PAYLOAD_IDENTIFIER } from './constants'
import { Session } from './models'
import { BotState, Session } from './models'

const HUBTYPE_API_URL = 'https://api.hubtype.com'

Expand Down Expand Up @@ -57,7 +57,7 @@ export async function getOpenQueues(
}

export class HandOffBuilder {
_session: SessionWithBotonicAction
_botState: any
_queue: string
_onFinish: string
_email: string
Expand All @@ -66,8 +66,8 @@ export class HandOffBuilder {
_caseInfo: string
_shadowing: boolean

constructor(session: SessionWithBotonicAction) {
this._session = session
constructor(botState: any) {
this._botState = botState
}

withQueue(queueNameOrId: string): this {
Expand Down Expand Up @@ -112,7 +112,7 @@ export class HandOffBuilder {

async handOff(): Promise<void> {
return _humanHandOff(
this._session,
this._botState,
this._queue,
this._onFinish,
this._email,
Expand Down Expand Up @@ -154,7 +154,7 @@ interface HubtypeHandoffParams {
on_finish?: string
}
async function _humanHandOff(
session: SessionWithBotonicAction,
botState: any,
queueNameOrId = '',
onFinish: string,
agentEmail = '',
Expand Down Expand Up @@ -185,7 +185,8 @@ async function _humanHandOff(
if (onFinish) {
params.on_finish = onFinish
}
session._botonic_action = `create_case:${JSON.stringify(params)}`
botState.botonicAction = `create_case:${JSON.stringify(params)}`
botState.isHandoff = true
}

export async function storeCaseRating(
Expand Down Expand Up @@ -256,14 +257,15 @@ export async function getAgentVacationRanges(
}

export function cancelHandoff(
session: SessionWithBotonicAction,
botState: BotState,
typification: string | null = null
): void {
let action = 'discard_case'
if (typification) action = `${action}:${JSON.stringify({ typification })}`
session._botonic_action = action
botState.botonicAction = action
botState.isHandoff = false // TODO: Review handoff functionalities
}

export function deleteUser(session: SessionWithBotonicAction): void {
session._botonic_action = `delete_user`
export function deleteUser(botState: BotState): void {
botState.botonicAction = `delete_user`
}
10 changes: 5 additions & 5 deletions packages/botonic-core/src/hubtype-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import axios, { AxiosResponse } from 'axios'
import Pusher, { AuthOptions, Channel } from 'pusher-js'
import Channels from 'pusher-js/types/src/core/channels/channels'

import { Input, SessionUser } from './models'
import { Input } from './models'
import { getWebpackEnvVar } from './utils'

interface UnsentInput {
Expand All @@ -21,7 +21,7 @@ interface ServerConfig {
}
interface HubtypeServiceArgs {
appId: string
user: SessionUser
user: any
lastMessageId: string
lastMessageUpdateDate: string
onEvent: any
Expand Down Expand Up @@ -50,7 +50,7 @@ const PONG_TIMEOUT = 5 * 1000 // https://pusher.com/docs/channels/using_channels
*/
export class HubtypeService {
appId: string
user: SessionUser
user: any
lastMessageId: string
lastMessageUpdateDate: string
onEvent: any
Expand Down Expand Up @@ -185,7 +185,7 @@ export class HubtypeService {
}

handleConnectionChange(online: boolean): void {
this.onPusherEvent({ action: 'connectionChange', online })
this.onPusherEvent({ action: 'connection_change', online })
}

onPusherEvent(event: any): void {
Expand Down Expand Up @@ -213,7 +213,7 @@ export class HubtypeService {
/**
* @return {Promise<void>}
*/
async postMessage(user: SessionUser, message: any): Promise<void> {
async postMessage(user: any, message: any): Promise<void> {
try {
// @ts-ignore
await this.init(user)
Expand Down
12 changes: 12 additions & 0 deletions packages/botonic-core/src/models/bot-state.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { RoutePath } from './legacy-types'

export interface BotState {
botId: string
isFirstInteraction: boolean
isHandoff: boolean
isShadowing: boolean
lastRoutePath: RoutePath
locale?: string
asastre marked this conversation as resolved.
Show resolved Hide resolved
retries: number
botonicAction?: any
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,6 @@ export interface BotonicMessageEvent extends BaseEvent {
type: MessageEventTypes
typing: number
delay: number
// idFromChannel?:string references to msgId
// also channel
}
2 changes: 2 additions & 0 deletions packages/botonic-core/src/models/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
export * from './bot-state'
export * from './events'
export * from './legacy-types'
export * from './session'
export * from './user'
Loading