Skip to content

Commit 3b3118d

Browse files
committed
Added Typebot integration
1 parent 8438684 commit 3b3118d

File tree

13 files changed

+648
-2
lines changed

13 files changed

+648
-2
lines changed

src/validate/validate.schema.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -974,3 +974,16 @@ export const rabbitmqSchema: JSONSchema7 = {
974974
required: ['enabled'],
975975
...isNotEmpty('enabled'),
976976
};
977+
978+
export const typebotSchema: JSONSchema7 = {
979+
$id: v4(),
980+
type: 'object',
981+
properties: {
982+
enabled: { type: 'boolean', enum: [true, false] },
983+
url: { type: 'string' },
984+
typebot: { type: 'string' },
985+
expire: { type: 'integer' },
986+
},
987+
required: ['enabled', 'url', 'typebot', 'expire'],
988+
...isNotEmpty('enabled', 'url', 'typebot', 'expire'),
989+
};
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import { Logger } from '../../config/logger.config';
2+
import { InstanceDto } from '../dto/instance.dto';
3+
import { TypebotDto } from '../dto/typebot.dto';
4+
import { TypebotService } from '../services/typebot.service';
5+
6+
const logger = new Logger('TypebotController');
7+
8+
export class TypebotController {
9+
constructor(private readonly typebotService: TypebotService) {}
10+
11+
public async createTypebot(instance: InstanceDto, data: TypebotDto) {
12+
logger.verbose('requested createTypebot from ' + instance.instanceName + ' instance');
13+
14+
if (!data.enabled) {
15+
logger.verbose('typebot disabled');
16+
data.url = '';
17+
data.typebot = '';
18+
data.expire = 0;
19+
data.sessions = [];
20+
} else {
21+
const saveData = await this.typebotService.find(instance);
22+
23+
if (saveData.enabled) {
24+
logger.verbose('typebot enabled');
25+
data.sessions = saveData.sessions;
26+
}
27+
}
28+
29+
return this.typebotService.create(instance, data);
30+
}
31+
32+
public async findTypebot(instance: InstanceDto) {
33+
logger.verbose('requested findTypebot from ' + instance.instanceName + ' instance');
34+
return this.typebotService.find(instance);
35+
}
36+
}

src/whatsapp/dto/typebot.dto.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
export class Session {
2+
remoteJid?: string;
3+
sessionId?: string;
4+
createdAt?: number;
5+
updateAt?: number;
6+
}
7+
8+
export class TypebotDto {
9+
enabled?: boolean;
10+
url: string;
11+
typebot?: string;
12+
expire?: number;
13+
sessions?: Session[];
14+
}

src/whatsapp/models/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,6 @@ export * from './contact.model';
55
export * from './message.model';
66
export * from './rabbitmq.model';
77
export * from './settings.model';
8+
export * from './typebot.model';
89
export * from './webhook.model';
910
export * from './websocket.model';

src/whatsapp/models/typebot.model.ts

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import { Schema } from 'mongoose';
2+
3+
import { dbserver } from '../../libs/db.connect';
4+
5+
class Session {
6+
remoteJid?: string;
7+
sessionId?: string;
8+
createdAt?: number;
9+
updateAt?: number;
10+
}
11+
12+
export class TypebotRaw {
13+
_id?: string;
14+
enabled?: boolean;
15+
url: string;
16+
typebot?: string;
17+
expire?: number;
18+
sessions?: Session[];
19+
}
20+
21+
const typebotSchema = new Schema<TypebotRaw>({
22+
_id: { type: String, _id: true },
23+
enabled: { type: Boolean, required: true },
24+
url: { type: String, required: true },
25+
typebot: { type: String, required: true },
26+
expire: { type: Number, required: true },
27+
sessions: [
28+
{
29+
remoteJid: { type: String, required: true },
30+
sessionId: { type: String, required: true },
31+
createdAt: { type: Number, required: true },
32+
updateAt: { type: Number, required: true },
33+
},
34+
],
35+
});
36+
37+
export const TypebotModel = dbserver?.model(TypebotRaw.name, typebotSchema, 'typebot');
38+
export type ITypebotModel = typeof TypebotModel;

