Skip to content

Commit ae53e6c

Browse files
committed
feat: new handlers for bot
1 parent 30b6c6b commit ae53e6c

1 file changed

Lines changed: 133 additions & 13 deletions

File tree

apps/web-app/server/services/telegram/wasabi-bot.ts

Lines changed: 133 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import type { Ticket, User } from '@roll-stack/database'
12
import type { Context } from 'grammy'
23
import { repository } from '@roll-stack/database'
34
import { Bot } from 'grammy'
@@ -9,12 +10,12 @@ const { telegram } = useRuntimeConfig()
910
let bot: Bot | null = null
1011

1112
export async function useCreateWasabiBot() {
12-
const botInDb = await repository.telegram.findBot(telegram.wasabiBotId)
13-
if (!botInDb?.token) {
13+
const token = await getBotToken()
14+
if (!token) {
1415
throw new Error('Wasabi bot is not configured')
1516
}
1617

17-
bot = new Bot(botInDb.token)
18+
bot = new Bot(token)
1819

1920
bot.on('message:text', async (ctx) => {
2021
if (ctx.hasCommand('start')) {
@@ -24,6 +25,22 @@ export async function useCreateWasabiBot() {
2425
return handleMessage(ctx)
2526
})
2627

28+
bot.on('message:photo', async (ctx) => {
29+
return handlePhoto(ctx)
30+
})
31+
32+
bot.on('message:video', async (ctx) => {
33+
return handleVideo(ctx)
34+
})
35+
36+
bot.on('message:document', async (ctx) => {
37+
return handleFile(ctx)
38+
})
39+
40+
bot.on('message:file', async (ctx) => {
41+
return handleFile(ctx)
42+
})
43+
2744
// Somebody invited bot to a group
2845
bot.on('my_chat_member', async (ctx) => {
2946
logger.log('my_chat_member', ctx.update)
@@ -84,11 +101,102 @@ async function handleMessage(ctx: Context) {
84101
return
85102
}
86103

87-
const telegramUser = await repository.telegram.findUserByTelegramIdAndBotId(ctx.message.from.id.toString(), telegram.wasabiBotId)
88-
if (!telegramUser?.user) {
104+
const data = await getUserAndTicket(ctx.message.from.id.toString())
105+
if (!data) {
106+
return
107+
}
108+
109+
await repository.ticket.createMessage({
110+
ticketId: data.ticket.id,
111+
userId: data.user.id,
112+
text: ctx.message.text,
113+
})
114+
115+
logger.log('message', data.user.id, ctx.message.from.id, ctx.message.text)
116+
ctx.reply('Сообщение передано в службу поддержки.')
117+
}
118+
119+
async function handlePhoto(ctx: Context) {
120+
if (!ctx.message?.photo?.length) {
121+
return
122+
}
123+
124+
const data = await getUserAndTicket(ctx.message.from.id.toString())
125+
if (!data) {
89126
return
90127
}
91128

129+
const bestQuality = ctx.message.photo.pop()
130+
if (!bestQuality) {
131+
return
132+
}
133+
134+
const botToken = await getBotToken()
135+
if (!botToken) {
136+
return null
137+
}
138+
139+
const downloadUrl = await getFileDownloadUrl({ ctx, fileId: bestQuality.file_id, botToken })
140+
141+
await repository.ticket.createMessage({
142+
ticketId: data.ticket.id,
143+
userId: data.user.id,
144+
text: JSON.stringify({ downloadUrl, photo: ctx.message.photo }),
145+
})
146+
147+
// Save photo?
148+
logger.log('photo', data.user.id, ctx.message.from.id, ctx.message.text, ctx.message.photo, downloadUrl)
149+
ctx.reply('Фото передано в службу поддержки.')
150+
}
151+
152+
async function handleVideo(ctx: Context) {
153+
if (!ctx.message?.video) {
154+
return
155+
}
156+
157+
const data = await getUserAndTicket(ctx.message.from.id.toString())
158+
if (!data) {
159+
return
160+
}
161+
162+
await repository.ticket.createMessage({
163+
ticketId: data.ticket.id,
164+
userId: data.user.id,
165+
text: JSON.stringify(ctx.message.video),
166+
})
167+
168+
// Save video?
169+
logger.log('video', data.user.id, ctx.message.from.id, ctx.message.text, ctx.message.video)
170+
ctx.reply('Видео передано в службу поддержки.')
171+
}
172+
173+
async function handleFile(ctx: Context) {
174+
if (!ctx.message?.document) {
175+
return
176+
}
177+
178+
const data = await getUserAndTicket(ctx.message.from.id.toString())
179+
if (!data) {
180+
return
181+
}
182+
183+
await repository.ticket.createMessage({
184+
ticketId: data.ticket.id,
185+
userId: data.user.id,
186+
text: JSON.stringify(ctx.message.document),
187+
})
188+
189+
// Save file?
190+
logger.log('file', data.user.id, ctx.message.from.id, ctx.message.text, ctx.message.document)
191+
ctx.reply('Файл передан в службу поддержки.')
192+
}
193+
194+
async function getUserAndTicket(telegramId: string): Promise<{ user: User, ticket: Ticket } | null> {
195+
const telegramUser = await repository.telegram.findUserByTelegramIdAndBotId(telegramId, telegram.wasabiBotId)
196+
if (!telegramUser?.user) {
197+
return null
198+
}
199+
92200
// Get last ticket
93201
const tickets = await repository.ticket.listOpenedByUser(telegramUser.user.id)
94202
let ticket = tickets?.[0]
@@ -102,17 +210,29 @@ async function handleMessage(ctx: Context) {
102210
})
103211
}
104212
if (!ticket) {
105-
return
213+
return null
106214
}
107215

108-
await repository.ticket.createMessage({
109-
ticketId: ticket.id,
110-
userId: telegramUser.user.id,
111-
text: ctx.message.text,
112-
})
216+
return { user: telegramUser.user, ticket }
217+
}
113218

114-
logger.log('message', telegramUser.user.id, ctx.message.from.id, ctx.message.text)
115-
ctx.reply('Сообщение передано в службу поддержки.')
219+
async function getFileDownloadUrl(data: { ctx: Context, fileId: string, botToken: string }) {
220+
// https://api.telegram.org/file/bot<token>/<file_path>
221+
const file = await data.ctx.api.getFile(data.fileId)
222+
if (!file) {
223+
return null
224+
}
225+
226+
return `https://api.telegram.org/file/bot${data.botToken}/${file.file_path}`
227+
}
228+
229+
async function getBotToken(): Promise<string | null> {
230+
const botInDb = await repository.telegram.findBot(telegram.wasabiBotId)
231+
if (!botInDb?.token) {
232+
return null
233+
}
234+
235+
return botInDb.token
116236
}
117237

118238
export function useWasabiBot(): Bot {

0 commit comments

Comments
 (0)