Skip to content

Commit 488a7af

Browse files
authored
πŸš€ release: v0.1.1-alpha - Merge pull request #4 from wgtechlabs/dev
2 parents be4d1da + b3bd4f2 commit 488a7af

File tree

6 files changed

+235
-47
lines changed

6 files changed

+235
-47
lines changed

β€ŽREADME.md

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,12 @@ The Unthread Telegram Bot seamlessly connects your Telegram community with Unthr
88

99
With simple commands and intuitive interactions, support tickets automatically sync between both platforms, streamlining your workflow and improving response times. Whether you're managing a community group, running a business chat, or supporting an open-source project, this bot provides the tools you need for efficient, organized customer support.
1010

11+
## πŸ’Έ Sponsored Ads
12+
13+
Open source development is resource-intensive. These **sponsored ads help keep Log Engine free and actively maintained** while connecting you with tools and services that support open-source development.
14+
15+
[![sponsored ads](https://gitads.dev/v1/ad-serve?source=wgtechlabs/unthread-telegram-bot@github)](https://gitads.dev/v1/ad-track?source=wgtechlabs/unthread-telegram-bot@github)
16+
1117
## πŸ€” How It Works
1218

1319
The Unthread Telegram Bot creates a seamless bridge between your Telegram group chats and Unthread's ticket management system. Here's how it works:
@@ -415,4 +421,6 @@ This project is created by **[Waren Gonzaga](https://github.com/warengonzaga)**
415421

416422
---
417423

418-
πŸ’» with ❀️ by [Waren Gonzaga](https://warengonzaga.com) under [WG Technology Labs](https://wgtechlabs.com), and [Him](https://www.youtube.com/watch?v=HHrxS4diLew&t=44s) πŸ™
424+
πŸ’» with ❀️ by [Waren Gonzaga](https://warengonzaga.com) under [WG Technology Labs](https://wgtechlabs.com), and [Him](https://www.youtube.com/watch?v=HHrxS4diLew&t=44s) πŸ™
425+
426+
<!-- GitAds-Verify: SKBGYTYZU867TO8VU9UB6VRLMN1V8RXA -->

β€Žsrc/events/message.js

Lines changed: 55 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -102,18 +102,40 @@ async function handleTicketReply(ctx) {
102102
// Get the ID of the message being replied to
103103
const replyToMessageId = ctx.message.reply_to_message.message_id;
104104

105+
LogEngine.info('Processing potential ticket reply', {
106+
replyToMessageId,
107+
messageText: ctx.message.text?.substring(0, 100),
108+
chatId: ctx.chat.id,
109+
userId: ctx.from.id
110+
});
111+
105112
// Check if this is a reply to a ticket confirmation
106113
const ticketInfo = await unthreadService.getTicketFromReply(replyToMessageId);
107114
if (ticketInfo) {
115+
LogEngine.info('Found ticket for reply', {
116+
ticketId: ticketInfo.ticketId,
117+
friendlyId: ticketInfo.friendlyId,
118+
replyToMessageId
119+
});
108120
return await handleTicketConfirmationReply(ctx, ticketInfo);
109121
}
110122

111123
// Check if this is a reply to an agent message
112124
const agentMessageInfo = await unthreadService.getAgentMessageFromReply(replyToMessageId);
113125
if (agentMessageInfo) {
126+
LogEngine.info('Found agent message for reply', {
127+
conversationId: agentMessageInfo.conversationId,
128+
friendlyId: agentMessageInfo.friendlyId,
129+
replyToMessageId
130+
});
114131
return await handleAgentMessageReply(ctx, agentMessageInfo);
115132
}
116133

134+
LogEngine.debug('No ticket or agent message found for reply', {
135+
replyToMessageId,
136+
chatId: ctx.chat.id
137+
});
138+
117139
return false;
118140
} catch (error) {
119141
LogEngine.error('Error in handleTicketReply', {
@@ -139,6 +161,15 @@ async function handleTicketConfirmationReply(ctx, ticketInfo) {
139161
const username = ctx.from.username;
140162
const message = ctx.message.text;
141163

164+
LogEngine.info('Processing ticket confirmation reply', {
165+
conversationId: ticketInfo.conversationId,
166+
ticketId: ticketInfo.ticketId,
167+
friendlyId: ticketInfo.friendlyId,
168+
telegramUserId,
169+
username,
170+
messageLength: message?.length
171+
});
172+
142173
// Send a waiting message
143174
const waitingMsg = await ctx.reply("Adding your message to the ticket...", {
144175
reply_to_message_id: ctx.message.message_id
@@ -148,9 +179,15 @@ async function handleTicketConfirmationReply(ctx, ticketInfo) {
148179
// Get user information from database
149180
const userData = await unthreadService.getOrCreateUser(telegramUserId, username);
150181

151-
// Send the message to the ticket
182+
LogEngine.info('Retrieved user data for ticket reply', {
183+
userData: JSON.stringify(userData),
184+
hasName: !!userData.name,
185+
hasEmail: !!userData.email
186+
});
187+
188+
// Send the message to the ticket using conversationId (which is the same as ticketId)
152189
await unthreadService.sendMessage({
153-
conversationId: ticketInfo.ticketId,
190+
conversationId: ticketInfo.conversationId || ticketInfo.ticketId,
154191
message,
155192
onBehalfOf: userData
156193
});
@@ -165,7 +202,7 @@ async function handleTicketConfirmationReply(ctx, ticketInfo) {
165202

166203
LogEngine.info('Added message to ticket', {
167204
ticketNumber: ticketInfo.friendlyId,
168-
ticketId: ticketInfo.ticketId,
205+
conversationId: ticketInfo.conversationId || ticketInfo.ticketId,
169206
telegramUserId,
170207
username,
171208
messageLength: message?.length,
@@ -177,7 +214,10 @@ async function handleTicketConfirmationReply(ctx, ticketInfo) {
177214
// Handle API errors
178215
LogEngine.error('Error adding message to ticket', {
179216
error: error.message,
180-
ticketId: ticketInfo.ticketId
217+
stack: error.stack,
218+
conversationId: ticketInfo.conversationId || ticketInfo.ticketId,
219+
telegramUserId,
220+
username
181221
});
182222

183223
// Update the waiting message with error
@@ -194,6 +234,7 @@ async function handleTicketConfirmationReply(ctx, ticketInfo) {
194234
} catch (error) {
195235
LogEngine.error('Error in handleTicketReply', {
196236
error: error.message,
237+
stack: error.stack,
197238
chatId: ctx.chat?.id
198239
});
199240
return false;
@@ -220,12 +261,14 @@ async function handleAgentMessageReply(ctx, agentMessageInfo) {
220261
});
221262

222263
try {
264+
// Get user information for proper onBehalfOf formatting
265+
const userData = await unthreadService.getOrCreateUser(telegramUserId, username);
266+
223267
// Send the message to the conversation
224268
await unthreadService.sendMessage({
225269
conversationId: agentMessageInfo.conversationId,
226270
message,
227-
username,
228-
telegramUserId
271+
onBehalfOf: userData
229272
});
230273

231274
// Update the waiting message with success
@@ -235,7 +278,12 @@ async function handleAgentMessageReply(ctx, agentMessageInfo) {
235278
null,
236279
`βœ… Your reply has been sent to the agent for Ticket #${agentMessageInfo.friendlyId}`
237280
);
238-
281+
282+
// Auto-delete the confirmation message after 1 minute
283+
setTimeout(() => {
284+
ctx.telegram.deleteMessage(ctx.chat.id, waitingMsg.message_id).catch(() => {});
285+
}, 5000); // 5,000 ms = 5 seconds
286+
239287
LogEngine.info('Sent reply to agent', {
240288
ticketNumber: agentMessageInfo.friendlyId,
241289
conversationId: agentMessageInfo.conversationId,

β€Žsrc/handlers/webhookMessage.js

Lines changed: 42 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ export class TelegramWebhookHandler {
2020
*/
2121
async handleMessageCreated(event) {
2222
try {
23-
LogEngine.info('Processing agent message webhook', {
23+
LogEngine.info('πŸ”„ Processing agent message webhook', {
2424
conversationId: event.data.conversationId,
2525
textLength: event.data.content?.length || 0,
2626
sentBy: event.data.userId,
@@ -30,28 +30,58 @@ export class TelegramWebhookHandler {
3030
// 1. Get conversation ID from webhook event
3131
const conversationId = event.data.conversationId;
3232
if (!conversationId) {
33-
LogEngine.warn('No conversation ID in webhook event', { event });
33+
LogEngine.warn('❌ No conversation ID in webhook event', { event });
3434
return;
3535
}
3636

37+
LogEngine.info('πŸ” Looking up ticket for conversation', { conversationId });
38+
3739
// 2. Look up original ticket message using bots-brain
3840
const ticketData = await this.botsStore.getTicketByConversationId(conversationId);
3941
if (!ticketData) {
40-
LogEngine.warn(`No ticket found for conversation: ${conversationId}`);
42+
LogEngine.warn(`❌ No ticket found for conversation: ${conversationId}`);
4143
return;
4244
}
4345

44-
// 3. Validate message content
45-
const messageText = event.data.content;
46+
LogEngine.info('βœ… Ticket found', {
47+
conversationId,
48+
friendlyId: ticketData.friendlyId,
49+
chatId: ticketData.chatId,
50+
messageId: ticketData.messageId
51+
});
52+
53+
// 3. Validate message content - check both 'content' and 'text' fields
54+
const messageText = event.data.content || event.data.text;
4655
if (!messageText || messageText.trim().length === 0) {
47-
LogEngine.warn('Empty message text in webhook event', { conversationId });
56+
LogEngine.warn('❌ Empty message text in webhook event', {
57+
conversationId,
58+
hasContent: !!event.data.content,
59+
hasText: !!event.data.text
60+
});
4861
return;
4962
}
5063

64+
LogEngine.info('βœ… Message content validated', {
65+
conversationId,
66+
messageLength: messageText.length,
67+
messagePreview: messageText.substring(0, 100) + (messageText.length > 100 ? '...' : '')
68+
});
69+
5170
// 4. Format agent message for Telegram
5271
const formattedMessage = this.formatAgentMessage(messageText, ticketData.friendlyId);
72+
73+
LogEngine.info('βœ… Message formatted for Telegram', {
74+
conversationId,
75+
formattedLength: formattedMessage.length
76+
});
5377

5478
// 5. Send agent message as reply to original ticket message
79+
LogEngine.info('πŸ“€ Attempting to send message to Telegram', {
80+
conversationId,
81+
chatId: ticketData.chatId,
82+
replyToMessageId: ticketData.messageId
83+
});
84+
5585
try {
5686
const sentMessage = await this.bot.telegram.sendMessage(
5787
ticketData.chatId,
@@ -73,7 +103,7 @@ export class TelegramWebhookHandler {
73103
sentAt: new Date().toISOString()
74104
});
75105

76-
this. LogEngine.info('Agent message delivered to Telegram', {
106+
LogEngine.info('βœ…πŸŽ‰ Agent message delivered to Telegram successfully!', {
77107
conversationId,
78108
chatId: ticketData.chatId,
79109
replyToMessageId: ticketData.messageId,
@@ -100,13 +130,13 @@ export class TelegramWebhookHandler {
100130
}
101131
);
102132

103-
this.LogEngine.info('Agent message sent as new message (fallback)', {
133+
LogEngine.info('Agent message sent as new message (fallback)', {
104134
conversationId,
105135
chatId: ticketData.chatId
106136
});
107137

108138
} catch (fallbackError) {
109-
this.LogEngine.error('Failed to send fallback message to Telegram', {
139+
LogEngine.error('Failed to send fallback message to Telegram', {
110140
error: fallbackError.message,
111141
chatId: ticketData.chatId,
112142
conversationId
@@ -116,7 +146,7 @@ export class TelegramWebhookHandler {
116146
}
117147

118148
} catch (error) {
119-
this.LogEngine.error('Error handling webhook message', {
149+
LogEngine.error('Error handling webhook message', {
120150
error: error.message,
121151
stack: error.stack,
122152
event: event
@@ -135,13 +165,11 @@ export class TelegramWebhookHandler {
135165
// Clean and truncate message if too long
136166
const cleanText = this.sanitizeMessageText(text);
137167
const maxLength = 4000; // Telegram message limit is 4096, leave some room
138-
139168
let truncatedText = cleanText;
140169
if (cleanText.length > maxLength) {
141170
truncatedText = cleanText.substring(0, maxLength - 50) + '...\n\n_Message truncated_';
142171
}
143-
144-
return `🎧 **Agent Response** (${friendlyId})\n\n${truncatedText}`;
172+
return `🎫 Ticket #${friendlyId}\n\nπŸ’¬ Response:\n${truncatedText}\n\n──────────\nπŸ“ Reply to this message to respond or add more info to your ticket.`;
145173
}
146174

147175
/**
@@ -172,7 +200,7 @@ export class TelegramWebhookHandler {
172200
* @param {Object} event - The webhook event data
173201
*/
174202
async handleOtherEvent(eventType, event) {
175-
this.LogEngine.info(`Received ${eventType} event (not processed)`, {
203+
LogEngine.info(`Received ${eventType} event (not processed)`, {
176204
eventType,
177205
conversationId: event.data?.conversationId,
178206
timestamp: event.timestamp
Lines changed: 44 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { LogEngine } from '@wgtechlabs/log-engine';
2+
13
/**
24
* EventValidator - Simple validation for Unthread webhook events
35
*
@@ -11,11 +13,47 @@ export class EventValidator {
1113
* @returns {boolean} - True if valid
1214
*/
1315
static validate(event) {
14-
return event &&
15-
event.type === 'message_created' &&
16-
event.sourcePlatform === 'dashboard' &&
17-
event.data &&
18-
event.data.conversationId &&
19-
event.data.content;
16+
LogEngine.debug('πŸ” EventValidator: Starting validation for event:', { event });
17+
18+
// Check each condition individually for detailed logging
19+
const hasEvent = !!event;
20+
LogEngine.debug('βœ… Has event object:', { hasEvent });
21+
22+
if (!hasEvent) return false;
23+
24+
const hasCorrectType = event.type === 'message_created';
25+
LogEngine.debug('βœ… Type is message_created:', { hasCorrectType, actual: event.type });
26+
27+
const hasCorrectPlatform = event.sourcePlatform === 'dashboard';
28+
LogEngine.debug('βœ… Source is dashboard:', { hasCorrectPlatform, actual: event.sourcePlatform });
29+
30+
const hasData = !!event.data;
31+
LogEngine.debug('βœ… Has data object:', { hasData });
32+
33+
if (!hasData) return false;
34+
35+
// Log the actual data structure for debugging
36+
LogEngine.debug('πŸ” Event data structure:', { data: event.data });
37+
38+
const hasConversationId = !!event.data.conversationId;
39+
LogEngine.debug('βœ… Has conversationId:', { hasConversationId, actual: event.data.conversationId });
40+
41+
// Check for both 'content' and 'text' fields (webhook server sends 'text')
42+
const hasContent = !!(event.data.content || event.data.text);
43+
LogEngine.debug('βœ… Has content/text:', { hasContent, content: event.data.content, text: event.data.text });
44+
45+
// Additional checks for debugging
46+
if (!hasConversationId) {
47+
LogEngine.warn('❌ Missing conversationId - data keys:', { keys: Object.keys(event.data || {}) });
48+
}
49+
50+
if (!hasContent) {
51+
LogEngine.warn('❌ Missing content/text - data keys:', { keys: Object.keys(event.data || {}) });
52+
}
53+
54+
const isValid = hasEvent && hasCorrectType && hasCorrectPlatform && hasData && hasConversationId && hasContent;
55+
LogEngine.info('🎯 Final validation result:', { isValid });
56+
57+
return isValid;
2058
}
2159
}

0 commit comments

Comments
Β (0)