Skip to content

Commit 9b38f47

Browse files
committed
feat(chatbot): add /chatbot/manage REST endpoint
- Create ChatbotManageController with actions: transfer_human, resolve_bot, pause_bot, resume_bot - Create ChatbotManageDto and JSONSchema7 validation - Create ChatbotManageRouter with POST /action and GET /status - Register routes in chatbot.router.ts and export schema
1 parent fb60119 commit 9b38f47

6 files changed

Lines changed: 140 additions & 0 deletions

File tree

src/api/integrations/chatbot/chatbot.router.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { ChatwootRouter } from '@api/integrations/chatbot/chatwoot/routes/chatwoot.router';
22
import { DifyRouter } from '@api/integrations/chatbot/dify/routes/dify.router';
3+
import { ChatbotManageRouter } from '@api/integrations/chatbot/manage/routes/chatbot-manage.router';
34
import { OpenaiRouter } from '@api/integrations/chatbot/openai/routes/openai.router';
45
import { TypebotRouter } from '@api/integrations/chatbot/typebot/routes/typebot.router';
56
import { Router } from 'express';
@@ -23,5 +24,6 @@ export class ChatbotRouter {
2324
this.router.use('/flowise', new FlowiseRouter(...guards).router);
2425
this.router.use('/n8n', new N8nRouter(...guards).router);
2526
this.router.use('/evoai', new EvoaiRouter(...guards).router);
27+
this.router.use('/manage', new ChatbotManageRouter(...guards).router);
2628
}
2729
}

