From 30933415c96abec6ad8be5ff7f35fdfaa69be3c0 Mon Sep 17 00:00:00 2001 From: Dmitry Anderson <4nd3r5z0n@gmail.com> Date: Mon, 28 Oct 2024 23:12:12 +0100 Subject: [PATCH] does anybody read those anyway? --- bot/bot.ts | 13 +++- bot/locales/en.ftl | 6 +- bot/locales/hu.ftl | 4 +- bot/locales/pl.ftl | 4 +- bot/locales/rs.ftl | 4 +- bot/locales/ru.ftl | 4 +- bot/locales/ua.ftl | 4 +- bot/normal_mode/captcha.ts | 11 +++- bot/normal_mode/init.ts | 53 ++++++++--------- bot/normal_mode/user_managment.ts | 98 ++++++++++++++++++------------- 10 files changed, 115 insertions(+), 86 deletions(-) diff --git a/bot/bot.ts b/bot/bot.ts index e7e8913..42393d4 100644 --- a/bot/bot.ts +++ b/bot/bot.ts @@ -14,8 +14,10 @@ export const runBot = async (cfg: BotConfig, initMode: (bot: Bot) => void) const i18n = new I18n({ defaultLocale: "en", directory: cfg.locales_dir, + localeNegotiator: (ctx) => + ctx.from?.language_code ?? "en" }) - console.log(i18n.locales) + console.log("Loaded locales: ", i18n.locales) bot.use(session({ initial: defaultSessionData }), i18n) bot.catch((err: BotError) => { @@ -37,5 +39,12 @@ export const runBot = async (cfg: BotConfig, initMode: (bot: Bot) => void) await bot.init() console.log(`starting bot ${bot.botInfo.username}`) - await bot.start().catch(err => console.log(err)) + await bot.start({ + allowed_updates: [ + "chat_member", + "message", + "inline_query" + ] + }).catch(err => console.log(err)) + await bot.stop(); } diff --git a/bot/locales/en.ftl b/bot/locales/en.ftl index 2c77d63..e438e46 100644 --- a/bot/locales/en.ftl +++ b/bot/locales/en.ftl @@ -1,4 +1,4 @@ # Captcha -captcha-already-in-chat = You are already in chat -captcha-passed = Captcha passed! Now you can join the community: { invite_link } -captcha-failed = You didn't pass the captcha. You can try again after { timeout_mins } minutes. +captcha-already-in-chat = You are already in the chat. +captcha-passed = Captcha passed! Now you can join the community: { $invite_link } +captcha-failed = You didn't pass the captcha. You can try again after { $timeout_mins } minute(s). diff --git a/bot/locales/hu.ftl b/bot/locales/hu.ftl index 56da55c..ae123d9 100644 --- a/bot/locales/hu.ftl +++ b/bot/locales/hu.ftl @@ -1,4 +1,4 @@ # Captcha captcha-already-in-chat = Már a csevegésben vagy -captcha-passed = Captcha sikeresen teljesítve! Most már csatlakozhat közösségünkhöz: { invite_link } -captcha-failed = A captcha nem sikerült. 15 perc múlva próbálkozhat { timeout_mins } újra. +captcha-passed = Captcha sikeresen teljesítve! Most már csatlakozhat közösségünkhöz: { $invite_link } +captcha-failed = A captcha nem sikerült. 15 perc múlva próbálkozhat { $timeout_mins } újra. diff --git a/bot/locales/pl.ftl b/bot/locales/pl.ftl index c03ada8..a1ea915 100644 --- a/bot/locales/pl.ftl +++ b/bot/locales/pl.ftl @@ -1,5 +1,5 @@ # Captcha captcha-already-in-chat = Już jesteś na czacie -captcha-passed = Captcha pomyślnie zakończona! Teraz możesz dołączyć do naszej społeczności: { invite_link } -captcha-failed = Captcha nieudana. Spróbuj ponownie za { timeout_mins } minut. +captcha-passed = Captcha pomyślnie zakończona! Teraz możesz dołączyć do naszej społeczności: { $invite_link } +captcha-failed = Captcha nieudana. Spróbuj ponownie za { $timeout_mins } minut. diff --git a/bot/locales/rs.ftl b/bot/locales/rs.ftl index db21a93..7d3b63b 100644 --- a/bot/locales/rs.ftl +++ b/bot/locales/rs.ftl @@ -1,4 +1,4 @@ # Captcha captcha-already-in-chat = Ti si već u chat-u -captcha-passed = Uspeo si sa captch-om! Sada mozes predruziti se nasoj zajednici: { invite_link } -captcha-failed = Nisi prošao captch-u. Mozes pokušati ponovo za { timeout_mins } minuta. +captcha-passed = Uspeo si sa captch-om! Sada mozes predruziti se nasoj zajednici: { $invite_link } +captcha-failed = Nisi prošao captch-u. Mozes pokušati ponovo za { $timeout_mins } minuta. diff --git a/bot/locales/ru.ftl b/bot/locales/ru.ftl index bad7855..dc94020 100644 --- a/bot/locales/ru.ftl +++ b/bot/locales/ru.ftl @@ -1,4 +1,4 @@ # Captcha captcha-already-in-chat = Вы уже в чате -captcha-passed = Капча пройдена! Теперь вы можете присоединиться к нашему сообществу: { invite_link } -captcha-failed = Капча не пройдена. Вы сможете попробовать снова через { timeout_mins } минут. +captcha-passed = Капча пройдена! Теперь вы можете присоединиться к нашему сообществу: { $invite_link } +captcha-failed = Капча не пройдена. Вы сможете попробовать снова через { $timeout_mins } минут. diff --git a/bot/locales/ua.ftl b/bot/locales/ua.ftl index 7976725..57febea 100644 --- a/bot/locales/ua.ftl +++ b/bot/locales/ua.ftl @@ -1,4 +1,4 @@ # Captcha captcha-already-in-chat = Ви вже в чаті -captcha-passed = Капча пройдена! Капча пройдена! Тепер ви можете приєднатися до нашої спільноти: { invite_link } -captcha-failed = Капча не пройдена. Ви зможете спробувати ще раз через { timeout_mins } хвилин. +captcha-passed = Капча пройдена! Капча пройдена! Тепер ви можете приєднатися до нашої спільноти: { $invite_link } +captcha-failed = Капча не пройдена. Ви зможете спробувати ще раз через { $timeout_mins } хвилин. diff --git a/bot/normal_mode/captcha.ts b/bot/normal_mode/captcha.ts index a446af9..697cfdf 100644 --- a/bot/normal_mode/captcha.ts +++ b/bot/normal_mode/captcha.ts @@ -76,14 +76,14 @@ const captchaFailed = async (ctx: Filter, db: Kysely CAPTCHA_FAILS_LIMIT) { const timeoutUntil = new Date() - timeoutUntil.setHours(timeoutUntil.getHours() + 12) + timeoutUntil.setMinutes(timeoutUntil.getMinutes() + TIMEOUT_AFTER_FAIL_MINS) await db.updateTable('users').set({ timeout_until: timeoutUntil, is_timeout: true, }).where('tg_id', '=', ctx.from.id).execute() - await ctx.reply(ctx.t("captcha-already-in-chat", + await ctx.reply(ctx.t("captcha-failed", {timeout_mins: TIMEOUT_AFTER_FAIL_MINS})) await ctx.api.deleteMessage(ctx.chatId, ctx.session.captcha_data!.message_id) } @@ -119,7 +119,12 @@ export const checkCaptchaSolution = async (ctx: Filter, db: const user = users[0] const userRestrictions = await checkUserRestrictions(db, user) - if (userRestrictions.isBlocked || userRestrictions.isTimeout) return + if (userRestrictions.isBlocked) return + if (userRestrictions.isTimeout) { + await ctx.reply("You were timed out") + return + } + console.log("User Info: ", user) if (isSolutionCorrect(ctx.session.captcha_data!.solution, ctx.message.text)) { await captchaPassed(ctx, db, cfg) diff --git a/bot/normal_mode/init.ts b/bot/normal_mode/init.ts index 5946295..4fe19f4 100644 --- a/bot/normal_mode/init.ts +++ b/bot/normal_mode/init.ts @@ -4,12 +4,10 @@ import { Kysely } from 'npm:kysely'; import { Ctx } from "../ctx.ts"; import { Database } from "../../repo/scheme.ts"; import { CompiledConfig } from "../../cfg/config.ts"; -import { checkUser, checkUserOnNewChatMember, onMemberLeftChat, checkUserOnStart } from "./user_managment.ts"; +import { checkUserOnNewChatMember, onMemberLeftChat, checkUserOnStart, checkUserTrx } from "./user_managment.ts"; import { checkCaptchaSolution, initUserCaptcha } from "./captcha.ts"; import { handleSafebooruQuery } from "./safebooru.ts"; -const DEFAULT_LOCALE = "en" - interface ChatMemberUpdateStatus { joined: boolean, left: boolean, @@ -19,13 +17,14 @@ interface ChatMemberUpdateStatus { } function getChatMemberUpdateStatus(oldMember: ChatMember, newMember: ChatMember): ChatMemberUpdateStatus { return { - joined: oldMember.status === "left" && - newMember.status !== "left" && newMember.status !== "kicked", - left: oldMember.status !== "left" && newMember.status === "left", - kicked: newMember.status === "kicked", - restricted: oldMember.status !== "restricted" && newMember.status === "restricted", - roleChanged: oldMember.status !== newMember.status && - (newMember.status !== "left" && newMember.status !== "kicked") + joined: (oldMember.status === "left" || oldMember.status === "kicked") + && (newMember.status !== "left" && newMember.status !== "kicked"), + left: (oldMember.status !== "left" && oldMember.status !== "kicked") + && (newMember.status === "left" || newMember.status === "kicked"), + kicked: newMember.status === "kicked", + restricted: oldMember.status !== "restricted" && newMember.status === "restricted", + roleChanged: oldMember.status !== newMember.status + && (newMember.status !== "left" && newMember.status !== "kicked") }; } @@ -42,22 +41,19 @@ export const init = (bot: Bot, db: Kysely, cfg: CompiledConfig) = `From: ${ctx.from.first_name} ${ctx.from.last_name} `+ `UID: ${ctx.from.id} Locale: ${ctx.from.language_code}`) console.log(ctx.msg.text) - console.log() - ctx.i18n.useLocale(ctx.from.language_code || DEFAULT_LOCALE) await next() }) bot.on('message:text', async (ctx, next) => { if (ctx.chat.id === botCfg.chat_id) { console.log("Message was sent into the mic chat") - const userInfo = await checkUser(ctx, db, botCfg, true) + const userInfo = await checkUserTrx(ctx, db, cfg.botCfg, true) console.log("User Info: ", userInfo) } else if (ctx.message.chat.type == "private" && ctx.session.captcha_data) { console.log("Handling message as captcha solution") await checkCaptchaSolution(ctx, db, botCfg) - } else { - await next() } + await next() }) bot.command('start', async ctx => { @@ -69,25 +65,28 @@ export const init = (bot: Bot, db: Kysely, cfg: CompiledConfig) = }) bot.on('chat_member', async (ctx, next) => { - if (ctx.from.is_bot) return + if (ctx.chatMember.from.is_bot) return if (ctx.chat.id !== botCfg.chat_id) return - ctx.i18n.useLocale(ctx.from.language_code || DEFAULT_LOCALE) const { old_chat_member, new_chat_member } = ctx.chatMember const chatMemberUpdateStatus = getChatMemberUpdateStatus(old_chat_member, new_chat_member) + console.log(chatMemberUpdateStatus) if (chatMemberUpdateStatus.joined) { - console.log(`New Chat member ${ctx.chatMember.from.id}:'+ - '${ctx.from.first_name} ${ctx.from.last_name}`) - await checkUserOnNewChatMember(ctx, db, botCfg) - // TODO: - // const userInfo = await checkUserOnNewChatMember(ctx, db, botCfg) - //if (userInfo.isNewUser) { /* Some hello message? */ } - } else if (chatMemberUpdateStatus.left || chatMemberUpdateStatus.kicked) { - console.log(`Chat member left ${ctx.chatMember.from.id}:'+ - '${ctx.from.first_name} ${ctx.from.last_name}`) + const userInfo = await checkUserOnNewChatMember(ctx, db) + console.log( + `New chat member ${ctx.chatMember.from.id}: `+ + `${ctx.from.first_name} ${ctx.from.last_name}` + ) + console.log("User info: ", userInfo) + ctx.reply("Welcome!") // TODO: Change message + } else if (chatMemberUpdateStatus.left) { + console.log( + `Chat member left ${ctx.chatMember.from.id}: `+ + `${ctx.from.first_name} ${ctx.from.last_name}` + ) await onMemberLeftChat(ctx, db) - // TODO: /* POBEG S DURKI! */ + ctx.reply("pobeg s durki :(") // TODO: Change message } await next() }) diff --git a/bot/normal_mode/user_managment.ts b/bot/normal_mode/user_managment.ts index d56060b..342cadd 100644 --- a/bot/normal_mode/user_managment.ts +++ b/bot/normal_mode/user_managment.ts @@ -19,8 +19,8 @@ export interface CheckUserOut extends UserCheckedRestrictions { // Ignores the start command export const checkUser = async ( ctx: Ctx, - db: Kysely, - cfg: BotConfig, + trx: Transaction, + cfg?: BotConfig, isMicChat?: boolean, ): Promise => { const out: CheckUserOut = { @@ -32,44 +32,59 @@ export const checkUser = async ( } if (!ctx.chat || !ctx.from) return out - isMicChat ??= ctx.chat.id === cfg.chat_id + if (cfg === undefined) { + isMicChat = false + } else { + isMicChat ??= ctx.chat.id === cfg.chat_id + } - await db.transaction().execute(async trx => { - const users = await trx.selectFrom('users') - .selectAll().where('tg_id', '=', ctx.from!.id).execute() - if (users.length < 1) { - await trx.insertInto('users').values({ - tg_id: ctx.from!.id, - joined_by_referal_from_user_id: null, - is_chat_participant: isMicChat, - is_captcha_passed: isMicChat, - joined_chat_at: new Date, - timeout_until: null - }).execute() - out.isNewUser = true - out.isChatParticipant = isMicChat - out.isCaptchaSolved = out.isChatParticipant - } else { - const user = users[0] - const userRestrictions = await checkUserRestrictions(db, user) + const users = await trx.selectFrom('users') + .selectAll().where('tg_id', '=', ctx.from!.id).execute() + if (users.length < 1) { + await trx.insertInto('users').values({ + tg_id: ctx.from!.id, + joined_by_referal_from_user_id: null, + is_chat_participant: isMicChat, + is_captcha_passed: isMicChat, + joined_chat_at: new Date, + timeout_until: null + }).execute() + out.isNewUser = true + out.isChatParticipant = isMicChat + out.isCaptchaSolved = out.isChatParticipant + } else { + const user = users[0] + const userRestrictions = await checkUserRestrictions(trx, user) - if (!user.is_chat_participant && isMicChat) { - await trx.updateTable('users').set({ - is_chat_participant: true, - is_captcha_passed: true, - }).where('tg_id', '=', user.tg_id).execute() - } - - out.isBlocked = userRestrictions.isBlocked - out.isTimeout = userRestrictions.isTimeout - out.isChatParticipant = user.is_chat_participant || isMicChat - out.isCaptchaSolved = user.is_captcha_passed + if (!user.is_chat_participant && isMicChat) { + await trx.updateTable('users').set({ + is_chat_participant: true, + is_captcha_passed: true, + }).where('tg_id', '=', user.tg_id).execute() } - }) + + out.isBlocked = userRestrictions.isBlocked + out.isTimeout = userRestrictions.isTimeout + out.isChatParticipant = user.is_chat_participant || isMicChat + out.isCaptchaSolved = user.is_captcha_passed + } return out } +export const checkUserTrx = async ( + ctx: Ctx, + db: Kysely, + cfg?: BotConfig, + isMicChat?: boolean, +): Promise => { + let res: CheckUserOut + await db.transaction().execute(async trx => { + res = await checkUser(ctx, trx, cfg, isMicChat) + }) + return res! +} + interface CheckUserOnNewChatMemberOut extends CheckUserOut { @@ -79,9 +94,8 @@ interface CheckUserOnNewChatMemberOut extends CheckUserOut { // Extends checkUser function with checking invite link functionality export const checkUserOnNewChatMember = async ( - ctx: Filter, - db: Kysely | Transaction, - cfg: BotConfig + ctx: Filter, + db: Kysely | Transaction, ): Promise => { const out: CheckUserOnNewChatMemberOut = { isBlocked: false, @@ -95,13 +109,13 @@ export const checkUserOnNewChatMember = async ( let userInfo: CheckUserOut await db.transaction().execute(async trx => { - userInfo = await checkUser(ctx, trx, cfg, true) + userInfo = await checkUser(ctx, trx) if (userInfo.isBlocked || userInfo.isNewUser) { return } - await trx.updateTable('users').where('tg_id', '=', ctx.from.id).set({ + await trx.updateTable('users').set({ is_chat_participant: true - }).execute() + }).where('tg_id', '=', ctx.from.id).execute() }) userInfo = userInfo! @@ -127,14 +141,16 @@ export const checkUserOnNewChatMember = async ( out.expectedUserTgId = -1 } else { const { expect_user_tg_id } = inviteLinksData[0] - out.isExpectedUserJoined = expect_user_tg_id === ctx.chatMember.from.id + out.isExpectedUserJoined = expect_user_tg_id == ctx.chatMember.from.id out.expectedUserTgId = expect_user_tg_id await db.deleteFrom('invite_links').where('link', '=', invite_link).execute() await ctx.revokeChatInviteLink(invite_link) } if (!out.isExpectedUserJoined) { - await db.updateTable('users').where(eb => eb.or([ + await db.updateTable('users').set({ + is_banned: true + }).where(eb => eb.or([ eb('tg_id', '=', out.expectedUserTgId), eb('tg_id', '=', ctx.chatMember.from.id), ])).execute()