2019-06-27 09:22:32 -03:00
|
|
|
import { ConversationReference } from 'botbuilder';
|
2022-04-26 15:13:19 -03:00
|
|
|
import { GBLog, GBMinInstance, GBService, IGBInstance } from 'botlib';
|
2020-01-26 17:43:50 -03:00
|
|
|
import { CollectionUtil } from 'pragmatismo-io-framework';
|
2023-01-31 10:08:48 -03:00
|
|
|
import { GuaribasUser } from '../models/index.js';
|
2022-05-19 10:22:22 -03:00
|
|
|
import { FindOptions } from 'sequelize';
|
2024-02-05 12:36:20 -03:00
|
|
|
import { DialogKeywords } from '../../../packages/basic.gblib/services/DialogKeywords.js';
|
|
|
|
import * as Fs from 'fs';
|
|
|
|
import mkdirp from 'mkdirp';
|
2024-03-11 13:30:11 -03:00
|
|
|
import urlJoin from 'url-join';
|
2024-04-21 23:39:39 -03:00
|
|
|
import { GBLogEx } from '../../core.gbapp/services/GBLogEx.js';
|
2024-08-17 21:35:09 -03:00
|
|
|
import { GBServer } from '../../../src/app.js';
|
2024-09-06 15:15:42 -03:00
|
|
|
import { GBUtil } from '../../../src/util.js';
|
2024-03-11 13:30:11 -03:00
|
|
|
|
2018-04-21 02:59:30 -03:00
|
|
|
|
2019-03-09 16:59:31 -03:00
|
|
|
/**
|
|
|
|
* Security service layer.
|
|
|
|
*/
|
2018-04-21 02:59:30 -03:00
|
|
|
export class SecService extends GBService {
|
2023-05-25 21:20:40 -03:00
|
|
|
public async ensureUser(
|
2024-02-05 12:36:20 -03:00
|
|
|
min: GBMinInstance,
|
2018-04-21 02:59:30 -03:00
|
|
|
userSystemId: string,
|
|
|
|
userName: string,
|
|
|
|
address: string,
|
|
|
|
channelName: string,
|
2021-03-03 16:46:18 -03:00
|
|
|
displayName: string,
|
|
|
|
email: string
|
2018-09-09 14:39:37 -03:00
|
|
|
): Promise<GuaribasUser> {
|
2024-03-19 11:45:21 -03:00
|
|
|
|
2024-09-06 15:15:42 -03:00
|
|
|
const gbaiPath = GBUtil.getGBAIPath(min.botId);
|
2024-03-19 11:45:21 -03:00
|
|
|
const dir = urlJoin ('work',gbaiPath, 'users', userSystemId);
|
|
|
|
|
|
|
|
if (!Fs.existsSync(dir)) {
|
|
|
|
mkdirp.sync(dir);
|
|
|
|
}
|
|
|
|
|
2019-08-22 19:36:23 -03:00
|
|
|
let user = await GuaribasUser.findOne({
|
|
|
|
where: {
|
|
|
|
userSystemId: userSystemId
|
|
|
|
}
|
2019-03-08 06:37:13 -03:00
|
|
|
});
|
2019-08-22 19:36:23 -03:00
|
|
|
|
|
|
|
if (!user) {
|
|
|
|
user = GuaribasUser.build();
|
2024-03-11 13:30:11 -03:00
|
|
|
}
|
2024-02-05 12:36:20 -03:00
|
|
|
|
2024-03-11 13:30:11 -03:00
|
|
|
const systemPromptFile = urlJoin(dir, 'systemPrompt.txt');
|
|
|
|
if (Fs.existsSync(systemPromptFile)) {
|
|
|
|
user[ 'systemPrompt'] = Fs.readFileSync(systemPromptFile);
|
2019-08-22 19:36:23 -03:00
|
|
|
}
|
|
|
|
|
2024-02-05 12:36:20 -03:00
|
|
|
user.instanceId = min.instance.instanceId;
|
2019-08-22 19:36:23 -03:00
|
|
|
user.userSystemId = userSystemId;
|
|
|
|
user.userName = userName;
|
|
|
|
user.displayName = displayName;
|
2021-03-03 16:46:18 -03:00
|
|
|
user.email = email;
|
2019-08-22 19:36:23 -03:00
|
|
|
user.defaultChannel = channelName;
|
2024-08-17 21:35:09 -03:00
|
|
|
GBServer.globals.users [user.userId] = user;
|
2024-08-19 16:12:23 -03:00
|
|
|
if(user.changed()){
|
|
|
|
await user.save();
|
|
|
|
}
|
|
|
|
return user;
|
2018-04-21 02:59:30 -03:00
|
|
|
}
|
2019-06-27 09:22:32 -03:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Retrives a conversation reference from contact phone.
|
|
|
|
*/
|
2023-05-25 21:20:40 -03:00
|
|
|
public async getConversationReference(phone: string): Promise<ConversationReference> {
|
2022-05-19 10:22:22 -03:00
|
|
|
const options = <FindOptions>{ rejectOnEmpty: true, where: { phone: phone } };
|
2019-06-27 09:22:32 -03:00
|
|
|
const user = await GuaribasUser.findOne(options);
|
|
|
|
|
|
|
|
return JSON.parse(user.conversationReference);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Updates a conversation reference from contact phone.
|
|
|
|
*/
|
2023-05-25 21:20:40 -03:00
|
|
|
public async updateConversationReference(phone: string, conversationReference: string) {
|
2022-01-03 13:11:21 -03:00
|
|
|
const options = <FindOptions>{ where: { phone: phone } };
|
2019-06-27 09:22:32 -03:00
|
|
|
const user = await GuaribasUser.findOne(options);
|
|
|
|
|
|
|
|
user.conversationReference = conversationReference;
|
2024-08-17 21:35:09 -03:00
|
|
|
GBServer.globals.users [user.userId] = user;
|
2019-06-27 09:22:32 -03:00
|
|
|
await user.save();
|
|
|
|
}
|
|
|
|
|
2023-05-25 21:20:40 -03:00
|
|
|
public async updateConversationReferenceById(userId: number, conversationReference: string) {
|
2022-01-03 13:11:21 -03:00
|
|
|
const options = <FindOptions>{ where: { userId: userId } };
|
2021-03-03 16:46:18 -03:00
|
|
|
const user = await GuaribasUser.findOne(options);
|
|
|
|
|
|
|
|
user.conversationReference = conversationReference;
|
2024-08-17 21:35:09 -03:00
|
|
|
GBServer.globals.users [user.userId] = user;
|
2021-03-03 16:46:18 -03:00
|
|
|
await user.save();
|
|
|
|
}
|
|
|
|
|
2023-05-25 21:20:40 -03:00
|
|
|
public async updateUserLocale(userId: number, locale: any): Promise<GuaribasUser> {
|
2020-12-31 15:36:19 -03:00
|
|
|
const user = await GuaribasUser.findOne({
|
2020-11-17 08:27:10 -03:00
|
|
|
where: {
|
2020-11-17 10:11:32 -03:00
|
|
|
userId: userId
|
2020-11-17 08:27:10 -03:00
|
|
|
}
|
|
|
|
});
|
|
|
|
user.locale = locale;
|
2024-08-17 21:35:09 -03:00
|
|
|
GBServer.globals.users [user.userId] = user;
|
2020-11-17 08:27:10 -03:00
|
|
|
return await user.save();
|
|
|
|
}
|
|
|
|
|
2023-05-25 21:20:40 -03:00
|
|
|
public async updateUserHearOnDialog(userId: number, dialogName: string): Promise<GuaribasUser> {
|
2020-12-31 15:36:19 -03:00
|
|
|
const user = await GuaribasUser.findOne({
|
2020-12-01 18:01:53 -03:00
|
|
|
where: {
|
|
|
|
userId: userId
|
|
|
|
}
|
|
|
|
});
|
|
|
|
user.hearOnDialog = dialogName;
|
2024-08-17 21:35:09 -03:00
|
|
|
GBServer.globals.users [user.userId] = user;
|
2020-12-01 18:01:53 -03:00
|
|
|
return await user.save();
|
|
|
|
}
|
|
|
|
|
2023-05-25 21:20:40 -03:00
|
|
|
public async updateUserInstance(userSystemId: string, instanceId: number): Promise<GuaribasUser> {
|
2020-12-31 15:36:19 -03:00
|
|
|
const user = await GuaribasUser.findOne({
|
2020-01-26 17:43:50 -03:00
|
|
|
where: {
|
2019-08-22 19:36:23 -03:00
|
|
|
userSystemId: userSystemId
|
|
|
|
}
|
|
|
|
});
|
2020-05-02 21:28:13 -03:00
|
|
|
user.instanceId = instanceId;
|
2024-08-17 21:35:09 -03:00
|
|
|
GBServer.globals.users [user.userId] = user;
|
2020-05-02 21:28:13 -03:00
|
|
|
return await user.save();
|
|
|
|
}
|
|
|
|
|
2021-03-03 16:46:18 -03:00
|
|
|
/**
|
|
|
|
* Finds and update user agent information to a next available person.
|
|
|
|
*/
|
2023-05-25 21:20:40 -03:00
|
|
|
public async updateHumanAgent(
|
2020-05-02 21:28:13 -03:00
|
|
|
userSystemId: string,
|
|
|
|
instanceId: number,
|
|
|
|
agentSystemId: string
|
|
|
|
): Promise<GuaribasUser> {
|
2022-11-19 23:34:58 -03:00
|
|
|
const user = await GuaribasUser.findOne({
|
2020-05-02 21:28:13 -03:00
|
|
|
where: {
|
2021-03-03 16:46:18 -03:00
|
|
|
userSystemId: userSystemId,
|
|
|
|
instanceId: instanceId
|
2020-05-02 21:28:13 -03:00
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2022-05-19 10:22:22 -03:00
|
|
|
if (agentSystemId === null && user.agentSystemId !== undefined) {
|
2020-05-02 21:28:13 -03:00
|
|
|
const agent = await GuaribasUser.findOne({
|
|
|
|
where: {
|
|
|
|
userSystemId: user.agentSystemId
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
if (agent !== null && agent !== undefined) {
|
2020-10-18 13:24:19 -03:00
|
|
|
agent.agentMode = 'bot';
|
2020-05-02 21:28:13 -03:00
|
|
|
agent.agentSystemId = null;
|
|
|
|
await agent.save();
|
|
|
|
}
|
|
|
|
|
2020-10-18 13:24:19 -03:00
|
|
|
user.agentMode = 'bot';
|
2020-05-02 21:28:13 -03:00
|
|
|
user.agentSystemId = null;
|
|
|
|
} else {
|
2020-10-18 13:24:19 -03:00
|
|
|
user.agentMode = 'human';
|
2020-05-02 21:28:13 -03:00
|
|
|
user.agentSystemId = agentSystemId;
|
|
|
|
const agent = await GuaribasUser.findOne({
|
|
|
|
where: {
|
|
|
|
userSystemId: agentSystemId
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
agent.instanceId = user.instanceId;
|
2020-10-18 13:24:19 -03:00
|
|
|
agent.agentMode = 'self';
|
2020-05-02 21:28:13 -03:00
|
|
|
agent.agentSystemId = null;
|
2024-08-17 21:35:09 -03:00
|
|
|
GBServer.globals.users [agent.userId] = user;
|
2020-05-02 21:28:13 -03:00
|
|
|
await agent.save();
|
|
|
|
}
|
|
|
|
|
2024-08-17 21:35:09 -03:00
|
|
|
GBServer.globals.users [user.userId] = user;
|
2019-08-22 19:36:23 -03:00
|
|
|
await user.save();
|
2020-12-31 15:36:19 -03:00
|
|
|
|
2019-08-22 19:36:23 -03:00
|
|
|
return user;
|
|
|
|
}
|
|
|
|
|
2023-05-25 21:20:40 -03:00
|
|
|
public async isAgentSystemId(systemId: string): Promise<Boolean> {
|
2020-12-31 15:36:19 -03:00
|
|
|
const user = await GuaribasUser.findOne({
|
2020-05-02 21:28:13 -03:00
|
|
|
where: {
|
|
|
|
userSystemId: systemId
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
if (user === null) {
|
2020-12-31 15:36:19 -03:00
|
|
|
throw new Error(`TRANSFER_TO phones must talk first to the bot before becoming an agent.`);
|
2020-05-02 21:28:13 -03:00
|
|
|
}
|
|
|
|
|
2020-10-18 13:24:19 -03:00
|
|
|
return user.agentMode === 'self';
|
2020-05-02 21:28:13 -03:00
|
|
|
}
|
|
|
|
|
2023-05-25 21:20:40 -03:00
|
|
|
public async assignHumanAgent(
|
2022-11-19 23:34:58 -03:00
|
|
|
min: GBMinInstance,
|
|
|
|
userSystemId: string,
|
|
|
|
agentSystemId: string = null
|
|
|
|
): Promise<string> {
|
2022-05-19 10:22:22 -03:00
|
|
|
if (!agentSystemId) {
|
2022-11-19 23:34:58 -03:00
|
|
|
let list = min.core.getParam<string>(min.instance, 'Transfer To', process.env.TRANSFER_TO);
|
2022-05-19 10:22:22 -03:00
|
|
|
|
|
|
|
if (list) {
|
2022-11-19 23:34:58 -03:00
|
|
|
list = list.split(';');
|
2022-05-19 10:22:22 -03:00
|
|
|
}
|
|
|
|
|
|
|
|
await CollectionUtil.asyncForEach(list, async item => {
|
|
|
|
if (
|
|
|
|
item !== undefined &&
|
2023-07-19 07:53:02 -03:00
|
|
|
!agentSystemId &&
|
2022-11-19 23:34:58 -03:00
|
|
|
item !== userSystemId &&
|
|
|
|
!(await this.isAgentSystemId(item))
|
2022-05-19 10:22:22 -03:00
|
|
|
) {
|
|
|
|
agentSystemId = item;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
2024-04-21 23:39:39 -03:00
|
|
|
GBLogEx.info(min, `Selected agentId: ${agentSystemId}`);
|
2022-04-26 15:13:19 -03:00
|
|
|
await this.updateHumanAgent(userSystemId, min.instance.instanceId, agentSystemId);
|
2024-04-21 23:39:39 -03:00
|
|
|
GBLogEx.info(min, `Updated agentId to: ${agentSystemId}`);
|
2022-05-19 10:22:22 -03:00
|
|
|
|
2020-05-02 21:28:13 -03:00
|
|
|
return agentSystemId;
|
|
|
|
}
|
|
|
|
|
2023-05-25 21:20:40 -03:00
|
|
|
public async getUserFromId(instanceId: number, userId: string): Promise<GuaribasUser> {
|
2023-01-13 16:09:45 -03:00
|
|
|
return await GuaribasUser.findOne({
|
|
|
|
where: {
|
|
|
|
instanceId: instanceId,
|
|
|
|
userId: userId
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2023-05-25 21:20:40 -03:00
|
|
|
public async getUserFromSystemId(systemId: string): Promise<GuaribasUser> {
|
2019-08-22 19:36:23 -03:00
|
|
|
return await GuaribasUser.findOne({
|
|
|
|
where: {
|
2020-05-02 21:28:13 -03:00
|
|
|
userSystemId: systemId
|
2019-08-22 19:36:23 -03:00
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2023-05-25 21:20:40 -03:00
|
|
|
public async getUserFromAgentSystemId(systemId: string): Promise<GuaribasUser> {
|
2020-05-02 21:28:13 -03:00
|
|
|
return await GuaribasUser.findOne({
|
|
|
|
where: {
|
2020-10-18 13:24:19 -03:00
|
|
|
agentSystemId: systemId
|
2020-05-02 21:28:13 -03:00
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
2019-08-22 19:36:23 -03:00
|
|
|
|
2023-05-25 21:20:40 -03:00
|
|
|
public async getAllUsers(instanceId: number): Promise<GuaribasUser[]> {
|
2020-10-18 13:24:19 -03:00
|
|
|
return await GuaribasUser.findAll({
|
|
|
|
where: {
|
|
|
|
instanceId: instanceId
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
2023-01-31 10:08:48 -03:00
|
|
|
|
2023-08-14 09:06:18 -03:00
|
|
|
public async getUserFromUsername(instanceId: number, username: string): Promise<GuaribasUser> {
|
|
|
|
return await GuaribasUser.findOne({
|
|
|
|
where: {
|
|
|
|
instanceId: instanceId,
|
|
|
|
userName: username
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2023-01-31 10:08:48 -03:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Get a dynamic param from user. Dynamic params are defined in .gbdialog SET
|
|
|
|
* variables and other semantics during conversation.
|
|
|
|
*
|
|
|
|
* @param name Name of param to get from instance.
|
|
|
|
* @param defaultValue Value returned when no param is defined.
|
|
|
|
*/
|
2023-05-25 21:20:40 -03:00
|
|
|
public getParam<T>(user: GuaribasUser, name: string, defaultValue?: T): any {
|
2023-01-31 10:08:48 -03:00
|
|
|
let value = null;
|
|
|
|
if (user.params) {
|
|
|
|
const params = JSON.parse(user.params);
|
|
|
|
value = params ? params[name] : defaultValue;
|
|
|
|
}
|
|
|
|
if (typeof defaultValue === 'boolean') {
|
|
|
|
return new Boolean(value ? value.toString().toLowerCase() === 'true' : defaultValue);
|
|
|
|
}
|
|
|
|
if (typeof defaultValue === 'string') {
|
|
|
|
return value ? value : defaultValue;
|
|
|
|
}
|
|
|
|
if (typeof defaultValue === 'number') {
|
|
|
|
return new Number(value ? value : defaultValue ? defaultValue : 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (user['dataValues'] && !value) {
|
|
|
|
value = user['dataValues'][name];
|
|
|
|
if (value === null) {
|
2023-05-25 21:20:40 -03:00
|
|
|
switch (name) {
|
2023-01-31 10:08:48 -03:00
|
|
|
case 'language':
|
|
|
|
value = 'en';
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
/**
|
|
|
|
* Saves user instance object to the storage handling
|
|
|
|
* multi-column JSON based store 'params' field.
|
|
|
|
*/
|
2023-05-25 21:20:40 -03:00
|
|
|
public async setParam(userId: number, name: string, value: any) {
|
2023-01-31 10:08:48 -03:00
|
|
|
const options = { where: {} };
|
2023-01-31 23:11:06 -03:00
|
|
|
options.where = { userId: userId };
|
2023-01-31 10:08:48 -03:00
|
|
|
let user = await GuaribasUser.findOne(options);
|
|
|
|
// tslint:disable-next-line:prefer-object-spread
|
2023-05-25 21:20:40 -03:00
|
|
|
let obj = JSON.parse(user.params);
|
|
|
|
if (!obj) {
|
2023-01-31 23:11:06 -03:00
|
|
|
obj = {};
|
|
|
|
}
|
2023-04-09 19:20:15 -03:00
|
|
|
obj[name] = value;
|
2023-01-31 10:08:48 -03:00
|
|
|
user.params = JSON.stringify(obj);
|
2024-08-17 21:35:09 -03:00
|
|
|
GBServer.globals.users [userId] = user;
|
2023-01-31 10:08:48 -03:00
|
|
|
return await user.save();
|
|
|
|
}
|
|
|
|
}
|