src/api/integrations/chatbot/chatbot.schema.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ export * from '@api/integrations/chatbot/dify/validate/dify.schema';
33
export * from '@api/integrations/chatbot/evoai/validate/evoai.schema';
44
export * from '@api/integrations/chatbot/evolutionBot/validate/evolutionBot.schema';
55
export * from '@api/integrations/chatbot/flowise/validate/flowise.schema';
6+
export * from '@api/integrations/chatbot/manage/validate/chatbot-manage.schema';
67
export * from '@api/integrations/chatbot/n8n/validate/n8n.schema';
78
export * from '@api/integrations/chatbot/openai/validate/openai.schema';
89
export * from '@api/integrations/chatbot/typebot/validate/typebot.schema';
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import { InstanceDto } from '@api/dto/instance.dto';
2+
import { ChatbotChatwootService } from '@api/integrations/chatbot/chatbot-chatwoot.service';
3+
import { PrismaRepository } from '@api/repository/repository.service';
4+
import { Logger } from '@config/logger.config';
5+
import { BadRequestException } from '@exceptions';
6+
7+
import { ChatbotManageDto } from '../dto/chatbot-manage.dto';
8+
9+
export class ChatbotManageController {
10+
private readonly logger = new Logger('ChatbotManageController');
11+
12+
constructor(
13+
private readonly chatbotChatwootService: ChatbotChatwootService,
14+
private readonly prismaRepository: PrismaRepository,
15+
) {}
16+
17+
public async manage(instance: InstanceDto, data: ChatbotManageDto) {
18+
const instanceDb = await this.prismaRepository.instance.findFirst({
19+
where: { name: instance.instanceName },
20+
});
21+
22+
if (!instanceDb) {
23+
throw new BadRequestException('Instance not found');
24+
}
25+
26+
if (!data.remoteJid) {
27+
throw new BadRequestException('remoteJid is required');
28+
}
29+
30+
// Normalize remoteJid
31+
const remoteJid = data.remoteJid.includes('@') ? data.remoteJid : `${data.remoteJid}@s.whatsapp.net`;
32+
33+
this.logger.log(`[Manage] action=${data.action}, instance=${instance.instanceName}, remoteJid=${remoteJid}`);
34+
35+
switch (data.action) {
36+
case 'transfer_human': {
37+
const result = await this.chatbotChatwootService.transferToHuman(
38+
instanceDb.id,
39+
remoteJid,
40+
data.chatwoot?.assigneeId,
41+
data.chatwoot?.teamId,
42+
);
43+
return { action: 'transfer_human', ...result };
44+
}
45+
46+
case 'resolve_bot': {
47+
const resolveChatwoot = data.chatwoot?.status !== undefined ? data.chatwoot.status === 'resolved' : true;
48+
const result = await this.chatbotChatwootService.resolveBot(instanceDb.id, remoteJid, resolveChatwoot);
49+
return { action: 'resolve_bot', ...result };
50+
}
51+
52+
case 'pause_bot': {
53+
const result = await this.chatbotChatwootService.pauseBot(instanceDb.id, remoteJid);
54+
return { action: 'pause_bot', ...result };
55+
}
56+
57+
case 'resume_bot': {
58+
const result = await this.chatbotChatwootService.resumeBot(instanceDb.id, remoteJid);
59+
return { action: 'resume_bot', ...result };
60+
}
61+
62+
default:
63+
throw new BadRequestException(`Invalid action: ${data.action}. Valid actions: transfer_human, resolve_bot, pause_bot, resume_bot`);
64+
}
65+
}
66+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
export class ChatbotManageDto {
2+
action: 'transfer_human' | 'resolve_bot' | 'pause_bot' | 'resume_bot';
3+
remoteJid: string;
4+
chatwoot?: {
5+
status?: 'open' | 'resolved' | 'pending';
6+
assigneeId?: number;
7+
teamId?: number;
8+
};
9+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import { RouterBroker } from '@api/abstract/abstract.router';
2+
import { InstanceDto } from '@api/dto/instance.dto';
3+
import { ChatbotManageDto } from '@api/integrations/chatbot/manage/dto/chatbot-manage.dto';
4+
import { chatbotManageSchema } from '@api/integrations/chatbot/manage/validate/chatbot-manage.schema';
5+
import { HttpStatus } from '@api/routes/index.router';
6+
import { chatbotManageController } from '@api/server.module';
7+
import { instanceSchema } from '@validate/validate.schema';
8+
import { RequestHandler, Router } from 'express';
9+
10+
export class ChatbotManageRouter extends RouterBroker {
11+
constructor(...guards: RequestHandler[]) {
12+
super();
13+
this.router
14+
.post(this.routerPath('action'), ...guards, async (req, res) => {
15+
const response = await this.dataValidate<ChatbotManageDto>({
16+
request: req,
17+
schema: chatbotManageSchema,
18+
ClassRef: ChatbotManageDto,
19+
execute: (instance, data) => chatbotManageController.manage(instance, data),
20+
});
21+
22+
res.status(HttpStatus.OK).json(response);
23+
})
24+
.get(this.routerPath('status'), ...guards, async (req, res) => {
25+
const response = await this.dataValidate<InstanceDto>({
26+
request: req,
27+
schema: instanceSchema,
28+
ClassRef: InstanceDto,
29+
execute: async (instance) => {
30+
return { status: 'ok', integration: 'chatbot-chatwoot-coordination', instance: instance.instanceName };
31+
},
32+
});
33+
34+
res.status(HttpStatus.OK).json(response);
35+
});
36+
}
37+
38+
public readonly router: Router = Router();
39+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { JSONSchema7 } from 'json-schema';
2+
import { v4 } from 'uuid';
3+
4+
export const chatbotManageSchema: JSONSchema7 = {
5+
$id: v4(),
6+
type: 'object',
7+
properties: {
8+
action: {
9+
type: 'string',
10+
enum: ['transfer_human', 'resolve_bot', 'pause_bot', 'resume_bot'],
11+
},
12+
remoteJid: { type: 'string' },
13+
chatwoot: {
14+
type: 'object',
15+
properties: {
16+
status: { type: 'string', enum: ['open', 'resolved', 'pending'] },
17+
assigneeId: { type: 'integer' },
18+
teamId: { type: 'integer' },
19+
},
20+
},
21+
},
22+
required: ['action', 'remoteJid'],
23+
};

0 commit comments

Comments
 (0)