src/whatsapp/repository/repository.manager.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import { MessageRepository } from './message.repository';
1212
import { MessageUpRepository } from './messageUp.repository';
1313
import { RabbitmqRepository } from './rabbitmq.repository';
1414
import { SettingsRepository } from './settings.repository';
15+
import { TypebotRepository } from './typebot.repository';
1516
import { WebhookRepository } from './webhook.repository';
1617
import { WebsocketRepository } from './websocket.repository';
1718
export class RepositoryBroker {
@@ -25,6 +26,7 @@ export class RepositoryBroker {
2526
public readonly settings: SettingsRepository,
2627
public readonly websocket: WebsocketRepository,
2728
public readonly rabbitmq: RabbitmqRepository,
29+
public readonly typebot: TypebotRepository,
2830
public readonly auth: AuthRepository,
2931
private configService: ConfigService,
3032
dbServer?: MongoClient,
@@ -57,6 +59,7 @@ export class RepositoryBroker {
5759
const settingsDir = join(storePath, 'settings');
5860
const websocketDir = join(storePath, 'websocket');
5961
const rabbitmqDir = join(storePath, 'rabbitmq');
62+
const typebotDir = join(storePath, 'typebot');
6063
const tempDir = join(storePath, 'temp');
6164

6265
if (!fs.existsSync(authDir)) {
@@ -99,6 +102,10 @@ export class RepositoryBroker {
99102
this.logger.verbose('creating rabbitmq dir: ' + rabbitmqDir);
100103
fs.mkdirSync(rabbitmqDir, { recursive: true });
101104
}
105+
if (!fs.existsSync(typebotDir)) {
106+
this.logger.verbose('creating typebot dir: ' + typebotDir);
107+
fs.mkdirSync(typebotDir, { recursive: true });
108+
}
102109
if (!fs.existsSync(tempDir)) {
103110
this.logger.verbose('creating temp dir: ' + tempDir);
104111
fs.mkdirSync(tempDir, { recursive: true });
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
import { readFileSync } from 'fs';
2+
import { join } from 'path';
3+
4+
import { ConfigService } from '../../config/env.config';
5+
import { Logger } from '../../config/logger.config';
6+
import { IInsert, Repository } from '../abstract/abstract.repository';
7+
import { ITypebotModel, TypebotRaw } from '../models';
8+
9+
export class TypebotRepository extends Repository {
10+
constructor(private readonly typebotModel: ITypebotModel, private readonly configService: ConfigService) {
11+
super(configService);
12+
}
13+
14+
private readonly logger = new Logger('TypebotRepository');
15+
16+
public async create(data: TypebotRaw, instance: string): Promise<IInsert> {
17+
try {
18+
this.logger.verbose('creating typebot');
19+
if (this.dbSettings.ENABLED) {
20+
this.logger.verbose('saving typebot to db');
21+
const insert = await this.typebotModel.replaceOne({ _id: instance }, { ...data }, { upsert: true });
22+
23+
this.logger.verbose('typebot saved to db: ' + insert.modifiedCount + ' typebot');
24+
return { insertCount: insert.modifiedCount };
25+
}
26+
27+
this.logger.verbose('saving typebot to store');
28+
29+
this.writeStore<TypebotRaw>({
30+
path: join(this.storePath, 'typebot'),
31+
fileName: instance,
32+
data,
33+
});
34+
35+
this.logger.verbose('typebot saved to store in path: ' + join(this.storePath, 'typebot') + '/' + instance);
36+
37+
this.logger.verbose('typebot created');
38+
return { insertCount: 1 };
39+
} catch (error) {
40+
return error;
41+
}
42+
}
43+
44+
public async find(instance: string): Promise<TypebotRaw> {
45+
try {
46+
this.logger.verbose('finding typebot');
47+
if (this.dbSettings.ENABLED) {
48+
this.logger.verbose('finding typebot in db');
49+
return await this.typebotModel.findOne({ _id: instance });
50+
}
51+
52+
this.logger.verbose('finding typebot in store');
53+
return JSON.parse(
54+
readFileSync(join(this.storePath, 'typebot', instance + '.json'), {
55+
encoding: 'utf-8',
56+
}),
57+
) as TypebotRaw;
58+
} catch (error) {
59+
return {
60+
enabled: false,
61+
url: '',
62+
typebot: '',
63+
expire: 0,
64+
sessions: [],
65+
};
66+
}
67+
}
68+
}

src/whatsapp/routers/index.router.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { InstanceRouter } from './instance.router';
1111
import { RabbitmqRouter } from './rabbitmq.router';
1212
import { MessageRouter } from './sendMessage.router';
1313
import { SettingsRouter } from './settings.router';
14+
import { TypebotRouter } from './typebot.router';
1415
import { ViewsRouter } from './view.router';
1516
import { WebhookRouter } from './webhook.router';
1617
import { WebsocketRouter } from './websocket.router';
@@ -48,6 +49,7 @@ router
4849
.use('/chatwoot', new ChatwootRouter(...guards).router)
4950
.use('/settings', new SettingsRouter(...guards).router)
5051
.use('/websocket', new WebsocketRouter(...guards).router)
51-
.use('/rabbitmq', new RabbitmqRouter(...guards).router);
52+
.use('/rabbitmq', new RabbitmqRouter(...guards).router)
53+
.use('/typebot', new TypebotRouter(...guards).router);
5254

5355
export { HttpStatus, router };
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import { RequestHandler, Router } from 'express';
2+
3+
import { Logger } from '../../config/logger.config';
4+
import { instanceNameSchema, typebotSchema } from '../../validate/validate.schema';
5+
import { RouterBroker } from '../abstract/abstract.router';
6+
import { InstanceDto } from '../dto/instance.dto';
7+
import { TypebotDto } from '../dto/typebot.dto';
8+
import { typebotController } from '../whatsapp.module';
9+
import { HttpStatus } from './index.router';
10+
11+
const logger = new Logger('TypebotRouter');
12+
13+
export class TypebotRouter extends RouterBroker {
14+
constructor(...guards: RequestHandler[]) {
15+
super();
16+
this.router
17+
.post(this.routerPath('set'), ...guards, async (req, res) => {
18+
logger.verbose('request received in setTypebot');
19+
logger.verbose('request body: ');
20+
logger.verbose(req.body);
21+
22+
logger.verbose('request query: ');
23+
logger.verbose(req.query);
24+
const response = await this.dataValidate<TypebotDto>({
25+
request: req,
26+
schema: typebotSchema,
27+
ClassRef: TypebotDto,
28+
execute: (instance, data) => typebotController.createTypebot(instance, data),
29+
});
30+
31+
res.status(HttpStatus.CREATED).json(response);
32+
})
33+
.get(this.routerPath('find'), ...guards, async (req, res) => {
34+
logger.verbose('request received in findTypebot');
35+
logger.verbose('request body: ');
36+
logger.verbose(req.body);
37+
38+
logger.verbose('request query: ');
39+
logger.verbose(req.query);
40+
const response = await this.dataValidate<InstanceDto>({
41+
request: req,
42+
schema: instanceNameSchema,
43+
ClassRef: InstanceDto,
44+
execute: (instance) => typebotController.findTypebot(instance),
45+
});
46+
47+
res.status(HttpStatus.OK).json(response);
48+
});
49+
}
50+
51+
public readonly router = Router();
52+
}

0 commit comments

Comments
 (0)