From 4cd9f56f553ce1258fff3715610c3ad7b4193d5a Mon Sep 17 00:00:00 2001 From: Lorenzo Corallo Date: Sat, 11 Apr 2026 20:46:19 +0200 Subject: [PATCH 1/3] feat: remove voting system from banall - poor me --- src/modules/tg-logger/ban-all.ts | 114 +------------------------------ src/modules/tg-logger/index.ts | 61 +++++------------ 2 files changed, 18 insertions(+), 157 deletions(-) diff --git a/src/modules/tg-logger/ban-all.ts b/src/modules/tg-logger/ban-all.ts index 1df190b..bf6849d 100644 --- a/src/modules/tg-logger/ban-all.ts +++ b/src/modules/tg-logger/ban-all.ts @@ -1,11 +1,6 @@ -import type { Context } from "grammy" import type { User } from "grammy/types" -import { type CallbackCtx, MenuGenerator } from "@/lib/menu" -import { logger } from "@/logger" import { fmt, fmtUser } from "@/utils/format" import { unicodeProgressBar } from "@/utils/progress" -import { calculateOutcome, type Outcome, type Vote, type Voter } from "@/utils/vote" -import { modules } from ".." export type BanAllState = { jobCount: number @@ -33,23 +28,9 @@ export type BanAll = { target: User reporter: User reason?: string - outcome: Outcome - voters: Voter[] state: BanAllState } -const VOTE_EMOJI: Record = { - inFavor: "✅", - against: "❌", - abstained: "🫥", -} - -const OUTCOME_STR: Record = { - waiting: "⏳ Waiting for votes", - approved: "✅ APPROVED", - denied: "❌ DENIED", -} - export const getProgressText = (state: BanAll["state"]): string => { if (state.jobCount === 0) return fmt(({ i }) => i`\nFetching groups...`) @@ -76,106 +57,15 @@ export const getProgressText = (state: BanAll["state"]): string => { */ export const getBanAllText = (data: BanAll) => fmt( - ({ n, b, skip, strikethrough, i }) => [ + ({ n, b, skip, i }) => [ data.type === "BAN" ? b`🚨 BAN ALL 🚨` : b`🕊 UN-BAN ALL 🕊`, "", n`${b`🎯 Target:`} ${fmtUser(data.target)} `, n`${b`📣 Reporter:`} ${fmtUser(data.reporter)} `, data.type === "BAN" ? n`${b`📋 Reason:`} ${data.reason ? data.reason : i`N/A`}` : undefined, "", - b`${OUTCOME_STR[data.outcome]} `, - data.outcome === "approved" ? skip`${getProgressText(data.state)}` : undefined, + skip`${getProgressText(data.state)}`, "", - b`Voters`, - ...data.voters.map((v) => - data.outcome !== "waiting" && !v.vote - ? strikethrough`➖ ${fmtUser(v.user)} ${v.isPresident ? b`PRES` : ""} ` - : n`${v.vote ? VOTE_EMOJI[v.vote] : "⏳"} ${fmtUser(v.user)} ${v.isPresident ? b`PRES` : ""} ` - ), ], { sep: "\n" } ) - -async function vote( - ctx: CallbackCtx, - data: BanAll, - vote: Vote -): Promise<{ feedback?: string; newData?: BanAll }> { - const voterId = ctx.callbackQuery.from.id - const voter = data.voters.find((v) => v.user.id === voterId) - if (!voter) - return { - feedback: "❌ You cannot vote", - } - if (voter.vote !== undefined) - return { - feedback: "⚠️ You cannot change your vote!", - } - - voter.vote = vote - const outcome = calculateOutcome(data.voters) - logger.debug({ outcome: data.outcome, voters: data.voters }, "[VOTE] new vote, calculating...") - if (outcome === null) { - logger.fatal({ banAll: data }, "ERROR WHILE VOTING FOR BAN_ALL, Outcome is null") - return { - feedback: "There was an error, check logs", - } - } - data.outcome = outcome - - if (outcome === "approved") { - try { - if (ctx.msgId) await modules.get("banAll").initiateBanAll(data, ctx.msgId) - else { - logger.error( - { callbackQuery: ctx.callbackQuery }, - "Message ID is undefined, cannot initiate ban all. How did this happen?" - ) - } - } catch (error) { - await modules - .get("tgLogger") - .exception({ error, type: "UNKNOWN" }, "There was an error while initializing BanAll queue, check logs") - } - } - - // remove buttons if there is an outcome (not waiting) - const reply_markup = outcome === "waiting" ? ctx.msg?.reply_markup : undefined - - await ctx.editMessageText(getBanAllText(data), { reply_markup }).catch(() => { - // throws if message is not modified - we don't care - }) - - return { - newData: data, - feedback: "✅ Thanks for voting!", - } -} - -/** - * Interactive menu for handling voting. - * - * @param data - {@link BanAll} initial BanAll - */ -export const banAllMenu = MenuGenerator.getInstance().create("ban-all-voting", [ - [ - { - text: VOTE_EMOJI.inFavor, - cb: async ({ ctx, data }) => { - return await vote(ctx, data, "inFavor") - }, - }, - { - text: VOTE_EMOJI.abstained, - cb: async ({ ctx, data }) => { - return await vote(ctx, data, "abstained") - }, - }, - { - text: VOTE_EMOJI.against, - cb: async ({ ctx, data }) => { - return await vote(ctx, data, "against") - }, - }, - ], -]) diff --git a/src/modules/tg-logger/index.ts b/src/modules/tg-logger/index.ts index c48e2cb..585541b 100644 --- a/src/modules/tg-logger/index.ts +++ b/src/modules/tg-logger/index.ts @@ -7,6 +7,7 @@ import { groupMessagesByChat, stripChatId } from "@/utils/chat" import { fmt, fmtChat, fmtDate, fmtUser } from "@/utils/format" import type { ModuleShared } from "@/utils/types" import { after } from "@/utils/wait" +import { modules } from ".." import type { ModerationAction, PreDeleteResult } from "../moderation/types" import { type BanAll, banAllMenu, getBanAllText } from "./ban-all" import { grantCreatedMenu, grantMessageMenu } from "./grants" @@ -161,55 +162,11 @@ export class TgLogger extends Module { } public async banAll(target: User, reporter: User, type: "BAN" | "UNBAN", reason?: string): Promise { - const direttivo = await api.tg.permissions.getDirettivo.query() - - switch (direttivo.error) { - case "EMPTY": - return fmt(({ n }) => n`Error: Direttivo is not set`) - - case "NOT_ENOUGH_MEMBERS": - return fmt(({ n }) => n`Error: Direttivo has not enough members!`) - - case "TOO_MANY_MEMBERS": - return fmt(({ n }) => n`Error: Direttivo has too many members!`) - - case "INTERNAL_SERVER_ERROR": - return fmt(({ n }) => n`Error: there was an internal error while fetching members of Direttivo.`) - - case null: - break - } - - const voters = direttivo.members.map((m) => ({ - user: m.user - ? { - id: m.userId, - first_name: m.user.firstName, - last_name: m.user.lastName, - username: m.user.username, - is_bot: m.user.isBot, - language_code: m.user.langCode, - } - : { id: m.userId }, - isPresident: m.isPresident, - vote: undefined, - })) - - if (!voters.some((v) => v.isPresident)) - return fmt( - ({ n, b }) => [b`Error: No member is President!`, n`${b`Members:`} ${voters.map((v) => v.user.id).join(" ")}`], - { - sep: "\n", - } - ) - const banAll: BanAll = { type, - outcome: "waiting", reporter: reporter, reason, target, - voters, state: { successCount: 0, failedCount: 0, @@ -220,9 +177,23 @@ export class TgLogger extends Module { const menu = await banAllMenu(banAll) await this.log(this.topics.banAll, "———————————————") const msg = await this.log(this.topics.banAll, getBanAllText(banAll), { reply_markup: menu }) + + if (!msg?.message_id) { + logger.error("[banall] There was an error when initiating banall, no msg.msgId") + return fmt( + ({ n, b }) => [ + b`${type} All ERROR!`, + n`Cannot log the message in tgLogger, therefore cannot start the procedure`, + n`This should be inspected as it should not never happen`, + ], + { sep: "\n" } + ) + } + + await modules.get("banAll").initiateBanAll(banAll, msg.message_id) return fmt( ({ n, b, link }) => [ - b`${type} All requested!`, + b`${type} All started!`, msg ? n`Check ${link("here", `https://t.me/c/${this.groupId}/${this.topics.banAll}/${msg.message_id}`)}` : undefined, From 304515eedd001fe088411ee3c7409eb05bbec776 Mon Sep 17 00:00:00 2001 From: Lorenzo Corallo Date: Sat, 11 Apr 2026 20:48:06 +0200 Subject: [PATCH 2/3] fix: remove menu and old outcome check --- src/modules/moderation/ban-all.ts | 4 ---- src/modules/tg-logger/index.ts | 6 ++---- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/src/modules/moderation/ban-all.ts b/src/modules/moderation/ban-all.ts index 171f80f..a789de8 100644 --- a/src/modules/moderation/ban-all.ts +++ b/src/modules/moderation/ban-all.ts @@ -166,10 +166,6 @@ export class BanAllQueue extends Module { private flowProducer = new FlowProducer({ connection }) public async initiateBanAll(banAll: BanAll, messageId: number) { - if (banAll.outcome !== "approved") { - throw new Error("Cannot initiate ban all for a non-approved BanAll") - } - const allGroups = await api.tg.groups.getAll.query() const chats = allGroups.map((g) => g.telegramId) const banType = banAll.type === "BAN" ? "ban" : "unban" diff --git a/src/modules/tg-logger/index.ts b/src/modules/tg-logger/index.ts index 585541b..c589697 100644 --- a/src/modules/tg-logger/index.ts +++ b/src/modules/tg-logger/index.ts @@ -1,6 +1,5 @@ import { GrammyError, InlineKeyboard } from "grammy" import type { Message, User } from "grammy/types" -import { api } from "@/backend" import { Module } from "@/lib/modules" import { logger } from "@/logger" import { groupMessagesByChat, stripChatId } from "@/utils/chat" @@ -9,7 +8,7 @@ import type { ModuleShared } from "@/utils/types" import { after } from "@/utils/wait" import { modules } from ".." import type { ModerationAction, PreDeleteResult } from "../moderation/types" -import { type BanAll, banAllMenu, getBanAllText } from "./ban-all" +import { type BanAll, getBanAllText } from "./ban-all" import { grantCreatedMenu, grantMessageMenu } from "./grants" import { getReportText, type Report, reportMenu } from "./report" import type * as Types from "./types" @@ -174,9 +173,8 @@ export class TgLogger extends Module { }, } - const menu = await banAllMenu(banAll) await this.log(this.topics.banAll, "———————————————") - const msg = await this.log(this.topics.banAll, getBanAllText(banAll), { reply_markup: menu }) + const msg = await this.log(this.topics.banAll, getBanAllText(banAll)) if (!msg?.message_id) { logger.error("[banall] There was an error when initiating banall, no msg.msgId") From 93c8e60d1d811fc0c548959240d15305d2fefe9a Mon Sep 17 00:00:00 2001 From: Lorenzo Corallo Date: Sat, 11 Apr 2026 20:51:56 +0200 Subject: [PATCH 3/3] docs: explain why this change --- src/modules/tg-logger/ban-all.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/modules/tg-logger/ban-all.ts b/src/modules/tg-logger/ban-all.ts index bf6849d..521fc9f 100644 --- a/src/modules/tg-logger/ban-all.ts +++ b/src/modules/tg-logger/ban-all.ts @@ -2,6 +2,14 @@ import type { User } from "grammy/types" import { fmt, fmtUser } from "@/utils/format" import { unicodeProgressBar } from "@/utils/progress" +// NOTE +// Previously this was using a voting system made in @/utils/vote.ts. +// Since banAll is a urgent moderation action to execute, we decided to remove it, +// giving priority to common sense over formality. +// If in the future we decide to reintroduce it, check the following PR +// https://github.com/PoliNetworkOrg/telegram/pull/94 +// to understand how to reimplement it + export type BanAllState = { jobCount: number successCount: number