bots/telegram.ts (view raw)
1import { Telegram, getUpdates } from "@gramio/wrappergram";
2import { findStopByName } from "@api/locationInformationRequest.ts";
3import { InlineKeyboard } from "@gramio/keyboards";
4import { getNextDepartures } from "@api/stopEvent.ts";
5import logger from "@lib/logger.ts";
6import * as kvdb from "../lib/kvdb.ts";
7
8const telegram = new Telegram(Deno.env.get("TELEGRAM_TOKEN") as string);
9
10const formatContent = (content?: string) =>
11 content
12 ?.replaceAll("-", "\\-")
13 .replaceAll(".", "\\.")
14 .replaceAll("(", "\\(")
15 .replaceAll(")", "\\)");
16
17const sendMessage = async (message: any) => {
18 await telegram.api.sendMessage(message);
19};
20
21const getUsername = (from: From) => {
22 let username = `id:${from.id}`;
23 if (from.username) username = `user:${from.username}`;
24 if (from.first_name && from.last_name)
25 return `${from.first_name} ${from.last_name} (${username})`;
26 else return username;
27};
28
29for await (const update of getUpdates(telegram)) {
30 logger.debug(JSON.stringify(update, null, 4));
31 // On new message
32 if (update.message) {
33 if (!update.message?.from) {
34 console.error("No 'from' in message");
35 continue;
36 }
37
38 const { from, text } = update.message;
39
40 logger.info(`New message from ${getUsername(from)}: ${text}`);
41
42 telegram.api.setMyCommands({
43 commands: [
44 { command: "aide", description: "Explique comment utiliser le bot" },
45 {
46 command: "favoris",
47 description: "Affiche la liste de vos arrêts favoris",
48 },
49 ],
50 });
51
52 if (text === "/aide" || text === "/start") {
53 sendMessage({
54 chat_id: from.id,
55 text: `Hey ! Je suis un bot qui te permet d'obtenir rapidement des informations sur les transports en commun dans toute la Suisse.
56Entre le nom d'un arrêt et laisse-toi guider !
57
58Ce bot est en cours de développement actif. Les fonctionnalités sont pour le moment limitées.
59
60/aide - Affiche ce message
61/favoris - Affiche vos favoris`,
62 });
63 } else if (text === "/favoris") {
64 const userId = `telegram:${from.id}`;
65 const favorites = kvdb.getUserFavorites(userId);
66
67 let inlineKeyboard = new InlineKeyboard();
68 for await (const favorite of favorites)
69 inlineKeyboard = inlineKeyboard
70 .text(favorite.value.name, {
71 cmd: "nextDepartures",
72 stopRef: favorite.value.stopRef,
73 })
74 .row();
75
76 await sendMessage({
77 chat_id: from.id,
78 text: "Voici vos favoris",
79 reply_markup: inlineKeyboard,
80 });
81 } else {
82 const stopLists = await findStopByName(text);
83 kvdb.saveStops(stopLists);
84 let keyboard = new InlineKeyboard();
85 for (const stop of stopLists)
86 keyboard = keyboard
87 .text(stop.name, { cmd: "nextDepartures", stopRef: stop.stopRef })
88 .row();
89
90 await sendMessage({
91 chat_id: from.id,
92 text: "Quel arrêt correspond ?",
93 reply_markup: keyboard,
94 });
95 }
96 }
97
98 // On keyboard event (callback query)
99 else if (update.callback_query) {
100 const { from, data, message } = update.callback_query;
101 const userId = `telegram:${from.id}`;
102 const payload = JSON.parse(data);
103
104 logger.info(`New request from ${getUsername(from)}: ${data}`);
105
106 if (payload?.cmd === "nextDepartures") {
107 const nextDepartures = await getNextDepartures(payload.stopRef);
108 const stop = await kvdb.getStopByRef(payload.stopRef);
109 const text = formatContent(`Prochains départs depuis *${
110 stop.value?.name || "n.c."
111 }*:\n
112${nextDepartures
113 .map(
114 item =>
115 `*${item.serviceName}* ${item.serviceTypeIcon} *${item.departure}* _${item.departureIn} min_ \n${item.to}\n`
116 )
117 .join("\n")}`);
118
119 let keyboard = new InlineKeyboard().text("Rafraîchir", {
120 cmd: "nextDepartures",
121 stopRef: payload.stopRef,
122 refresh: message.message_id,
123 });
124 const existingFavorite = await kvdb.getUserFavorite(
125 userId,
126 payload.stopRef
127 );
128 if (!existingFavorite?.value)
129 keyboard = keyboard.text("Enregistrer comme favoris", {
130 cmd: "saveFavorite",
131 stopRef: payload.stopRef,
132 });
133
134 await sendMessage({
135 chat_id: from.id,
136 parse_mode: "MarkdownV2",
137 text,
138 reply_markup: keyboard,
139 });
140 } else if (payload?.cmd === "saveFavorite") {
141 const stop = await kvdb.getStopByRef(payload.stopRef);
142 if (stop?.value) await kvdb.saveUserFavorite(userId, stop.value);
143 await sendMessage({
144 chat_id: from.id,
145 parse_mode: "MarkdownV2",
146 text: `L'arrêt *${formatContent(
147 stop.value?.name
148 )}* a été enregistré dans vos /favoris`,
149 });
150 }
151 }
152}